12f4a32ccSToke Høiland-Jørgensen // SPDX-License-Identifier: GPL-2.0
22f4a32ccSToke Høiland-Jørgensen 
32f4a32ccSToke Høiland-Jørgensen #include <sys/types.h>
42f4a32ccSToke Høiland-Jørgensen #include <sys/stat.h>
52f4a32ccSToke Høiland-Jørgensen #include <unistd.h>
62f4a32ccSToke Høiland-Jørgensen #include <test_progs.h>
72f4a32ccSToke Høiland-Jørgensen 
82f4a32ccSToke Høiland-Jørgensen __u32 get_map_id(struct bpf_object *obj, const char *name)
92f4a32ccSToke Høiland-Jørgensen {
102f4a32ccSToke Høiland-Jørgensen 	struct bpf_map_info map_info = {};
112f4a32ccSToke Høiland-Jørgensen 	__u32 map_info_len, duration = 0;
122f4a32ccSToke Høiland-Jørgensen 	struct bpf_map *map;
132f4a32ccSToke Høiland-Jørgensen 	int err;
142f4a32ccSToke Høiland-Jørgensen 
152f4a32ccSToke Høiland-Jørgensen 	map_info_len = sizeof(map_info);
162f4a32ccSToke Høiland-Jørgensen 
172f4a32ccSToke Høiland-Jørgensen 	map = bpf_object__find_map_by_name(obj, name);
182f4a32ccSToke Høiland-Jørgensen 	if (CHECK(!map, "find map", "NULL map"))
192f4a32ccSToke Høiland-Jørgensen 		return 0;
202f4a32ccSToke Høiland-Jørgensen 
212f4a32ccSToke Høiland-Jørgensen 	err = bpf_obj_get_info_by_fd(bpf_map__fd(map),
222f4a32ccSToke Høiland-Jørgensen 				     &map_info, &map_info_len);
232f4a32ccSToke Høiland-Jørgensen 	CHECK(err, "get map info", "err %d errno %d", err, errno);
242f4a32ccSToke Høiland-Jørgensen 	return map_info.id;
252f4a32ccSToke Høiland-Jørgensen }
262f4a32ccSToke Høiland-Jørgensen 
272f4a32ccSToke Høiland-Jørgensen void test_pinning(void)
282f4a32ccSToke Høiland-Jørgensen {
292f4a32ccSToke Høiland-Jørgensen 	const char *file_invalid = "./test_pinning_invalid.o";
302f4a32ccSToke Høiland-Jørgensen 	const char *custpinpath = "/sys/fs/bpf/custom/pinmap";
312f4a32ccSToke Høiland-Jørgensen 	const char *nopinpath = "/sys/fs/bpf/nopinmap";
322f4a32ccSToke Høiland-Jørgensen 	const char *nopinpath2 = "/sys/fs/bpf/nopinmap2";
332f4a32ccSToke Høiland-Jørgensen 	const char *custpath = "/sys/fs/bpf/custom";
342f4a32ccSToke Høiland-Jørgensen 	const char *pinpath = "/sys/fs/bpf/pinmap";
352f4a32ccSToke Høiland-Jørgensen 	const char *file = "./test_pinning.o";
362f4a32ccSToke Høiland-Jørgensen 	__u32 map_id, map_id2, duration = 0;
372f4a32ccSToke Høiland-Jørgensen 	struct stat statbuf = {};
382f4a32ccSToke Høiland-Jørgensen 	struct bpf_object *obj;
392f4a32ccSToke Høiland-Jørgensen 	struct bpf_map *map;
402f4a32ccSToke Høiland-Jørgensen 	int err;
412f4a32ccSToke Høiland-Jørgensen 	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
422f4a32ccSToke Høiland-Jørgensen 		.pin_root_path = custpath,
432f4a32ccSToke Høiland-Jørgensen 	);
442f4a32ccSToke Høiland-Jørgensen 
452f4a32ccSToke Høiland-Jørgensen 	/* check that opening fails with invalid pinning value in map def */
462f4a32ccSToke Høiland-Jørgensen 	obj = bpf_object__open_file(file_invalid, NULL);
472f4a32ccSToke Høiland-Jørgensen 	err = libbpf_get_error(obj);
482f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err != -EINVAL, "invalid open", "err %d errno %d\n", err, errno)) {
492f4a32ccSToke Høiland-Jørgensen 		obj = NULL;
502f4a32ccSToke Høiland-Jørgensen 		goto out;
512f4a32ccSToke Høiland-Jørgensen 	}
522f4a32ccSToke Høiland-Jørgensen 
532f4a32ccSToke Høiland-Jørgensen 	/* open the valid object file  */
542f4a32ccSToke Høiland-Jørgensen 	obj = bpf_object__open_file(file, NULL);
552f4a32ccSToke Høiland-Jørgensen 	err = libbpf_get_error(obj);
562f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "default open", "err %d errno %d\n", err, errno)) {
572f4a32ccSToke Høiland-Jørgensen 		obj = NULL;
582f4a32ccSToke Høiland-Jørgensen 		goto out;
592f4a32ccSToke Høiland-Jørgensen 	}
602f4a32ccSToke Høiland-Jørgensen 
612f4a32ccSToke Høiland-Jørgensen 	err = bpf_object__load(obj);
622f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "default load", "err %d errno %d\n", err, errno))
632f4a32ccSToke Høiland-Jørgensen 		goto out;
642f4a32ccSToke Høiland-Jørgensen 
652f4a32ccSToke Høiland-Jørgensen 	/* check that pinmap was pinned */
662f4a32ccSToke Høiland-Jørgensen 	err = stat(pinpath, &statbuf);
672f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "stat pinpath", "err %d errno %d\n", err, errno))
682f4a32ccSToke Høiland-Jørgensen 		goto out;
692f4a32ccSToke Høiland-Jørgensen 
702f4a32ccSToke Høiland-Jørgensen 	/* check that nopinmap was *not* pinned */
712f4a32ccSToke Høiland-Jørgensen 	err = stat(nopinpath, &statbuf);
722f4a32ccSToke Høiland-Jørgensen 	if (CHECK(!err || errno != ENOENT, "stat nopinpath",
732f4a32ccSToke Høiland-Jørgensen 		  "err %d errno %d\n", err, errno))
742f4a32ccSToke Høiland-Jørgensen 		goto out;
752f4a32ccSToke Høiland-Jørgensen 
762f4a32ccSToke Høiland-Jørgensen 	/* check that nopinmap2 was *not* pinned */
772f4a32ccSToke Høiland-Jørgensen 	err = stat(nopinpath2, &statbuf);
782f4a32ccSToke Høiland-Jørgensen 	if (CHECK(!err || errno != ENOENT, "stat nopinpath2",
792f4a32ccSToke Høiland-Jørgensen 		  "err %d errno %d\n", err, errno))
802f4a32ccSToke Høiland-Jørgensen 		goto out;
812f4a32ccSToke Høiland-Jørgensen 
822f4a32ccSToke Høiland-Jørgensen 	map_id = get_map_id(obj, "pinmap");
832f4a32ccSToke Høiland-Jørgensen 	if (!map_id)
842f4a32ccSToke Høiland-Jørgensen 		goto out;
852f4a32ccSToke Høiland-Jørgensen 
862f4a32ccSToke Høiland-Jørgensen 	bpf_object__close(obj);
872f4a32ccSToke Høiland-Jørgensen 
882f4a32ccSToke Høiland-Jørgensen 	obj = bpf_object__open_file(file, NULL);
892f4a32ccSToke Høiland-Jørgensen 	if (CHECK_FAIL(libbpf_get_error(obj))) {
902f4a32ccSToke Høiland-Jørgensen 		obj = NULL;
912f4a32ccSToke Høiland-Jørgensen 		goto out;
922f4a32ccSToke Høiland-Jørgensen 	}
932f4a32ccSToke Høiland-Jørgensen 
942f4a32ccSToke Høiland-Jørgensen 	err = bpf_object__load(obj);
952f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "default load", "err %d errno %d\n", err, errno))
962f4a32ccSToke Høiland-Jørgensen 		goto out;
972f4a32ccSToke Høiland-Jørgensen 
982f4a32ccSToke Høiland-Jørgensen 	/* check that same map ID was reused for second load */
992f4a32ccSToke Høiland-Jørgensen 	map_id2 = get_map_id(obj, "pinmap");
1002f4a32ccSToke Høiland-Jørgensen 	if (CHECK(map_id != map_id2, "check reuse",
1012f4a32ccSToke Høiland-Jørgensen 		  "err %d errno %d id %d id2 %d\n", err, errno, map_id, map_id2))
1022f4a32ccSToke Høiland-Jørgensen 		goto out;
1032f4a32ccSToke Høiland-Jørgensen 
1042f4a32ccSToke Høiland-Jørgensen 	/* should be no-op to re-pin same map */
1052f4a32ccSToke Høiland-Jørgensen 	map = bpf_object__find_map_by_name(obj, "pinmap");
1062f4a32ccSToke Høiland-Jørgensen 	if (CHECK(!map, "find map", "NULL map"))
1072f4a32ccSToke Høiland-Jørgensen 		goto out;
1082f4a32ccSToke Høiland-Jørgensen 
1092f4a32ccSToke Høiland-Jørgensen 	err = bpf_map__pin(map, NULL);
1102f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "re-pin map", "err %d errno %d\n", err, errno))
1112f4a32ccSToke Høiland-Jørgensen 		goto out;
1122f4a32ccSToke Høiland-Jørgensen 
1132f4a32ccSToke Høiland-Jørgensen 	/* but error to pin at different location */
1142f4a32ccSToke Høiland-Jørgensen 	err = bpf_map__pin(map, "/sys/fs/bpf/other");
1152f4a32ccSToke Høiland-Jørgensen 	if (CHECK(!err, "pin map different", "err %d errno %d\n", err, errno))
1162f4a32ccSToke Høiland-Jørgensen 		goto out;
1172f4a32ccSToke Høiland-Jørgensen 
1182f4a32ccSToke Høiland-Jørgensen 	/* unpin maps with a pin_path set */
1192f4a32ccSToke Høiland-Jørgensen 	err = bpf_object__unpin_maps(obj, NULL);
1202f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "unpin maps", "err %d errno %d\n", err, errno))
1212f4a32ccSToke Høiland-Jørgensen 		goto out;
1222f4a32ccSToke Høiland-Jørgensen 
1232f4a32ccSToke Høiland-Jørgensen 	/* and re-pin them... */
1242f4a32ccSToke Høiland-Jørgensen 	err = bpf_object__pin_maps(obj, NULL);
1252f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "pin maps", "err %d errno %d\n", err, errno))
1262f4a32ccSToke Høiland-Jørgensen 		goto out;
1272f4a32ccSToke Høiland-Jørgensen 
1282f4a32ccSToke Høiland-Jørgensen 	/* set pinning path of other map and re-pin all */
1292f4a32ccSToke Høiland-Jørgensen 	map = bpf_object__find_map_by_name(obj, "nopinmap");
1302f4a32ccSToke Høiland-Jørgensen 	if (CHECK(!map, "find map", "NULL map"))
1312f4a32ccSToke Høiland-Jørgensen 		goto out;
1322f4a32ccSToke Høiland-Jørgensen 
1332f4a32ccSToke Høiland-Jørgensen 	err = bpf_map__set_pin_path(map, custpinpath);
1342f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "set pin path", "err %d errno %d\n", err, errno))
1352f4a32ccSToke Høiland-Jørgensen 		goto out;
1362f4a32ccSToke Høiland-Jørgensen 
1372f4a32ccSToke Høiland-Jørgensen 	/* should only pin the one unpinned map */
1382f4a32ccSToke Høiland-Jørgensen 	err = bpf_object__pin_maps(obj, NULL);
1392f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "pin maps", "err %d errno %d\n", err, errno))
1402f4a32ccSToke Høiland-Jørgensen 		goto out;
1412f4a32ccSToke Høiland-Jørgensen 
1422f4a32ccSToke Høiland-Jørgensen 	/* check that nopinmap was pinned at the custom path */
1432f4a32ccSToke Høiland-Jørgensen 	err = stat(custpinpath, &statbuf);
1442f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno))
1452f4a32ccSToke Høiland-Jørgensen 		goto out;
1462f4a32ccSToke Høiland-Jørgensen 
1472f4a32ccSToke Høiland-Jørgensen 	/* remove the custom pin path to re-test it with auto-pinning below */
1482f4a32ccSToke Høiland-Jørgensen 	err = unlink(custpinpath);
1492f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "unlink custpinpath", "err %d errno %d\n", err, errno))
1502f4a32ccSToke Høiland-Jørgensen 		goto out;
1512f4a32ccSToke Høiland-Jørgensen 
1522f4a32ccSToke Høiland-Jørgensen 	err = rmdir(custpath);
1532f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "rmdir custpindir", "err %d errno %d\n", err, errno))
1542f4a32ccSToke Høiland-Jørgensen 		goto out;
1552f4a32ccSToke Høiland-Jørgensen 
1562f4a32ccSToke Høiland-Jørgensen 	bpf_object__close(obj);
1572f4a32ccSToke Høiland-Jørgensen 
1582f4a32ccSToke Høiland-Jørgensen 	/* open the valid object file again */
1592f4a32ccSToke Høiland-Jørgensen 	obj = bpf_object__open_file(file, NULL);
1602f4a32ccSToke Høiland-Jørgensen 	err = libbpf_get_error(obj);
1612f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "default open", "err %d errno %d\n", err, errno)) {
1622f4a32ccSToke Høiland-Jørgensen 		obj = NULL;
1632f4a32ccSToke Høiland-Jørgensen 		goto out;
1642f4a32ccSToke Høiland-Jørgensen 	}
1652f4a32ccSToke Høiland-Jørgensen 
1669c4e395aSToke Høiland-Jørgensen 	/* set pin paths so that nopinmap2 will attempt to reuse the map at
1679c4e395aSToke Høiland-Jørgensen 	 * pinpath (which will fail), but not before pinmap has already been
1689c4e395aSToke Høiland-Jørgensen 	 * reused
1699c4e395aSToke Høiland-Jørgensen 	 */
1702f4a32ccSToke Høiland-Jørgensen 	bpf_object__for_each_map(map, obj) {
1712f4a32ccSToke Høiland-Jørgensen 		if (!strcmp(bpf_map__name(map), "nopinmap"))
1729c4e395aSToke Høiland-Jørgensen 			err = bpf_map__set_pin_path(map, nopinpath2);
1739c4e395aSToke Høiland-Jørgensen 		else if (!strcmp(bpf_map__name(map), "nopinmap2"))
1742f4a32ccSToke Høiland-Jørgensen 			err = bpf_map__set_pin_path(map, pinpath);
1752f4a32ccSToke Høiland-Jørgensen 		else
1762f4a32ccSToke Høiland-Jørgensen 			continue;
1772f4a32ccSToke Høiland-Jørgensen 
1782f4a32ccSToke Høiland-Jørgensen 		if (CHECK(err, "set pin path", "err %d errno %d\n", err, errno))
1792f4a32ccSToke Høiland-Jørgensen 			goto out;
1802f4a32ccSToke Høiland-Jørgensen 	}
1812f4a32ccSToke Høiland-Jørgensen 
1822f4a32ccSToke Høiland-Jørgensen 	/* should fail because of map parameter mismatch */
1832f4a32ccSToke Høiland-Jørgensen 	err = bpf_object__load(obj);
1842f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err != -EINVAL, "param mismatch load", "err %d errno %d\n", err, errno))
1852f4a32ccSToke Høiland-Jørgensen 		goto out;
1862f4a32ccSToke Høiland-Jørgensen 
1879c4e395aSToke Høiland-Jørgensen 	/* nopinmap2 should have been pinned and cleaned up again */
1889c4e395aSToke Høiland-Jørgensen 	err = stat(nopinpath2, &statbuf);
1899c4e395aSToke Høiland-Jørgensen 	if (CHECK(!err || errno != ENOENT, "stat nopinpath2",
1909c4e395aSToke Høiland-Jørgensen 		  "err %d errno %d\n", err, errno))
1919c4e395aSToke Høiland-Jørgensen 		goto out;
1929c4e395aSToke Høiland-Jørgensen 
1939c4e395aSToke Høiland-Jørgensen 	/* pinmap should still be there */
1949c4e395aSToke Høiland-Jørgensen 	err = stat(pinpath, &statbuf);
1959c4e395aSToke Høiland-Jørgensen 	if (CHECK(err, "stat pinpath", "err %d errno %d\n", err, errno))
1969c4e395aSToke Høiland-Jørgensen 		goto out;
1979c4e395aSToke Høiland-Jørgensen 
1982f4a32ccSToke Høiland-Jørgensen 	bpf_object__close(obj);
1992f4a32ccSToke Høiland-Jørgensen 
2002f4a32ccSToke Høiland-Jørgensen 	/* test auto-pinning at custom path with open opt */
2012f4a32ccSToke Høiland-Jørgensen 	obj = bpf_object__open_file(file, &opts);
2022f4a32ccSToke Høiland-Jørgensen 	if (CHECK_FAIL(libbpf_get_error(obj))) {
2032f4a32ccSToke Høiland-Jørgensen 		obj = NULL;
2042f4a32ccSToke Høiland-Jørgensen 		goto out;
2052f4a32ccSToke Høiland-Jørgensen 	}
2062f4a32ccSToke Høiland-Jørgensen 
2072f4a32ccSToke Høiland-Jørgensen 	err = bpf_object__load(obj);
2082f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "custom load", "err %d errno %d\n", err, errno))
2092f4a32ccSToke Høiland-Jørgensen 		goto out;
2102f4a32ccSToke Høiland-Jørgensen 
2112f4a32ccSToke Høiland-Jørgensen 	/* check that pinmap was pinned at the custom path */
2122f4a32ccSToke Høiland-Jørgensen 	err = stat(custpinpath, &statbuf);
2132f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno))
2142f4a32ccSToke Høiland-Jørgensen 		goto out;
2152f4a32ccSToke Høiland-Jørgensen 
2162f4a32ccSToke Høiland-Jørgensen out:
2172f4a32ccSToke Høiland-Jørgensen 	unlink(pinpath);
2182f4a32ccSToke Høiland-Jørgensen 	unlink(nopinpath);
2192f4a32ccSToke Høiland-Jørgensen 	unlink(nopinpath2);
2202f4a32ccSToke Høiland-Jørgensen 	unlink(custpinpath);
2212f4a32ccSToke Høiland-Jørgensen 	rmdir(custpath);
2222f4a32ccSToke Høiland-Jørgensen 	if (obj)
2232f4a32ccSToke Høiland-Jørgensen 		bpf_object__close(obj);
2242f4a32ccSToke Høiland-Jørgensen }
225