File Index
Files and directories
Sign in
FILE

cgroup_mprog_opts.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/prog_tests/cgroup_mprog_opts.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
  3#include <test_progs.h>
  4#include "cgroup_helpers.h"
  5#include "cgroup_mprog.skel.h"
  6
  7static void assert_mprog_count(int cg, int atype, int expected)
  8{
  9	__u32 count = 0, attach_flags = 0;
 10	int err;
 11
 12	err = bpf_prog_query(cg, atype, 0, &attach_flags,
 13			     NULL, &count);
 14	ASSERT_EQ(count, expected, "count");
 15	ASSERT_EQ(err, 0, "prog_query");
 16}
 17
 18static void test_prog_attach_detach(int atype)
 19{
 20	LIBBPF_OPTS(bpf_prog_attach_opts, opta);
 21	LIBBPF_OPTS(bpf_prog_detach_opts, optd);
 22	LIBBPF_OPTS(bpf_prog_query_opts, optq);
 23	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
 24	struct cgroup_mprog *skel;
 25	__u32 prog_ids[10];
 26	int cg, err;
 27
 28	cg = test__join_cgroup("/prog_attach_detach");
 29	if (!ASSERT_GE(cg, 0, "join_cgroup /prog_attach_detach"))
 30		return;
 31
 32	skel = cgroup_mprog__open_and_load();
 33	if (!ASSERT_OK_PTR(skel, "skel_load"))
 34		goto cleanup;
 35
 36	fd1 = bpf_program__fd(skel->progs.getsockopt_1);
 37	fd2 = bpf_program__fd(skel->progs.getsockopt_2);
 38	fd3 = bpf_program__fd(skel->progs.getsockopt_3);
 39	fd4 = bpf_program__fd(skel->progs.getsockopt_4);
 40
 41	id1 = id_from_prog_fd(fd1);
 42	id2 = id_from_prog_fd(fd2);
 43	id3 = id_from_prog_fd(fd3);
 44	id4 = id_from_prog_fd(fd4);
 45
 46	assert_mprog_count(cg, atype, 0);
 47
 48	LIBBPF_OPTS_RESET(opta,
 49		.flags = BPF_F_ALLOW_MULTI | BPF_F_BEFORE | BPF_F_AFTER,
 50		.expected_revision = 1,
 51	);
 52
 53	/* ordering: [fd1] */
 54	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
 55	if (!ASSERT_EQ(err, 0, "prog_attach"))
 56		goto cleanup;
 57
 58	assert_mprog_count(cg, atype, 1);
 59
 60	LIBBPF_OPTS_RESET(opta,
 61		.flags = BPF_F_ALLOW_MULTI | BPF_F_BEFORE,
 62		.expected_revision = 2,
 63	);
 64
 65	/* ordering: [fd2, fd1] */
 66	err = bpf_prog_attach_opts(fd2, cg, atype, &opta);
 67	if (!ASSERT_EQ(err, 0, "prog_attach"))
 68		goto cleanup1;
 69
 70	assert_mprog_count(cg, atype, 2);
 71
 72	LIBBPF_OPTS_RESET(opta,
 73		.flags = BPF_F_ALLOW_MULTI | BPF_F_AFTER,
 74		.relative_fd = fd2,
 75		.expected_revision = 3,
 76	);
 77
 78	/* ordering: [fd2, fd3, fd1] */
 79	err = bpf_prog_attach_opts(fd3, cg, atype, &opta);
 80	if (!ASSERT_EQ(err, 0, "prog_attach"))
 81		goto cleanup2;
 82
 83	assert_mprog_count(cg, atype, 3);
 84
 85	LIBBPF_OPTS_RESET(opta,
 86		.flags = BPF_F_ALLOW_MULTI,
 87		.expected_revision = 4,
 88	);
 89
 90	/* ordering: [fd2, fd3, fd1, fd4] */
 91	err = bpf_prog_attach_opts(fd4, cg, atype, &opta);
 92	if (!ASSERT_EQ(err, 0, "prog_attach"))
 93		goto cleanup3;
 94
 95	assert_mprog_count(cg, atype, 4);
 96
 97	/* retrieve optq.prog_cnt */
 98	err = bpf_prog_query_opts(cg, atype, &optq);
 99	if (!ASSERT_OK(err, "prog_query"))
100		goto cleanup4;
101
102	/* optq.prog_cnt will be used in below query */
103	memset(prog_ids, 0, sizeof(prog_ids));
104	optq.prog_ids = prog_ids;
105	err = bpf_prog_query_opts(cg, atype, &optq);
106	if (!ASSERT_OK(err, "prog_query"))
107		goto cleanup4;
108
109	ASSERT_EQ(optq.count, 4, "count");
110	ASSERT_EQ(optq.revision, 5, "revision");
111	ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
112	ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
113	ASSERT_EQ(optq.prog_ids[2], id1, "prog_ids[2]");
114	ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
115	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
116	ASSERT_EQ(optq.link_ids, NULL, "link_ids");
117
118cleanup4:
119	optd.expected_revision = 5;
120	err = bpf_prog_detach_opts(fd4, cg, atype, &optd);
121	ASSERT_OK(err, "prog_detach");
122	assert_mprog_count(cg, atype, 3);
123
124cleanup3:
125	LIBBPF_OPTS_RESET(optd);
126	err = bpf_prog_detach_opts(fd3, cg, atype, &optd);
127	ASSERT_OK(err, "prog_detach");
128	assert_mprog_count(cg, atype, 2);
129
130	/* Check revision after two detach operations */
131	err = bpf_prog_query_opts(cg, atype, &optq);
132	ASSERT_OK(err, "prog_query");
133	ASSERT_EQ(optq.revision, 7, "revision");
134
135cleanup2:
136	err = bpf_prog_detach_opts(fd2, cg, atype, &optd);
137	ASSERT_OK(err, "prog_detach");
138	assert_mprog_count(cg, atype, 1);
139
140cleanup1:
141	err = bpf_prog_detach_opts(fd1, cg, atype, &optd);
142	ASSERT_OK(err, "prog_detach");
143	assert_mprog_count(cg, atype, 0);
144
145cleanup:
146	cgroup_mprog__destroy(skel);
147	close(cg);
148}
149
150static void test_link_attach_detach(int atype)
151{
152	LIBBPF_OPTS(bpf_cgroup_opts, opta);
153	LIBBPF_OPTS(bpf_cgroup_opts, optd);
154	LIBBPF_OPTS(bpf_prog_query_opts, optq);
155	struct bpf_link *link1, *link2, *link3, *link4;
156	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
157	struct cgroup_mprog *skel;
158	__u32 prog_ids[10];
159	int cg, err;
160
161	cg = test__join_cgroup("/link_attach_detach");
162	if (!ASSERT_GE(cg, 0, "join_cgroup /link_attach_detach"))
163		return;
164
165	skel = cgroup_mprog__open_and_load();
166	if (!ASSERT_OK_PTR(skel, "skel_load"))
167		goto cleanup;
168
169	fd1 = bpf_program__fd(skel->progs.getsockopt_1);
170	fd2 = bpf_program__fd(skel->progs.getsockopt_2);
171	fd3 = bpf_program__fd(skel->progs.getsockopt_3);
172	fd4 = bpf_program__fd(skel->progs.getsockopt_4);
173
174	id1 = id_from_prog_fd(fd1);
175	id2 = id_from_prog_fd(fd2);
176	id3 = id_from_prog_fd(fd3);
177	id4 = id_from_prog_fd(fd4);
178
179	assert_mprog_count(cg, atype, 0);
180
181	LIBBPF_OPTS_RESET(opta,
182		.expected_revision = 1,
183	);
184
185	/* ordering: [fd1] */
186	link1 = bpf_program__attach_cgroup_opts(skel->progs.getsockopt_1, cg, &opta);
187	if (!ASSERT_OK_PTR(link1, "link_attach"))
188		goto cleanup;
189
190	assert_mprog_count(cg, atype, 1);
191
192	LIBBPF_OPTS_RESET(opta,
193		.flags = BPF_F_BEFORE | BPF_F_LINK,
194		.relative_id = id_from_link_fd(bpf_link__fd(link1)),
195		.expected_revision = 2,
196	);
197
198	/* ordering: [fd2, fd1] */
199	link2 = bpf_program__attach_cgroup_opts(skel->progs.getsockopt_2, cg, &opta);
200	if (!ASSERT_OK_PTR(link2, "link_attach"))
201		goto cleanup1;
202
203	assert_mprog_count(cg, atype, 2);
204
205	LIBBPF_OPTS_RESET(opta,
206		.flags = BPF_F_AFTER | BPF_F_LINK,
207		.relative_fd = bpf_link__fd(link2),
208		.expected_revision = 3,
209	);
210
211	/* ordering: [fd2, fd3, fd1] */
212	link3 = bpf_program__attach_cgroup_opts(skel->progs.getsockopt_3, cg, &opta);
213	if (!ASSERT_OK_PTR(link3, "link_attach"))
214		goto cleanup2;
215
216	assert_mprog_count(cg, atype, 3);
217
218	LIBBPF_OPTS_RESET(opta,
219		.expected_revision = 4,
220	);
221
222	/* ordering: [fd2, fd3, fd1, fd4] */
223	link4 = bpf_program__attach_cgroup_opts(skel->progs.getsockopt_4, cg, &opta);
224	if (!ASSERT_OK_PTR(link4, "link_attach"))
225		goto cleanup3;
226
227	assert_mprog_count(cg, atype, 4);
228
229	/* retrieve optq.prog_cnt */
230	err = bpf_prog_query_opts(cg, atype, &optq);
231	if (!ASSERT_OK(err, "prog_query"))
232		goto cleanup4;
233
234	/* optq.prog_cnt will be used in below query */
235	memset(prog_ids, 0, sizeof(prog_ids));
236	optq.prog_ids = prog_ids;
237	err = bpf_prog_query_opts(cg, atype, &optq);
238	if (!ASSERT_OK(err, "prog_query"))
239		goto cleanup4;
240
241	ASSERT_EQ(optq.count, 4, "count");
242	ASSERT_EQ(optq.revision, 5, "revision");
243	ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");
244	ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");
245	ASSERT_EQ(optq.prog_ids[2], id1, "prog_ids[2]");
246	ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");
247	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");
248	ASSERT_EQ(optq.link_ids, NULL, "link_ids");
249
250cleanup4:
251	bpf_link__destroy(link4);
252	assert_mprog_count(cg, atype, 3);
253
254cleanup3:
255	bpf_link__destroy(link3);
256	assert_mprog_count(cg, atype, 2);
257
258	/* Check revision after two detach operations */
259	err = bpf_prog_query_opts(cg, atype, &optq);
260	ASSERT_OK(err, "prog_query");
261	ASSERT_EQ(optq.revision, 7, "revision");
262
263cleanup2:
264	bpf_link__destroy(link2);
265	assert_mprog_count(cg, atype, 1);
266
267cleanup1:
268	bpf_link__destroy(link1);
269	assert_mprog_count(cg, atype, 0);
270
271cleanup:
272	cgroup_mprog__destroy(skel);
273	close(cg);
274}
275
276static void test_preorder_prog_attach_detach(int atype)
277{
278	LIBBPF_OPTS(bpf_prog_attach_opts, opta);
279	LIBBPF_OPTS(bpf_prog_detach_opts, optd);
280	__u32 fd1, fd2, fd3, fd4;
281	struct cgroup_mprog *skel;
282	int cg, err;
283
284	cg = test__join_cgroup("/preorder_prog_attach_detach");
285	if (!ASSERT_GE(cg, 0, "join_cgroup /preorder_prog_attach_detach"))
286		return;
287
288	skel = cgroup_mprog__open_and_load();
289	if (!ASSERT_OK_PTR(skel, "skel_load"))
290		goto cleanup;
291
292	fd1 = bpf_program__fd(skel->progs.getsockopt_1);
293	fd2 = bpf_program__fd(skel->progs.getsockopt_2);
294	fd3 = bpf_program__fd(skel->progs.getsockopt_3);
295	fd4 = bpf_program__fd(skel->progs.getsockopt_4);
296
297	assert_mprog_count(cg, atype, 0);
298
299	LIBBPF_OPTS_RESET(opta,
300		.flags = BPF_F_ALLOW_MULTI,
301		.expected_revision = 1,
302	);
303
304	/* ordering: [fd1] */
305	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
306	if (!ASSERT_EQ(err, 0, "prog_attach"))
307		goto cleanup;
308
309	assert_mprog_count(cg, atype, 1);
310
311	LIBBPF_OPTS_RESET(opta,
312		.flags = BPF_F_ALLOW_MULTI | BPF_F_PREORDER,
313		.expected_revision = 2,
314	);
315
316	/* ordering: [fd1, fd2] */
317	err = bpf_prog_attach_opts(fd2, cg, atype, &opta);
318	if (!ASSERT_EQ(err, 0, "prog_attach"))
319		goto cleanup1;
320
321	assert_mprog_count(cg, atype, 2);
322
323	LIBBPF_OPTS_RESET(opta,
324		.flags = BPF_F_ALLOW_MULTI | BPF_F_AFTER,
325		.relative_fd = fd2,
326		.expected_revision = 3,
327	);
328
329	err = bpf_prog_attach_opts(fd3, cg, atype, &opta);
330	if (!ASSERT_EQ(err, -EINVAL, "prog_attach"))
331		goto cleanup2;
332
333	assert_mprog_count(cg, atype, 2);
334
335	LIBBPF_OPTS_RESET(opta,
336		.flags = BPF_F_ALLOW_MULTI | BPF_F_AFTER | BPF_F_PREORDER,
337		.relative_fd = fd2,
338		.expected_revision = 3,
339	);
340
341	/* ordering: [fd1, fd2, fd3] */
342	err = bpf_prog_attach_opts(fd3, cg, atype, &opta);
343	if (!ASSERT_EQ(err, 0, "prog_attach"))
344		goto cleanup2;
345
346	assert_mprog_count(cg, atype, 3);
347
348	LIBBPF_OPTS_RESET(opta,
349		.flags = BPF_F_ALLOW_MULTI,
350		.expected_revision = 4,
351	);
352
353	/* ordering: [fd2, fd3, fd1, fd4] */
354	err = bpf_prog_attach_opts(fd4, cg, atype, &opta);
355	if (!ASSERT_EQ(err, 0, "prog_attach"))
356		goto cleanup3;
357
358	assert_mprog_count(cg, atype, 4);
359
360	err = bpf_prog_detach_opts(fd4, cg, atype, &optd);
361	ASSERT_OK(err, "prog_detach");
362	assert_mprog_count(cg, atype, 3);
363
364cleanup3:
365	err = bpf_prog_detach_opts(fd3, cg, atype, &optd);
366	ASSERT_OK(err, "prog_detach");
367	assert_mprog_count(cg, atype, 2);
368
369cleanup2:
370	err = bpf_prog_detach_opts(fd2, cg, atype, &optd);
371	ASSERT_OK(err, "prog_detach");
372	assert_mprog_count(cg, atype, 1);
373
374cleanup1:
375	err = bpf_prog_detach_opts(fd1, cg, atype, &optd);
376	ASSERT_OK(err, "prog_detach");
377	assert_mprog_count(cg, atype, 0);
378
379cleanup:
380	cgroup_mprog__destroy(skel);
381	close(cg);
382}
383
384static void test_preorder_link_attach_detach(int atype)
385{
386	LIBBPF_OPTS(bpf_cgroup_opts, opta);
387	struct bpf_link *link1, *link2, *link3, *link4;
388	struct cgroup_mprog *skel;
389	__u32 fd2;
390	int cg;
391
392	cg = test__join_cgroup("/preorder_link_attach_detach");
393	if (!ASSERT_GE(cg, 0, "join_cgroup /preorder_link_attach_detach"))
394		return;
395
396	skel = cgroup_mprog__open_and_load();
397	if (!ASSERT_OK_PTR(skel, "skel_load"))
398		goto cleanup;
399
400	fd2 = bpf_program__fd(skel->progs.getsockopt_2);
401
402	assert_mprog_count(cg, atype, 0);
403
404	LIBBPF_OPTS_RESET(opta,
405		.expected_revision = 1,
406	);
407
408	/* ordering: [fd1] */
409	link1 = bpf_program__attach_cgroup_opts(skel->progs.getsockopt_1, cg, &opta);
410	if (!ASSERT_OK_PTR(link1, "link_attach"))
411		goto cleanup;
412
413	assert_mprog_count(cg, atype, 1);
414
415	LIBBPF_OPTS_RESET(opta,
416		.flags = BPF_F_PREORDER,
417		.expected_revision = 2,
418	);
419
420	/* ordering: [fd1, fd2] */
421	link2 = bpf_program__attach_cgroup_opts(skel->progs.getsockopt_2, cg, &opta);
422	if (!ASSERT_OK_PTR(link2, "link_attach"))
423		goto cleanup1;
424
425	assert_mprog_count(cg, atype, 2);
426
427	LIBBPF_OPTS_RESET(opta,
428		.flags = BPF_F_AFTER,
429		.relative_fd = fd2,
430		.expected_revision = 3,
431	);
432
433	link3 = bpf_program__attach_cgroup_opts(skel->progs.getsockopt_3, cg, &opta);
434	if (!ASSERT_ERR_PTR(link3, "link_attach"))
435		goto cleanup2;
436
437	assert_mprog_count(cg, atype, 2);
438
439	LIBBPF_OPTS_RESET(opta,
440		.flags = BPF_F_AFTER | BPF_F_PREORDER | BPF_F_LINK,
441		.relative_fd = bpf_link__fd(link2),
442		.expected_revision = 3,
443	);
444
445	/* ordering: [fd1, fd2, fd3] */
446	link3 = bpf_program__attach_cgroup_opts(skel->progs.getsockopt_3, cg, &opta);
447	if (!ASSERT_OK_PTR(link3, "link_attach"))
448		goto cleanup2;
449
450	assert_mprog_count(cg, atype, 3);
451
452	LIBBPF_OPTS_RESET(opta,
453		.expected_revision = 4,
454	);
455
456	/* ordering: [fd2, fd3, fd1, fd4] */
457	link4 = bpf_program__attach_cgroup_opts(skel->progs.getsockopt_4, cg, &opta);
458	if (!ASSERT_OK_PTR(link4, "prog_attach"))
459		goto cleanup3;
460
461	assert_mprog_count(cg, atype, 4);
462
463	bpf_link__destroy(link4);
464	assert_mprog_count(cg, atype, 3);
465
466cleanup3:
467	bpf_link__destroy(link3);
468	assert_mprog_count(cg, atype, 2);
469
470cleanup2:
471	bpf_link__destroy(link2);
472	assert_mprog_count(cg, atype, 1);
473
474cleanup1:
475	bpf_link__destroy(link1);
476	assert_mprog_count(cg, atype, 0);
477
478cleanup:
479	cgroup_mprog__destroy(skel);
480	close(cg);
481}
482
483static void test_invalid_attach_detach(int atype)
484{
485	LIBBPF_OPTS(bpf_prog_attach_opts, opta);
486	__u32 fd1, fd2, id2;
487	struct cgroup_mprog *skel;
488	int cg, err;
489
490	cg = test__join_cgroup("/invalid_attach_detach");
491	if (!ASSERT_GE(cg, 0, "join_cgroup /invalid_attach_detach"))
492		return;
493
494	skel = cgroup_mprog__open_and_load();
495	if (!ASSERT_OK_PTR(skel, "skel_load"))
496		goto cleanup;
497
498	fd1 = bpf_program__fd(skel->progs.getsockopt_1);
499	fd2 = bpf_program__fd(skel->progs.getsockopt_2);
500
501	id2 = id_from_prog_fd(fd2);
502
503	assert_mprog_count(cg, atype, 0);
504
505	LIBBPF_OPTS_RESET(opta,
506		.flags = BPF_F_ALLOW_MULTI | BPF_F_BEFORE | BPF_F_AFTER,
507		.relative_id = id2,
508	);
509
510	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
511	ASSERT_EQ(err, -EINVAL, "prog_attach");
512	assert_mprog_count(cg, atype, 0);
513
514	LIBBPF_OPTS_RESET(opta,
515		.flags = BPF_F_ALLOW_MULTI | BPF_F_BEFORE | BPF_F_ID,
516	);
517
518	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
519	ASSERT_EQ(err, -ENOENT, "prog_attach");
520	assert_mprog_count(cg, atype, 0);
521
522	LIBBPF_OPTS_RESET(opta,
523		.flags = BPF_F_ALLOW_MULTI | BPF_F_AFTER | BPF_F_ID,
524	);
525
526	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
527	ASSERT_EQ(err, -ENOENT, "prog_attach");
528	assert_mprog_count(cg, atype, 0);
529
530	LIBBPF_OPTS_RESET(opta,
531		.flags = BPF_F_ALLOW_MULTI | BPF_F_BEFORE | BPF_F_AFTER,
532		.relative_id = id2,
533	);
534
535	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
536	ASSERT_EQ(err, -EINVAL, "prog_attach");
537	assert_mprog_count(cg, atype, 0);
538
539	LIBBPF_OPTS_RESET(opta,
540		.flags = BPF_F_ALLOW_MULTI | BPF_F_LINK,
541		.relative_id = id2,
542	);
543
544	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
545	ASSERT_EQ(err, -EINVAL, "prog_attach");
546	assert_mprog_count(cg, atype, 0);
547
548	LIBBPF_OPTS_RESET(opta,
549		.flags = BPF_F_ALLOW_MULTI,
550		.relative_id = id2,
551	);
552
553	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
554	ASSERT_EQ(err, -EINVAL, "prog_attach");
555	assert_mprog_count(cg, atype, 0);
556
557	LIBBPF_OPTS_RESET(opta,
558		.flags = BPF_F_ALLOW_MULTI | BPF_F_BEFORE,
559		.relative_fd = fd1,
560	);
561
562	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
563	ASSERT_EQ(err, -ENOENT, "prog_attach");
564	assert_mprog_count(cg, atype, 0);
565
566	LIBBPF_OPTS_RESET(opta,
567		.flags = BPF_F_ALLOW_MULTI | BPF_F_AFTER,
568		.relative_fd = fd1,
569	);
570
571	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
572	ASSERT_EQ(err, -ENOENT, "prog_attach");
573	assert_mprog_count(cg, atype, 0);
574
575	LIBBPF_OPTS_RESET(opta,
576		.flags = BPF_F_ALLOW_MULTI,
577	);
578
579	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
580	if (!ASSERT_EQ(err, 0, "prog_attach"))
581		goto cleanup;
582	assert_mprog_count(cg, atype, 1);
583
584	LIBBPF_OPTS_RESET(opta,
585		.flags = BPF_F_ALLOW_MULTI | BPF_F_AFTER,
586	);
587
588	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
589	ASSERT_EQ(err, -EINVAL, "prog_attach");
590	assert_mprog_count(cg, atype, 1);
591
592	LIBBPF_OPTS_RESET(opta,
593		.flags = BPF_F_ALLOW_MULTI | BPF_F_REPLACE | BPF_F_AFTER,
594		.replace_prog_fd = fd1,
595	);
596
597	err = bpf_prog_attach_opts(fd1, cg, atype, &opta);
598	ASSERT_EQ(err, -EINVAL, "prog_attach");
599	assert_mprog_count(cg, atype, 1);
600cleanup:
601	cgroup_mprog__destroy(skel);
602	close(cg);
603}
604
605void test_cgroup_mprog_opts(void)
606{
607	if (test__start_subtest("prog_attach_detach"))
608		test_prog_attach_detach(BPF_CGROUP_GETSOCKOPT);
609	if (test__start_subtest("link_attach_detach"))
610		test_link_attach_detach(BPF_CGROUP_GETSOCKOPT);
611	if (test__start_subtest("preorder_prog_attach_detach"))
612		test_preorder_prog_attach_detach(BPF_CGROUP_GETSOCKOPT);
613	if (test__start_subtest("preorder_link_attach_detach"))
614		test_preorder_link_attach_detach(BPF_CGROUP_GETSOCKOPT);
615	if (test__start_subtest("invalid_attach_detach"))
616		test_invalid_attach_detach(BPF_CGROUP_GETSOCKOPT);
617}
~/ Read-only file preview.