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 
get_map_id(struct bpf_object * obj,const char * name)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 
21*c5a237a4SIlya Leoshkevich 	err = bpf_map_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 
test_pinning(void)272f4a32ccSToke Høiland-Jørgensen void test_pinning(void)
282f4a32ccSToke Høiland-Jørgensen {
29afef88e6SDaniel Müller 	const char *file_invalid = "./test_pinning_invalid.bpf.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";
35afef88e6SDaniel Müller 	const char *file = "./test_pinning.bpf.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;
4044c4aa2bSHangbin Liu 	int err, map_fd;
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 
128e244d34dSEvgeniy Litvinenko 	/* get pinning path */
129e244d34dSEvgeniy Litvinenko 	if (!ASSERT_STREQ(bpf_map__pin_path(map), pinpath, "get pin path"))
130e244d34dSEvgeniy Litvinenko 		goto out;
131e244d34dSEvgeniy Litvinenko 
1322f4a32ccSToke Høiland-Jørgensen 	/* set pinning path of other map and re-pin all */
1332f4a32ccSToke Høiland-Jørgensen 	map = bpf_object__find_map_by_name(obj, "nopinmap");
1342f4a32ccSToke Høiland-Jørgensen 	if (CHECK(!map, "find map", "NULL map"))
1352f4a32ccSToke Høiland-Jørgensen 		goto out;
1362f4a32ccSToke Høiland-Jørgensen 
1372f4a32ccSToke Høiland-Jørgensen 	err = bpf_map__set_pin_path(map, custpinpath);
1382f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "set pin path", "err %d errno %d\n", err, errno))
1392f4a32ccSToke Høiland-Jørgensen 		goto out;
1402f4a32ccSToke Høiland-Jørgensen 
141e244d34dSEvgeniy Litvinenko 	/* get pinning path after set */
142e244d34dSEvgeniy Litvinenko 	if (!ASSERT_STREQ(bpf_map__pin_path(map), custpinpath,
143e244d34dSEvgeniy Litvinenko 			  "get pin path after set"))
144e244d34dSEvgeniy Litvinenko 		goto out;
145e244d34dSEvgeniy Litvinenko 
1462f4a32ccSToke Høiland-Jørgensen 	/* should only pin the one unpinned map */
1472f4a32ccSToke Høiland-Jørgensen 	err = bpf_object__pin_maps(obj, NULL);
1482f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "pin maps", "err %d errno %d\n", err, errno))
1492f4a32ccSToke Høiland-Jørgensen 		goto out;
1502f4a32ccSToke Høiland-Jørgensen 
1512f4a32ccSToke Høiland-Jørgensen 	/* check that nopinmap was pinned at the custom path */
1522f4a32ccSToke Høiland-Jørgensen 	err = stat(custpinpath, &statbuf);
1532f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno))
1542f4a32ccSToke Høiland-Jørgensen 		goto out;
1552f4a32ccSToke Høiland-Jørgensen 
1562f4a32ccSToke Høiland-Jørgensen 	/* remove the custom pin path to re-test it with auto-pinning below */
1572f4a32ccSToke Høiland-Jørgensen 	err = unlink(custpinpath);
1582f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "unlink custpinpath", "err %d errno %d\n", err, errno))
1592f4a32ccSToke Høiland-Jørgensen 		goto out;
1602f4a32ccSToke Høiland-Jørgensen 
1612f4a32ccSToke Høiland-Jørgensen 	err = rmdir(custpath);
1622f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "rmdir custpindir", "err %d errno %d\n", err, errno))
1632f4a32ccSToke Høiland-Jørgensen 		goto out;
1642f4a32ccSToke Høiland-Jørgensen 
1652f4a32ccSToke Høiland-Jørgensen 	bpf_object__close(obj);
1662f4a32ccSToke Høiland-Jørgensen 
1672f4a32ccSToke Høiland-Jørgensen 	/* open the valid object file again */
1682f4a32ccSToke Høiland-Jørgensen 	obj = bpf_object__open_file(file, NULL);
1692f4a32ccSToke Høiland-Jørgensen 	err = libbpf_get_error(obj);
1702f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "default open", "err %d errno %d\n", err, errno)) {
1712f4a32ccSToke Høiland-Jørgensen 		obj = NULL;
1722f4a32ccSToke Høiland-Jørgensen 		goto out;
1732f4a32ccSToke Høiland-Jørgensen 	}
1742f4a32ccSToke Høiland-Jørgensen 
1759c4e395aSToke Høiland-Jørgensen 	/* set pin paths so that nopinmap2 will attempt to reuse the map at
1769c4e395aSToke Høiland-Jørgensen 	 * pinpath (which will fail), but not before pinmap has already been
1779c4e395aSToke Høiland-Jørgensen 	 * reused
1789c4e395aSToke Høiland-Jørgensen 	 */
1792f4a32ccSToke Høiland-Jørgensen 	bpf_object__for_each_map(map, obj) {
1802f4a32ccSToke Høiland-Jørgensen 		if (!strcmp(bpf_map__name(map), "nopinmap"))
1819c4e395aSToke Høiland-Jørgensen 			err = bpf_map__set_pin_path(map, nopinpath2);
1829c4e395aSToke Høiland-Jørgensen 		else if (!strcmp(bpf_map__name(map), "nopinmap2"))
1832f4a32ccSToke Høiland-Jørgensen 			err = bpf_map__set_pin_path(map, pinpath);
1842f4a32ccSToke Høiland-Jørgensen 		else
1852f4a32ccSToke Høiland-Jørgensen 			continue;
1862f4a32ccSToke Høiland-Jørgensen 
1872f4a32ccSToke Høiland-Jørgensen 		if (CHECK(err, "set pin path", "err %d errno %d\n", err, errno))
1882f4a32ccSToke Høiland-Jørgensen 			goto out;
1892f4a32ccSToke Høiland-Jørgensen 	}
1902f4a32ccSToke Høiland-Jørgensen 
1912f4a32ccSToke Høiland-Jørgensen 	/* should fail because of map parameter mismatch */
1922f4a32ccSToke Høiland-Jørgensen 	err = bpf_object__load(obj);
1932f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err != -EINVAL, "param mismatch load", "err %d errno %d\n", err, errno))
1942f4a32ccSToke Høiland-Jørgensen 		goto out;
1952f4a32ccSToke Høiland-Jørgensen 
1969c4e395aSToke Høiland-Jørgensen 	/* nopinmap2 should have been pinned and cleaned up again */
1979c4e395aSToke Høiland-Jørgensen 	err = stat(nopinpath2, &statbuf);
1989c4e395aSToke Høiland-Jørgensen 	if (CHECK(!err || errno != ENOENT, "stat nopinpath2",
1999c4e395aSToke Høiland-Jørgensen 		  "err %d errno %d\n", err, errno))
2009c4e395aSToke Høiland-Jørgensen 		goto out;
2019c4e395aSToke Høiland-Jørgensen 
2029c4e395aSToke Høiland-Jørgensen 	/* pinmap should still be there */
2039c4e395aSToke Høiland-Jørgensen 	err = stat(pinpath, &statbuf);
2049c4e395aSToke Høiland-Jørgensen 	if (CHECK(err, "stat pinpath", "err %d errno %d\n", err, errno))
2059c4e395aSToke Høiland-Jørgensen 		goto out;
2069c4e395aSToke Høiland-Jørgensen 
2072f4a32ccSToke Høiland-Jørgensen 	bpf_object__close(obj);
2082f4a32ccSToke Høiland-Jørgensen 
2092f4a32ccSToke Høiland-Jørgensen 	/* test auto-pinning at custom path with open opt */
2102f4a32ccSToke Høiland-Jørgensen 	obj = bpf_object__open_file(file, &opts);
2112f4a32ccSToke Høiland-Jørgensen 	if (CHECK_FAIL(libbpf_get_error(obj))) {
2122f4a32ccSToke Høiland-Jørgensen 		obj = NULL;
2132f4a32ccSToke Høiland-Jørgensen 		goto out;
2142f4a32ccSToke Høiland-Jørgensen 	}
2152f4a32ccSToke Høiland-Jørgensen 
2162f4a32ccSToke Høiland-Jørgensen 	err = bpf_object__load(obj);
2172f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "custom load", "err %d errno %d\n", err, errno))
2182f4a32ccSToke Høiland-Jørgensen 		goto out;
2192f4a32ccSToke Høiland-Jørgensen 
2202f4a32ccSToke Høiland-Jørgensen 	/* check that pinmap was pinned at the custom path */
2212f4a32ccSToke Høiland-Jørgensen 	err = stat(custpinpath, &statbuf);
2222f4a32ccSToke Høiland-Jørgensen 	if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno))
2232f4a32ccSToke Høiland-Jørgensen 		goto out;
2242f4a32ccSToke Høiland-Jørgensen 
22544c4aa2bSHangbin Liu 	/* remove the custom pin path to re-test it with reuse fd below */
22644c4aa2bSHangbin Liu 	err = unlink(custpinpath);
22744c4aa2bSHangbin Liu 	if (CHECK(err, "unlink custpinpath", "err %d errno %d\n", err, errno))
22844c4aa2bSHangbin Liu 		goto out;
22944c4aa2bSHangbin Liu 
23044c4aa2bSHangbin Liu 	err = rmdir(custpath);
23144c4aa2bSHangbin Liu 	if (CHECK(err, "rmdir custpindir", "err %d errno %d\n", err, errno))
23244c4aa2bSHangbin Liu 		goto out;
23344c4aa2bSHangbin Liu 
23444c4aa2bSHangbin Liu 	bpf_object__close(obj);
23544c4aa2bSHangbin Liu 
23644c4aa2bSHangbin Liu 	/* test pinning at custom path with reuse fd */
23744c4aa2bSHangbin Liu 	obj = bpf_object__open_file(file, NULL);
23844c4aa2bSHangbin Liu 	err = libbpf_get_error(obj);
23944c4aa2bSHangbin Liu 	if (CHECK(err, "default open", "err %d errno %d\n", err, errno)) {
24044c4aa2bSHangbin Liu 		obj = NULL;
24144c4aa2bSHangbin Liu 		goto out;
24244c4aa2bSHangbin Liu 	}
24344c4aa2bSHangbin Liu 
2442fe256a4SAndrii Nakryiko 	map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, sizeof(__u32),
2452fe256a4SAndrii Nakryiko 				sizeof(__u64), 1, NULL);
24644c4aa2bSHangbin Liu 	if (CHECK(map_fd < 0, "create pinmap manually", "fd %d\n", map_fd))
24744c4aa2bSHangbin Liu 		goto out;
24844c4aa2bSHangbin Liu 
24944c4aa2bSHangbin Liu 	map = bpf_object__find_map_by_name(obj, "pinmap");
25044c4aa2bSHangbin Liu 	if (CHECK(!map, "find map", "NULL map"))
25144c4aa2bSHangbin Liu 		goto close_map_fd;
25244c4aa2bSHangbin Liu 
25344c4aa2bSHangbin Liu 	err = bpf_map__reuse_fd(map, map_fd);
25444c4aa2bSHangbin Liu 	if (CHECK(err, "reuse pinmap fd", "err %d errno %d\n", err, errno))
25544c4aa2bSHangbin Liu 		goto close_map_fd;
25644c4aa2bSHangbin Liu 
25744c4aa2bSHangbin Liu 	err = bpf_map__set_pin_path(map, custpinpath);
25844c4aa2bSHangbin Liu 	if (CHECK(err, "set pin path", "err %d errno %d\n", err, errno))
25944c4aa2bSHangbin Liu 		goto close_map_fd;
26044c4aa2bSHangbin Liu 
26144c4aa2bSHangbin Liu 	err = bpf_object__load(obj);
26244c4aa2bSHangbin Liu 	if (CHECK(err, "custom load", "err %d errno %d\n", err, errno))
26344c4aa2bSHangbin Liu 		goto close_map_fd;
26444c4aa2bSHangbin Liu 
26544c4aa2bSHangbin Liu 	/* check that pinmap was pinned at the custom path */
26644c4aa2bSHangbin Liu 	err = stat(custpinpath, &statbuf);
26744c4aa2bSHangbin Liu 	if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno))
26844c4aa2bSHangbin Liu 		goto close_map_fd;
26944c4aa2bSHangbin Liu 
27044c4aa2bSHangbin Liu close_map_fd:
27144c4aa2bSHangbin Liu 	close(map_fd);
2722f4a32ccSToke Høiland-Jørgensen out:
2732f4a32ccSToke Høiland-Jørgensen 	unlink(pinpath);
2742f4a32ccSToke Høiland-Jørgensen 	unlink(nopinpath);
2752f4a32ccSToke Høiland-Jørgensen 	unlink(nopinpath2);
2762f4a32ccSToke Høiland-Jørgensen 	unlink(custpinpath);
2772f4a32ccSToke Høiland-Jørgensen 	rmdir(custpath);
2782f4a32ccSToke Høiland-Jørgensen 	if (obj)
2792f4a32ccSToke Høiland-Jørgensen 		bpf_object__close(obj);
2802f4a32ccSToke Høiland-Jørgensen }
281