brintos

brintos / linux-shallow public Read only

0
0
Text · 76.2 KiB · f77f604 Raw
2815 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2023 Isovalent */3#include <uapi/linux/if_link.h>4#include <net/if.h>5#include <test_progs.h>6 7#define loopback 18#define ping_cmd "ping -q -c1 -w1 127.0.0.1 > /dev/null"9 10#include "test_tc_link.skel.h"11#include "tc_helpers.h"12 13void serial_test_tc_opts_basic(void)14{15	LIBBPF_OPTS(bpf_prog_attach_opts, opta);16	LIBBPF_OPTS(bpf_prog_detach_opts, optd);17	LIBBPF_OPTS(bpf_prog_query_opts, optq);18	__u32 fd1, fd2, id1, id2;19	struct test_tc_link *skel;20	__u32 prog_ids[2];21	int err;22 23	skel = test_tc_link__open_and_load();24	if (!ASSERT_OK_PTR(skel, "skel_load"))25		goto cleanup;26 27	fd1 = bpf_program__fd(skel->progs.tc1);28	fd2 = bpf_program__fd(skel->progs.tc2);29 30	id1 = id_from_prog_fd(fd1);31	id2 = id_from_prog_fd(fd2);32 33	ASSERT_NEQ(id1, id2, "prog_ids_1_2");34 35	assert_mprog_count(BPF_TCX_INGRESS, 0);36	assert_mprog_count(BPF_TCX_EGRESS, 0);37 38	ASSERT_EQ(skel->bss->seen_tc1, false, "seen_tc1");39	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");40 41	err = bpf_prog_attach_opts(fd1, loopback, BPF_TCX_INGRESS, &opta);42	if (!ASSERT_EQ(err, 0, "prog_attach"))43		goto cleanup;44 45	assert_mprog_count(BPF_TCX_INGRESS, 1);46	assert_mprog_count(BPF_TCX_EGRESS, 0);47 48	optq.prog_ids = prog_ids;49 50	memset(prog_ids, 0, sizeof(prog_ids));51	optq.count = ARRAY_SIZE(prog_ids);52 53	err = bpf_prog_query_opts(loopback, BPF_TCX_INGRESS, &optq);54	if (!ASSERT_OK(err, "prog_query"))55		goto cleanup_in;56 57	ASSERT_EQ(optq.count, 1, "count");58	ASSERT_EQ(optq.revision, 2, "revision");59	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");60	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");61 62	tc_skel_reset_all_seen(skel);63	ASSERT_OK(system(ping_cmd), ping_cmd);64 65	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");66	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");67 68	err = bpf_prog_attach_opts(fd2, loopback, BPF_TCX_EGRESS, &opta);69	if (!ASSERT_EQ(err, 0, "prog_attach"))70		goto cleanup_in;71 72	assert_mprog_count(BPF_TCX_INGRESS, 1);73	assert_mprog_count(BPF_TCX_EGRESS, 1);74 75	memset(prog_ids, 0, sizeof(prog_ids));76	optq.count = ARRAY_SIZE(prog_ids);77 78	err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq);79	if (!ASSERT_OK(err, "prog_query"))80		goto cleanup_eg;81 82	ASSERT_EQ(optq.count, 1, "count");83	ASSERT_EQ(optq.revision, 2, "revision");84	ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");85	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");86 87	tc_skel_reset_all_seen(skel);88	ASSERT_OK(system(ping_cmd), ping_cmd);89 90	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");91	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");92 93cleanup_eg:94	err = bpf_prog_detach_opts(fd2, loopback, BPF_TCX_EGRESS, &optd);95	ASSERT_OK(err, "prog_detach_eg");96 97	assert_mprog_count(BPF_TCX_INGRESS, 1);98	assert_mprog_count(BPF_TCX_EGRESS, 0);99 100cleanup_in:101	err = bpf_prog_detach_opts(fd1, loopback, BPF_TCX_INGRESS, &optd);102	ASSERT_OK(err, "prog_detach_in");103 104	assert_mprog_count(BPF_TCX_INGRESS, 0);105	assert_mprog_count(BPF_TCX_EGRESS, 0);106 107cleanup:108	test_tc_link__destroy(skel);109}110 111static void test_tc_opts_before_target(int target)112{113	LIBBPF_OPTS(bpf_prog_attach_opts, opta);114	LIBBPF_OPTS(bpf_prog_detach_opts, optd);115	LIBBPF_OPTS(bpf_prog_query_opts, optq);116	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;117	struct test_tc_link *skel;118	__u32 prog_ids[5];119	int err;120 121	skel = test_tc_link__open_and_load();122	if (!ASSERT_OK_PTR(skel, "skel_load"))123		goto cleanup;124 125	fd1 = bpf_program__fd(skel->progs.tc1);126	fd2 = bpf_program__fd(skel->progs.tc2);127	fd3 = bpf_program__fd(skel->progs.tc3);128	fd4 = bpf_program__fd(skel->progs.tc4);129 130	id1 = id_from_prog_fd(fd1);131	id2 = id_from_prog_fd(fd2);132	id3 = id_from_prog_fd(fd3);133	id4 = id_from_prog_fd(fd4);134 135	ASSERT_NEQ(id1, id2, "prog_ids_1_2");136	ASSERT_NEQ(id3, id4, "prog_ids_3_4");137	ASSERT_NEQ(id2, id3, "prog_ids_2_3");138 139	assert_mprog_count(target, 0);140 141	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);142	if (!ASSERT_EQ(err, 0, "prog_attach"))143		goto cleanup;144 145	assert_mprog_count(target, 1);146 147	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);148	if (!ASSERT_EQ(err, 0, "prog_attach"))149		goto cleanup_target;150 151	assert_mprog_count(target, 2);152 153	optq.prog_ids = prog_ids;154 155	memset(prog_ids, 0, sizeof(prog_ids));156	optq.count = ARRAY_SIZE(prog_ids);157 158	err = bpf_prog_query_opts(loopback, target, &optq);159	if (!ASSERT_OK(err, "prog_query"))160		goto cleanup_target2;161 162	ASSERT_EQ(optq.count, 2, "count");163	ASSERT_EQ(optq.revision, 3, "revision");164	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");165	ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");166	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");167 168	tc_skel_reset_all_seen(skel);169	ASSERT_OK(system(ping_cmd), ping_cmd);170 171	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");172	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");173	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");174	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");175 176	LIBBPF_OPTS_RESET(opta,177		.flags = BPF_F_BEFORE,178		.relative_fd = fd2,179	);180 181	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);182	if (!ASSERT_EQ(err, 0, "prog_attach"))183		goto cleanup_target2;184 185	memset(prog_ids, 0, sizeof(prog_ids));186	optq.count = ARRAY_SIZE(prog_ids);187 188	err = bpf_prog_query_opts(loopback, target, &optq);189	if (!ASSERT_OK(err, "prog_query"))190		goto cleanup_target3;191 192	ASSERT_EQ(optq.count, 3, "count");193	ASSERT_EQ(optq.revision, 4, "revision");194	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");195	ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");196	ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");197	ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");198 199	LIBBPF_OPTS_RESET(opta,200		.flags = BPF_F_BEFORE,201		.relative_id = id1,202	);203 204	err = bpf_prog_attach_opts(fd4, loopback, target, &opta);205	if (!ASSERT_EQ(err, 0, "prog_attach"))206		goto cleanup_target3;207 208	assert_mprog_count(target, 4);209 210	memset(prog_ids, 0, sizeof(prog_ids));211	optq.count = ARRAY_SIZE(prog_ids);212 213	err = bpf_prog_query_opts(loopback, target, &optq);214	if (!ASSERT_OK(err, "prog_query"))215		goto cleanup_target4;216 217	ASSERT_EQ(optq.count, 4, "count");218	ASSERT_EQ(optq.revision, 5, "revision");219	ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");220	ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");221	ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");222	ASSERT_EQ(optq.prog_ids[3], id2, "prog_ids[3]");223	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");224 225	tc_skel_reset_all_seen(skel);226	ASSERT_OK(system(ping_cmd), ping_cmd);227 228	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");229	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");230	ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");231	ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");232 233cleanup_target4:234	err = bpf_prog_detach_opts(fd4, loopback, target, &optd);235	ASSERT_OK(err, "prog_detach");236	assert_mprog_count(target, 3);237 238cleanup_target3:239	err = bpf_prog_detach_opts(fd3, loopback, target, &optd);240	ASSERT_OK(err, "prog_detach");241	assert_mprog_count(target, 2);242 243cleanup_target2:244	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);245	ASSERT_OK(err, "prog_detach");246	assert_mprog_count(target, 1);247 248cleanup_target:249	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);250	ASSERT_OK(err, "prog_detach");251	assert_mprog_count(target, 0);252 253cleanup:254	test_tc_link__destroy(skel);255}256 257void serial_test_tc_opts_before(void)258{259	test_tc_opts_before_target(BPF_TCX_INGRESS);260	test_tc_opts_before_target(BPF_TCX_EGRESS);261}262 263static void test_tc_opts_after_target(int target)264{265	LIBBPF_OPTS(bpf_prog_attach_opts, opta);266	LIBBPF_OPTS(bpf_prog_detach_opts, optd);267	LIBBPF_OPTS(bpf_prog_query_opts, optq);268	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;269	struct test_tc_link *skel;270	__u32 prog_ids[5];271	int err;272 273	skel = test_tc_link__open_and_load();274	if (!ASSERT_OK_PTR(skel, "skel_load"))275		goto cleanup;276 277	fd1 = bpf_program__fd(skel->progs.tc1);278	fd2 = bpf_program__fd(skel->progs.tc2);279	fd3 = bpf_program__fd(skel->progs.tc3);280	fd4 = bpf_program__fd(skel->progs.tc4);281 282	id1 = id_from_prog_fd(fd1);283	id2 = id_from_prog_fd(fd2);284	id3 = id_from_prog_fd(fd3);285	id4 = id_from_prog_fd(fd4);286 287	ASSERT_NEQ(id1, id2, "prog_ids_1_2");288	ASSERT_NEQ(id3, id4, "prog_ids_3_4");289	ASSERT_NEQ(id2, id3, "prog_ids_2_3");290 291	assert_mprog_count(target, 0);292 293	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);294	if (!ASSERT_EQ(err, 0, "prog_attach"))295		goto cleanup;296 297	assert_mprog_count(target, 1);298 299	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);300	if (!ASSERT_EQ(err, 0, "prog_attach"))301		goto cleanup_target;302 303	assert_mprog_count(target, 2);304 305	optq.prog_ids = prog_ids;306 307	memset(prog_ids, 0, sizeof(prog_ids));308	optq.count = ARRAY_SIZE(prog_ids);309 310	err = bpf_prog_query_opts(loopback, target, &optq);311	if (!ASSERT_OK(err, "prog_query"))312		goto cleanup_target2;313 314	ASSERT_EQ(optq.count, 2, "count");315	ASSERT_EQ(optq.revision, 3, "revision");316	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");317	ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");318	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");319 320	tc_skel_reset_all_seen(skel);321	ASSERT_OK(system(ping_cmd), ping_cmd);322 323	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");324	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");325	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");326	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");327 328	LIBBPF_OPTS_RESET(opta,329		.flags = BPF_F_AFTER,330		.relative_fd = fd1,331	);332 333	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);334	if (!ASSERT_EQ(err, 0, "prog_attach"))335		goto cleanup_target2;336 337	memset(prog_ids, 0, sizeof(prog_ids));338	optq.count = ARRAY_SIZE(prog_ids);339 340	err = bpf_prog_query_opts(loopback, target, &optq);341	if (!ASSERT_OK(err, "prog_query"))342		goto cleanup_target3;343 344	ASSERT_EQ(optq.count, 3, "count");345	ASSERT_EQ(optq.revision, 4, "revision");346	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");347	ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");348	ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");349	ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");350 351	LIBBPF_OPTS_RESET(opta,352		.flags = BPF_F_AFTER,353		.relative_id = id2,354	);355 356	err = bpf_prog_attach_opts(fd4, loopback, target, &opta);357	if (!ASSERT_EQ(err, 0, "prog_attach"))358		goto cleanup_target3;359 360	assert_mprog_count(target, 4);361 362	memset(prog_ids, 0, sizeof(prog_ids));363	optq.count = ARRAY_SIZE(prog_ids);364 365	err = bpf_prog_query_opts(loopback, target, &optq);366	if (!ASSERT_OK(err, "prog_query"))367		goto cleanup_target4;368 369	ASSERT_EQ(optq.count, 4, "count");370	ASSERT_EQ(optq.revision, 5, "revision");371	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");372	ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");373	ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");374	ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");375	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");376 377	tc_skel_reset_all_seen(skel);378	ASSERT_OK(system(ping_cmd), ping_cmd);379 380	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");381	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");382	ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");383	ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");384 385cleanup_target4:386	err = bpf_prog_detach_opts(fd4, loopback, target, &optd);387	ASSERT_OK(err, "prog_detach");388	assert_mprog_count(target, 3);389 390	memset(prog_ids, 0, sizeof(prog_ids));391	optq.count = ARRAY_SIZE(prog_ids);392 393	err = bpf_prog_query_opts(loopback, target, &optq);394	if (!ASSERT_OK(err, "prog_query"))395		goto cleanup_target3;396 397	ASSERT_EQ(optq.count, 3, "count");398	ASSERT_EQ(optq.revision, 6, "revision");399	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");400	ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");401	ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");402	ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");403 404cleanup_target3:405	err = bpf_prog_detach_opts(fd3, loopback, target, &optd);406	ASSERT_OK(err, "prog_detach");407	assert_mprog_count(target, 2);408 409	memset(prog_ids, 0, sizeof(prog_ids));410	optq.count = ARRAY_SIZE(prog_ids);411 412	err = bpf_prog_query_opts(loopback, target, &optq);413	if (!ASSERT_OK(err, "prog_query"))414		goto cleanup_target2;415 416	ASSERT_EQ(optq.count, 2, "count");417	ASSERT_EQ(optq.revision, 7, "revision");418	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");419	ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");420	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");421 422cleanup_target2:423	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);424	ASSERT_OK(err, "prog_detach");425	assert_mprog_count(target, 1);426 427	memset(prog_ids, 0, sizeof(prog_ids));428	optq.count = ARRAY_SIZE(prog_ids);429 430	err = bpf_prog_query_opts(loopback, target, &optq);431	if (!ASSERT_OK(err, "prog_query"))432		goto cleanup_target;433 434	ASSERT_EQ(optq.count, 1, "count");435	ASSERT_EQ(optq.revision, 8, "revision");436	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");437	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");438 439cleanup_target:440	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);441	ASSERT_OK(err, "prog_detach");442	assert_mprog_count(target, 0);443 444cleanup:445	test_tc_link__destroy(skel);446}447 448void serial_test_tc_opts_after(void)449{450	test_tc_opts_after_target(BPF_TCX_INGRESS);451	test_tc_opts_after_target(BPF_TCX_EGRESS);452}453 454static void test_tc_opts_revision_target(int target)455{456	LIBBPF_OPTS(bpf_prog_attach_opts, opta);457	LIBBPF_OPTS(bpf_prog_detach_opts, optd);458	LIBBPF_OPTS(bpf_prog_query_opts, optq);459	__u32 fd1, fd2, id1, id2;460	struct test_tc_link *skel;461	__u32 prog_ids[3];462	int err;463 464	skel = test_tc_link__open_and_load();465	if (!ASSERT_OK_PTR(skel, "skel_load"))466		goto cleanup;467 468	fd1 = bpf_program__fd(skel->progs.tc1);469	fd2 = bpf_program__fd(skel->progs.tc2);470 471	id1 = id_from_prog_fd(fd1);472	id2 = id_from_prog_fd(fd2);473 474	ASSERT_NEQ(id1, id2, "prog_ids_1_2");475 476	assert_mprog_count(target, 0);477 478	LIBBPF_OPTS_RESET(opta,479		.expected_revision = 1,480	);481 482	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);483	if (!ASSERT_EQ(err, 0, "prog_attach"))484		goto cleanup;485 486	assert_mprog_count(target, 1);487 488	LIBBPF_OPTS_RESET(opta,489		.expected_revision = 1,490	);491 492	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);493	if (!ASSERT_EQ(err, -ESTALE, "prog_attach"))494		goto cleanup_target;495 496	assert_mprog_count(target, 1);497 498	LIBBPF_OPTS_RESET(opta,499		.expected_revision = 2,500	);501 502	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);503	if (!ASSERT_EQ(err, 0, "prog_attach"))504		goto cleanup_target;505 506	assert_mprog_count(target, 2);507 508	optq.prog_ids = prog_ids;509 510	memset(prog_ids, 0, sizeof(prog_ids));511	optq.count = ARRAY_SIZE(prog_ids);512 513	err = bpf_prog_query_opts(loopback, target, &optq);514	if (!ASSERT_OK(err, "prog_query"))515		goto cleanup_target2;516 517	ASSERT_EQ(optq.count, 2, "count");518	ASSERT_EQ(optq.revision, 3, "revision");519	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");520	ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");521	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");522 523	tc_skel_reset_all_seen(skel);524	ASSERT_OK(system(ping_cmd), ping_cmd);525 526	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");527	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");528 529	LIBBPF_OPTS_RESET(optd,530		.expected_revision = 2,531	);532 533	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);534	ASSERT_EQ(err, -ESTALE, "prog_detach");535	assert_mprog_count(target, 2);536 537cleanup_target2:538	LIBBPF_OPTS_RESET(optd,539		.expected_revision = 3,540	);541 542	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);543	ASSERT_OK(err, "prog_detach");544	assert_mprog_count(target, 1);545 546cleanup_target:547	LIBBPF_OPTS_RESET(optd);548 549	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);550	ASSERT_OK(err, "prog_detach");551	assert_mprog_count(target, 0);552 553cleanup:554	test_tc_link__destroy(skel);555}556 557void serial_test_tc_opts_revision(void)558{559	test_tc_opts_revision_target(BPF_TCX_INGRESS);560	test_tc_opts_revision_target(BPF_TCX_EGRESS);561}562 563static void test_tc_chain_classic(int target, bool chain_tc_old)564{565	LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);566	LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);567	LIBBPF_OPTS(bpf_prog_attach_opts, opta);568	LIBBPF_OPTS(bpf_prog_detach_opts, optd);569	bool hook_created = false, tc_attached = false;570	__u32 fd1, fd2, fd3, id1, id2, id3;571	struct test_tc_link *skel;572	int err;573 574	skel = test_tc_link__open_and_load();575	if (!ASSERT_OK_PTR(skel, "skel_load"))576		goto cleanup;577 578	fd1 = bpf_program__fd(skel->progs.tc1);579	fd2 = bpf_program__fd(skel->progs.tc2);580	fd3 = bpf_program__fd(skel->progs.tc3);581 582	id1 = id_from_prog_fd(fd1);583	id2 = id_from_prog_fd(fd2);584	id3 = id_from_prog_fd(fd3);585 586	ASSERT_NEQ(id1, id2, "prog_ids_1_2");587	ASSERT_NEQ(id2, id3, "prog_ids_2_3");588 589	assert_mprog_count(target, 0);590 591	if (chain_tc_old) {592		tc_hook.attach_point = target == BPF_TCX_INGRESS ?593				       BPF_TC_INGRESS : BPF_TC_EGRESS;594		err = bpf_tc_hook_create(&tc_hook);595		if (err == 0)596			hook_created = true;597		err = err == -EEXIST ? 0 : err;598		if (!ASSERT_OK(err, "bpf_tc_hook_create"))599			goto cleanup;600 601		tc_opts.prog_fd = fd3;602		err = bpf_tc_attach(&tc_hook, &tc_opts);603		if (!ASSERT_OK(err, "bpf_tc_attach"))604			goto cleanup;605		tc_attached = true;606	}607 608	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);609	if (!ASSERT_EQ(err, 0, "prog_attach"))610		goto cleanup;611 612	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);613	if (!ASSERT_EQ(err, 0, "prog_attach"))614		goto cleanup_detach;615 616	assert_mprog_count(target, 2);617 618	tc_skel_reset_all_seen(skel);619	ASSERT_OK(system(ping_cmd), ping_cmd);620 621	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");622	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");623	ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");624 625	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);626	if (!ASSERT_OK(err, "prog_detach"))627		goto cleanup_detach;628 629	assert_mprog_count(target, 1);630 631	tc_skel_reset_all_seen(skel);632	ASSERT_OK(system(ping_cmd), ping_cmd);633 634	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");635	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");636	ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");637 638cleanup_detach:639	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);640	if (!ASSERT_OK(err, "prog_detach"))641		goto cleanup;642 643	assert_mprog_count(target, 0);644cleanup:645	if (tc_attached) {646		tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;647		err = bpf_tc_detach(&tc_hook, &tc_opts);648		ASSERT_OK(err, "bpf_tc_detach");649	}650	if (hook_created) {651		tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;652		bpf_tc_hook_destroy(&tc_hook);653	}654	test_tc_link__destroy(skel);655	assert_mprog_count(target, 0);656}657 658void serial_test_tc_opts_chain_classic(void)659{660	test_tc_chain_classic(BPF_TCX_INGRESS, false);661	test_tc_chain_classic(BPF_TCX_EGRESS, false);662	test_tc_chain_classic(BPF_TCX_INGRESS, true);663	test_tc_chain_classic(BPF_TCX_EGRESS, true);664}665 666static void test_tc_opts_replace_target(int target)667{668	LIBBPF_OPTS(bpf_prog_attach_opts, opta);669	LIBBPF_OPTS(bpf_prog_detach_opts, optd);670	LIBBPF_OPTS(bpf_prog_query_opts, optq);671	__u32 fd1, fd2, fd3, id1, id2, id3, detach_fd;672	__u32 prog_ids[4], prog_flags[4];673	struct test_tc_link *skel;674	int err;675 676	skel = test_tc_link__open_and_load();677	if (!ASSERT_OK_PTR(skel, "skel_load"))678		goto cleanup;679 680	fd1 = bpf_program__fd(skel->progs.tc1);681	fd2 = bpf_program__fd(skel->progs.tc2);682	fd3 = bpf_program__fd(skel->progs.tc3);683 684	id1 = id_from_prog_fd(fd1);685	id2 = id_from_prog_fd(fd2);686	id3 = id_from_prog_fd(fd3);687 688	ASSERT_NEQ(id1, id2, "prog_ids_1_2");689	ASSERT_NEQ(id2, id3, "prog_ids_2_3");690 691	assert_mprog_count(target, 0);692 693	LIBBPF_OPTS_RESET(opta,694		.expected_revision = 1,695	);696 697	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);698	if (!ASSERT_EQ(err, 0, "prog_attach"))699		goto cleanup;700 701	assert_mprog_count(target, 1);702 703	LIBBPF_OPTS_RESET(opta,704		.flags = BPF_F_BEFORE,705		.relative_id = id1,706		.expected_revision = 2,707	);708 709	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);710	if (!ASSERT_EQ(err, 0, "prog_attach"))711		goto cleanup_target;712 713	detach_fd = fd2;714 715	assert_mprog_count(target, 2);716 717	optq.prog_attach_flags = prog_flags;718	optq.prog_ids = prog_ids;719 720	memset(prog_flags, 0, sizeof(prog_flags));721	memset(prog_ids, 0, sizeof(prog_ids));722	optq.count = ARRAY_SIZE(prog_ids);723 724	err = bpf_prog_query_opts(loopback, target, &optq);725	if (!ASSERT_OK(err, "prog_query"))726		goto cleanup_target2;727 728	ASSERT_EQ(optq.count, 2, "count");729	ASSERT_EQ(optq.revision, 3, "revision");730	ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");731	ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");732	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");733 734	ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]");735	ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");736	ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");737 738	tc_skel_reset_all_seen(skel);739	ASSERT_OK(system(ping_cmd), ping_cmd);740 741	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");742	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");743	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");744 745	LIBBPF_OPTS_RESET(opta,746		.flags = BPF_F_REPLACE,747		.replace_prog_fd = fd2,748		.expected_revision = 3,749	);750 751	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);752	if (!ASSERT_EQ(err, 0, "prog_attach"))753		goto cleanup_target2;754 755	detach_fd = fd3;756 757	assert_mprog_count(target, 2);758 759	memset(prog_ids, 0, sizeof(prog_ids));760	optq.count = ARRAY_SIZE(prog_ids);761 762	err = bpf_prog_query_opts(loopback, target, &optq);763	if (!ASSERT_OK(err, "prog_query"))764		goto cleanup_target2;765 766	ASSERT_EQ(optq.count, 2, "count");767	ASSERT_EQ(optq.revision, 4, "revision");768	ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]");769	ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");770	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");771 772	tc_skel_reset_all_seen(skel);773	ASSERT_OK(system(ping_cmd), ping_cmd);774 775	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");776	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");777	ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");778 779	LIBBPF_OPTS_RESET(opta,780		.flags = BPF_F_REPLACE | BPF_F_BEFORE,781		.replace_prog_fd = fd3,782		.relative_fd = fd1,783		.expected_revision = 4,784	);785 786	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);787	if (!ASSERT_EQ(err, 0, "prog_attach"))788		goto cleanup_target2;789 790	detach_fd = fd2;791 792	assert_mprog_count(target, 2);793 794	memset(prog_ids, 0, sizeof(prog_ids));795	optq.count = ARRAY_SIZE(prog_ids);796 797	err = bpf_prog_query_opts(loopback, target, &optq);798	if (!ASSERT_OK(err, "prog_query"))799		goto cleanup_target2;800 801	ASSERT_EQ(optq.count, 2, "count");802	ASSERT_EQ(optq.revision, 5, "revision");803	ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");804	ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");805	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");806 807	tc_skel_reset_all_seen(skel);808	ASSERT_OK(system(ping_cmd), ping_cmd);809 810	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");811	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");812	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");813 814	LIBBPF_OPTS_RESET(opta,815		.flags = BPF_F_REPLACE,816		.replace_prog_fd = fd2,817	);818 819	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);820	ASSERT_EQ(err, -EEXIST, "prog_attach");821	assert_mprog_count(target, 2);822 823	LIBBPF_OPTS_RESET(opta,824		.flags = BPF_F_REPLACE | BPF_F_AFTER,825		.replace_prog_fd = fd2,826		.relative_fd = fd1,827		.expected_revision = 5,828	);829 830	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);831	ASSERT_EQ(err, -ERANGE, "prog_attach");832	assert_mprog_count(target, 2);833 834	LIBBPF_OPTS_RESET(opta,835		.flags = BPF_F_BEFORE | BPF_F_AFTER | BPF_F_REPLACE,836		.replace_prog_fd = fd2,837		.relative_fd = fd1,838		.expected_revision = 5,839	);840 841	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);842	ASSERT_EQ(err, -ERANGE, "prog_attach");843	assert_mprog_count(target, 2);844 845	LIBBPF_OPTS_RESET(optd,846		.flags = BPF_F_BEFORE,847		.relative_id = id1,848		.expected_revision = 5,849	);850 851cleanup_target2:852	err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);853	ASSERT_OK(err, "prog_detach");854	assert_mprog_count(target, 1);855 856cleanup_target:857	LIBBPF_OPTS_RESET(optd);858 859	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);860	ASSERT_OK(err, "prog_detach");861	assert_mprog_count(target, 0);862 863cleanup:864	test_tc_link__destroy(skel);865}866 867void serial_test_tc_opts_replace(void)868{869	test_tc_opts_replace_target(BPF_TCX_INGRESS);870	test_tc_opts_replace_target(BPF_TCX_EGRESS);871}872 873static void test_tc_opts_invalid_target(int target)874{875	LIBBPF_OPTS(bpf_prog_attach_opts, opta);876	LIBBPF_OPTS(bpf_prog_detach_opts, optd);877	__u32 fd1, fd2, id1, id2;878	struct test_tc_link *skel;879	int err;880 881	skel = test_tc_link__open_and_load();882	if (!ASSERT_OK_PTR(skel, "skel_load"))883		goto cleanup;884 885	fd1 = bpf_program__fd(skel->progs.tc1);886	fd2 = bpf_program__fd(skel->progs.tc2);887 888	id1 = id_from_prog_fd(fd1);889	id2 = id_from_prog_fd(fd2);890 891	ASSERT_NEQ(id1, id2, "prog_ids_1_2");892 893	assert_mprog_count(target, 0);894 895	LIBBPF_OPTS_RESET(opta,896		.flags = BPF_F_BEFORE | BPF_F_AFTER,897	);898 899	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);900	ASSERT_EQ(err, -ERANGE, "prog_attach");901	assert_mprog_count(target, 0);902 903	LIBBPF_OPTS_RESET(opta,904		.flags = BPF_F_BEFORE | BPF_F_ID,905	);906 907	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);908	ASSERT_EQ(err, -ENOENT, "prog_attach");909	assert_mprog_count(target, 0);910 911	LIBBPF_OPTS_RESET(opta,912		.flags = BPF_F_AFTER | BPF_F_ID,913	);914 915	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);916	ASSERT_EQ(err, -ENOENT, "prog_attach");917	assert_mprog_count(target, 0);918 919	LIBBPF_OPTS_RESET(opta,920		.relative_fd = fd2,921	);922 923	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);924	ASSERT_EQ(err, -EINVAL, "prog_attach");925	assert_mprog_count(target, 0);926 927	LIBBPF_OPTS_RESET(opta,928		.flags = BPF_F_BEFORE | BPF_F_AFTER,929		.relative_fd = fd2,930	);931 932	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);933	ASSERT_EQ(err, -ENOENT, "prog_attach");934	assert_mprog_count(target, 0);935 936	LIBBPF_OPTS_RESET(opta,937		.flags = BPF_F_ID,938		.relative_id = id2,939	);940 941	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);942	ASSERT_EQ(err, -EINVAL, "prog_attach");943	assert_mprog_count(target, 0);944 945	LIBBPF_OPTS_RESET(opta,946		.flags = BPF_F_BEFORE,947		.relative_fd = fd1,948	);949 950	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);951	ASSERT_EQ(err, -ENOENT, "prog_attach");952	assert_mprog_count(target, 0);953 954	LIBBPF_OPTS_RESET(opta,955		.flags = BPF_F_AFTER,956		.relative_fd = fd1,957	);958 959	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);960	ASSERT_EQ(err, -ENOENT, "prog_attach");961	assert_mprog_count(target, 0);962 963	LIBBPF_OPTS_RESET(opta);964 965	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);966	if (!ASSERT_EQ(err, 0, "prog_attach"))967		goto cleanup;968 969	assert_mprog_count(target, 1);970 971	LIBBPF_OPTS_RESET(opta);972 973	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);974	ASSERT_EQ(err, -EEXIST, "prog_attach");975	assert_mprog_count(target, 1);976 977	LIBBPF_OPTS_RESET(opta,978		.flags = BPF_F_BEFORE,979		.relative_fd = fd1,980	);981 982	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);983	ASSERT_EQ(err, -EEXIST, "prog_attach");984	assert_mprog_count(target, 1);985 986	LIBBPF_OPTS_RESET(opta,987		.flags = BPF_F_AFTER,988		.relative_fd = fd1,989	);990 991	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);992	ASSERT_EQ(err, -EEXIST, "prog_attach");993	assert_mprog_count(target, 1);994 995	LIBBPF_OPTS_RESET(opta,996		.flags = BPF_F_REPLACE,997		.relative_fd = fd1,998	);999 1000	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1001	ASSERT_EQ(err, -EINVAL, "prog_attach_x1");1002	assert_mprog_count(target, 1);1003 1004	LIBBPF_OPTS_RESET(opta,1005		.flags = BPF_F_REPLACE,1006		.replace_prog_fd = fd1,1007	);1008 1009	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1010	ASSERT_EQ(err, -EEXIST, "prog_attach");1011	assert_mprog_count(target, 1);1012 1013	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1014	ASSERT_OK(err, "prog_detach");1015	assert_mprog_count(target, 0);1016cleanup:1017	test_tc_link__destroy(skel);1018}1019 1020void serial_test_tc_opts_invalid(void)1021{1022	test_tc_opts_invalid_target(BPF_TCX_INGRESS);1023	test_tc_opts_invalid_target(BPF_TCX_EGRESS);1024}1025 1026static void test_tc_opts_prepend_target(int target)1027{1028	LIBBPF_OPTS(bpf_prog_attach_opts, opta);1029	LIBBPF_OPTS(bpf_prog_detach_opts, optd);1030	LIBBPF_OPTS(bpf_prog_query_opts, optq);1031	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;1032	struct test_tc_link *skel;1033	__u32 prog_ids[5];1034	int err;1035 1036	skel = test_tc_link__open_and_load();1037	if (!ASSERT_OK_PTR(skel, "skel_load"))1038		goto cleanup;1039 1040	fd1 = bpf_program__fd(skel->progs.tc1);1041	fd2 = bpf_program__fd(skel->progs.tc2);1042	fd3 = bpf_program__fd(skel->progs.tc3);1043	fd4 = bpf_program__fd(skel->progs.tc4);1044 1045	id1 = id_from_prog_fd(fd1);1046	id2 = id_from_prog_fd(fd2);1047	id3 = id_from_prog_fd(fd3);1048	id4 = id_from_prog_fd(fd4);1049 1050	ASSERT_NEQ(id1, id2, "prog_ids_1_2");1051	ASSERT_NEQ(id3, id4, "prog_ids_3_4");1052	ASSERT_NEQ(id2, id3, "prog_ids_2_3");1053 1054	assert_mprog_count(target, 0);1055 1056	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1057	if (!ASSERT_EQ(err, 0, "prog_attach"))1058		goto cleanup;1059 1060	assert_mprog_count(target, 1);1061 1062	LIBBPF_OPTS_RESET(opta,1063		.flags = BPF_F_BEFORE,1064	);1065 1066	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);1067	if (!ASSERT_EQ(err, 0, "prog_attach"))1068		goto cleanup_target;1069 1070	assert_mprog_count(target, 2);1071 1072	optq.prog_ids = prog_ids;1073 1074	memset(prog_ids, 0, sizeof(prog_ids));1075	optq.count = ARRAY_SIZE(prog_ids);1076 1077	err = bpf_prog_query_opts(loopback, target, &optq);1078	if (!ASSERT_OK(err, "prog_query"))1079		goto cleanup_target2;1080 1081	ASSERT_EQ(optq.count, 2, "count");1082	ASSERT_EQ(optq.revision, 3, "revision");1083	ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");1084	ASSERT_EQ(optq.prog_ids[1], id1, "prog_ids[1]");1085	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1086 1087	tc_skel_reset_all_seen(skel);1088	ASSERT_OK(system(ping_cmd), ping_cmd);1089 1090	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1091	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1092	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");1093	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1094 1095	LIBBPF_OPTS_RESET(opta,1096		.flags = BPF_F_BEFORE,1097	);1098 1099	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);1100	if (!ASSERT_EQ(err, 0, "prog_attach"))1101		goto cleanup_target2;1102 1103	LIBBPF_OPTS_RESET(opta,1104		.flags = BPF_F_BEFORE,1105	);1106 1107	err = bpf_prog_attach_opts(fd4, loopback, target, &opta);1108	if (!ASSERT_EQ(err, 0, "prog_attach"))1109		goto cleanup_target3;1110 1111	assert_mprog_count(target, 4);1112 1113	memset(prog_ids, 0, sizeof(prog_ids));1114	optq.count = ARRAY_SIZE(prog_ids);1115 1116	err = bpf_prog_query_opts(loopback, target, &optq);1117	if (!ASSERT_OK(err, "prog_query"))1118		goto cleanup_target4;1119 1120	ASSERT_EQ(optq.count, 4, "count");1121	ASSERT_EQ(optq.revision, 5, "revision");1122	ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");1123	ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");1124	ASSERT_EQ(optq.prog_ids[2], id2, "prog_ids[2]");1125	ASSERT_EQ(optq.prog_ids[3], id1, "prog_ids[3]");1126	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1127 1128	tc_skel_reset_all_seen(skel);1129	ASSERT_OK(system(ping_cmd), ping_cmd);1130 1131	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1132	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1133	ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");1134	ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");1135 1136cleanup_target4:1137	err = bpf_prog_detach_opts(fd4, loopback, target, &optd);1138	ASSERT_OK(err, "prog_detach");1139	assert_mprog_count(target, 3);1140 1141cleanup_target3:1142	err = bpf_prog_detach_opts(fd3, loopback, target, &optd);1143	ASSERT_OK(err, "prog_detach");1144	assert_mprog_count(target, 2);1145 1146cleanup_target2:1147	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1148	ASSERT_OK(err, "prog_detach");1149	assert_mprog_count(target, 1);1150 1151cleanup_target:1152	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1153	ASSERT_OK(err, "prog_detach");1154	assert_mprog_count(target, 0);1155 1156cleanup:1157	test_tc_link__destroy(skel);1158}1159 1160void serial_test_tc_opts_prepend(void)1161{1162	test_tc_opts_prepend_target(BPF_TCX_INGRESS);1163	test_tc_opts_prepend_target(BPF_TCX_EGRESS);1164}1165 1166static void test_tc_opts_append_target(int target)1167{1168	LIBBPF_OPTS(bpf_prog_attach_opts, opta);1169	LIBBPF_OPTS(bpf_prog_detach_opts, optd);1170	LIBBPF_OPTS(bpf_prog_query_opts, optq);1171	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;1172	struct test_tc_link *skel;1173	__u32 prog_ids[5];1174	int err;1175 1176	skel = test_tc_link__open_and_load();1177	if (!ASSERT_OK_PTR(skel, "skel_load"))1178		goto cleanup;1179 1180	fd1 = bpf_program__fd(skel->progs.tc1);1181	fd2 = bpf_program__fd(skel->progs.tc2);1182	fd3 = bpf_program__fd(skel->progs.tc3);1183	fd4 = bpf_program__fd(skel->progs.tc4);1184 1185	id1 = id_from_prog_fd(fd1);1186	id2 = id_from_prog_fd(fd2);1187	id3 = id_from_prog_fd(fd3);1188	id4 = id_from_prog_fd(fd4);1189 1190	ASSERT_NEQ(id1, id2, "prog_ids_1_2");1191	ASSERT_NEQ(id3, id4, "prog_ids_3_4");1192	ASSERT_NEQ(id2, id3, "prog_ids_2_3");1193 1194	assert_mprog_count(target, 0);1195 1196	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1197	if (!ASSERT_EQ(err, 0, "prog_attach"))1198		goto cleanup;1199 1200	assert_mprog_count(target, 1);1201 1202	LIBBPF_OPTS_RESET(opta,1203		.flags = BPF_F_AFTER,1204	);1205 1206	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);1207	if (!ASSERT_EQ(err, 0, "prog_attach"))1208		goto cleanup_target;1209 1210	assert_mprog_count(target, 2);1211 1212	optq.prog_ids = prog_ids;1213 1214	memset(prog_ids, 0, sizeof(prog_ids));1215	optq.count = ARRAY_SIZE(prog_ids);1216 1217	err = bpf_prog_query_opts(loopback, target, &optq);1218	if (!ASSERT_OK(err, "prog_query"))1219		goto cleanup_target2;1220 1221	ASSERT_EQ(optq.count, 2, "count");1222	ASSERT_EQ(optq.revision, 3, "revision");1223	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");1224	ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");1225	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1226 1227	tc_skel_reset_all_seen(skel);1228	ASSERT_OK(system(ping_cmd), ping_cmd);1229 1230	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1231	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1232	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");1233	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1234 1235	LIBBPF_OPTS_RESET(opta,1236		.flags = BPF_F_AFTER,1237	);1238 1239	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);1240	if (!ASSERT_EQ(err, 0, "prog_attach"))1241		goto cleanup_target2;1242 1243	LIBBPF_OPTS_RESET(opta,1244		.flags = BPF_F_AFTER,1245	);1246 1247	err = bpf_prog_attach_opts(fd4, loopback, target, &opta);1248	if (!ASSERT_EQ(err, 0, "prog_attach"))1249		goto cleanup_target3;1250 1251	assert_mprog_count(target, 4);1252 1253	memset(prog_ids, 0, sizeof(prog_ids));1254	optq.count = ARRAY_SIZE(prog_ids);1255 1256	err = bpf_prog_query_opts(loopback, target, &optq);1257	if (!ASSERT_OK(err, "prog_query"))1258		goto cleanup_target4;1259 1260	ASSERT_EQ(optq.count, 4, "count");1261	ASSERT_EQ(optq.revision, 5, "revision");1262	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");1263	ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");1264	ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");1265	ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");1266	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1267 1268	tc_skel_reset_all_seen(skel);1269	ASSERT_OK(system(ping_cmd), ping_cmd);1270 1271	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1272	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1273	ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");1274	ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");1275 1276cleanup_target4:1277	err = bpf_prog_detach_opts(fd4, loopback, target, &optd);1278	ASSERT_OK(err, "prog_detach");1279	assert_mprog_count(target, 3);1280 1281cleanup_target3:1282	err = bpf_prog_detach_opts(fd3, loopback, target, &optd);1283	ASSERT_OK(err, "prog_detach");1284	assert_mprog_count(target, 2);1285 1286cleanup_target2:1287	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1288	ASSERT_OK(err, "prog_detach");1289	assert_mprog_count(target, 1);1290 1291cleanup_target:1292	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1293	ASSERT_OK(err, "prog_detach");1294	assert_mprog_count(target, 0);1295 1296cleanup:1297	test_tc_link__destroy(skel);1298}1299 1300void serial_test_tc_opts_append(void)1301{1302	test_tc_opts_append_target(BPF_TCX_INGRESS);1303	test_tc_opts_append_target(BPF_TCX_EGRESS);1304}1305 1306static void test_tc_opts_dev_cleanup_target(int target)1307{1308	LIBBPF_OPTS(bpf_prog_attach_opts, opta);1309	LIBBPF_OPTS(bpf_prog_detach_opts, optd);1310	LIBBPF_OPTS(bpf_prog_query_opts, optq);1311	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;1312	struct test_tc_link *skel;1313	int err, ifindex;1314 1315	ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");1316	ifindex = if_nametoindex("tcx_opts1");1317	ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");1318 1319	skel = test_tc_link__open_and_load();1320	if (!ASSERT_OK_PTR(skel, "skel_load"))1321		goto cleanup;1322 1323	fd1 = bpf_program__fd(skel->progs.tc1);1324	fd2 = bpf_program__fd(skel->progs.tc2);1325	fd3 = bpf_program__fd(skel->progs.tc3);1326	fd4 = bpf_program__fd(skel->progs.tc4);1327 1328	id1 = id_from_prog_fd(fd1);1329	id2 = id_from_prog_fd(fd2);1330	id3 = id_from_prog_fd(fd3);1331	id4 = id_from_prog_fd(fd4);1332 1333	ASSERT_NEQ(id1, id2, "prog_ids_1_2");1334	ASSERT_NEQ(id3, id4, "prog_ids_3_4");1335	ASSERT_NEQ(id2, id3, "prog_ids_2_3");1336 1337	assert_mprog_count_ifindex(ifindex, target, 0);1338 1339	err = bpf_prog_attach_opts(fd1, ifindex, target, &opta);1340	if (!ASSERT_EQ(err, 0, "prog_attach"))1341		goto cleanup;1342 1343	assert_mprog_count_ifindex(ifindex, target, 1);1344 1345	err = bpf_prog_attach_opts(fd2, ifindex, target, &opta);1346	if (!ASSERT_EQ(err, 0, "prog_attach"))1347		goto cleanup1;1348 1349	assert_mprog_count_ifindex(ifindex, target, 2);1350 1351	err = bpf_prog_attach_opts(fd3, ifindex, target, &opta);1352	if (!ASSERT_EQ(err, 0, "prog_attach"))1353		goto cleanup2;1354 1355	assert_mprog_count_ifindex(ifindex, target, 3);1356 1357	err = bpf_prog_attach_opts(fd4, ifindex, target, &opta);1358	if (!ASSERT_EQ(err, 0, "prog_attach"))1359		goto cleanup3;1360 1361	assert_mprog_count_ifindex(ifindex, target, 4);1362 1363	ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1364	ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1365	ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1366	return;1367cleanup3:1368	err = bpf_prog_detach_opts(fd3, loopback, target, &optd);1369	ASSERT_OK(err, "prog_detach");1370 1371	assert_mprog_count_ifindex(ifindex, target, 2);1372cleanup2:1373	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1374	ASSERT_OK(err, "prog_detach");1375 1376	assert_mprog_count_ifindex(ifindex, target, 1);1377cleanup1:1378	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1379	ASSERT_OK(err, "prog_detach");1380 1381	assert_mprog_count_ifindex(ifindex, target, 0);1382cleanup:1383	test_tc_link__destroy(skel);1384 1385	ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1386	ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1387	ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1388}1389 1390void serial_test_tc_opts_dev_cleanup(void)1391{1392	test_tc_opts_dev_cleanup_target(BPF_TCX_INGRESS);1393	test_tc_opts_dev_cleanup_target(BPF_TCX_EGRESS);1394}1395 1396static void test_tc_opts_mixed_target(int target)1397{1398	LIBBPF_OPTS(bpf_prog_attach_opts, opta);1399	LIBBPF_OPTS(bpf_prog_detach_opts, optd);1400	LIBBPF_OPTS(bpf_prog_query_opts, optq);1401	LIBBPF_OPTS(bpf_tcx_opts, optl);1402	__u32 pid1, pid2, pid3, pid4, lid2, lid4;1403	__u32 prog_flags[4], link_flags[4];1404	__u32 prog_ids[4], link_ids[4];1405	struct test_tc_link *skel;1406	struct bpf_link *link;1407	int err, detach_fd;1408 1409	skel = test_tc_link__open();1410	if (!ASSERT_OK_PTR(skel, "skel_open"))1411		goto cleanup;1412 1413	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1414		  0, "tc1_attach_type");1415	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1416		  0, "tc2_attach_type");1417	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),1418		  0, "tc3_attach_type");1419	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1420		  0, "tc4_attach_type");1421 1422	err = test_tc_link__load(skel);1423	if (!ASSERT_OK(err, "skel_load"))1424		goto cleanup;1425 1426	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1427	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1428	pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1429	pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1430 1431	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1432	ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");1433	ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1434 1435	assert_mprog_count(target, 0);1436 1437	err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),1438				   loopback, target, &opta);1439	if (!ASSERT_EQ(err, 0, "prog_attach"))1440		goto cleanup;1441 1442	detach_fd = bpf_program__fd(skel->progs.tc1);1443 1444	assert_mprog_count(target, 1);1445 1446	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1447	if (!ASSERT_OK_PTR(link, "link_attach"))1448		goto cleanup1;1449	skel->links.tc2 = link;1450 1451	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));1452 1453	assert_mprog_count(target, 2);1454 1455	LIBBPF_OPTS_RESET(opta,1456		.flags = BPF_F_REPLACE,1457		.replace_prog_fd = bpf_program__fd(skel->progs.tc1),1458	);1459 1460	err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2),1461				   loopback, target, &opta);1462	ASSERT_EQ(err, -EEXIST, "prog_attach");1463 1464	assert_mprog_count(target, 2);1465 1466	LIBBPF_OPTS_RESET(opta,1467		.flags = BPF_F_REPLACE,1468		.replace_prog_fd = bpf_program__fd(skel->progs.tc2),1469	);1470 1471	err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),1472				   loopback, target, &opta);1473	ASSERT_EQ(err, -EEXIST, "prog_attach");1474 1475	assert_mprog_count(target, 2);1476 1477	LIBBPF_OPTS_RESET(opta,1478		.flags = BPF_F_REPLACE,1479		.replace_prog_fd = bpf_program__fd(skel->progs.tc2),1480	);1481 1482	err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3),1483				   loopback, target, &opta);1484	ASSERT_EQ(err, -EBUSY, "prog_attach");1485 1486	assert_mprog_count(target, 2);1487 1488	LIBBPF_OPTS_RESET(opta,1489		.flags = BPF_F_REPLACE,1490		.replace_prog_fd = bpf_program__fd(skel->progs.tc1),1491	);1492 1493	err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc3),1494				   loopback, target, &opta);1495	if (!ASSERT_EQ(err, 0, "prog_attach"))1496		goto cleanup1;1497 1498	detach_fd = bpf_program__fd(skel->progs.tc3);1499 1500	assert_mprog_count(target, 2);1501 1502	link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);1503	if (!ASSERT_OK_PTR(link, "link_attach"))1504		goto cleanup1;1505	skel->links.tc4 = link;1506 1507	lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));1508 1509	assert_mprog_count(target, 3);1510 1511	LIBBPF_OPTS_RESET(opta,1512		.flags = BPF_F_REPLACE,1513		.replace_prog_fd = bpf_program__fd(skel->progs.tc4),1514	);1515 1516	err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc2),1517				   loopback, target, &opta);1518	ASSERT_EQ(err, -EEXIST, "prog_attach");1519 1520	optq.prog_ids = prog_ids;1521	optq.prog_attach_flags = prog_flags;1522	optq.link_ids = link_ids;1523	optq.link_attach_flags = link_flags;1524 1525	memset(prog_ids, 0, sizeof(prog_ids));1526	memset(prog_flags, 0, sizeof(prog_flags));1527	memset(link_ids, 0, sizeof(link_ids));1528	memset(link_flags, 0, sizeof(link_flags));1529	optq.count = ARRAY_SIZE(prog_ids);1530 1531	err = bpf_prog_query_opts(loopback, target, &optq);1532	if (!ASSERT_OK(err, "prog_query"))1533		goto cleanup1;1534 1535	ASSERT_EQ(optq.count, 3, "count");1536	ASSERT_EQ(optq.revision, 5, "revision");1537	ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]");1538	ASSERT_EQ(optq.prog_attach_flags[0], 0, "prog_flags[0]");1539	ASSERT_EQ(optq.link_ids[0], 0, "link_ids[0]");1540	ASSERT_EQ(optq.link_attach_flags[0], 0, "link_flags[0]");1541	ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");1542	ASSERT_EQ(optq.prog_attach_flags[1], 0, "prog_flags[1]");1543	ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");1544	ASSERT_EQ(optq.link_attach_flags[1], 0, "link_flags[1]");1545	ASSERT_EQ(optq.prog_ids[2], pid4, "prog_ids[2]");1546	ASSERT_EQ(optq.prog_attach_flags[2], 0, "prog_flags[2]");1547	ASSERT_EQ(optq.link_ids[2], lid4, "link_ids[2]");1548	ASSERT_EQ(optq.link_attach_flags[2], 0, "link_flags[2]");1549	ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");1550	ASSERT_EQ(optq.prog_attach_flags[3], 0, "prog_flags[3]");1551	ASSERT_EQ(optq.link_ids[3], 0, "link_ids[3]");1552	ASSERT_EQ(optq.link_attach_flags[3], 0, "link_flags[3]");1553 1554	ASSERT_OK(system(ping_cmd), ping_cmd);1555 1556cleanup1:1557	err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);1558	ASSERT_OK(err, "prog_detach");1559	assert_mprog_count(target, 2);1560 1561cleanup:1562	test_tc_link__destroy(skel);1563	assert_mprog_count(target, 0);1564}1565 1566void serial_test_tc_opts_mixed(void)1567{1568	test_tc_opts_mixed_target(BPF_TCX_INGRESS);1569	test_tc_opts_mixed_target(BPF_TCX_EGRESS);1570}1571 1572static void test_tc_opts_demixed_target(int target)1573{1574	LIBBPF_OPTS(bpf_prog_attach_opts, opta);1575	LIBBPF_OPTS(bpf_prog_detach_opts, optd);1576	LIBBPF_OPTS(bpf_tcx_opts, optl);1577	struct test_tc_link *skel;1578	struct bpf_link *link;1579	__u32 pid1, pid2;1580	int err;1581 1582	skel = test_tc_link__open();1583	if (!ASSERT_OK_PTR(skel, "skel_open"))1584		goto cleanup;1585 1586	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1587		  0, "tc1_attach_type");1588	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1589		  0, "tc2_attach_type");1590 1591	err = test_tc_link__load(skel);1592	if (!ASSERT_OK(err, "skel_load"))1593		goto cleanup;1594 1595	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1596	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1597	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1598 1599	assert_mprog_count(target, 0);1600 1601	err = bpf_prog_attach_opts(bpf_program__fd(skel->progs.tc1),1602				   loopback, target, &opta);1603	if (!ASSERT_EQ(err, 0, "prog_attach"))1604		goto cleanup;1605 1606	assert_mprog_count(target, 1);1607 1608	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1609	if (!ASSERT_OK_PTR(link, "link_attach"))1610		goto cleanup1;1611	skel->links.tc2 = link;1612 1613	assert_mprog_count(target, 2);1614 1615	LIBBPF_OPTS_RESET(optd,1616		.flags = BPF_F_AFTER,1617	);1618 1619	err = bpf_prog_detach_opts(0, loopback, target, &optd);1620	ASSERT_EQ(err, -EBUSY, "prog_detach");1621 1622	assert_mprog_count(target, 2);1623 1624	LIBBPF_OPTS_RESET(optd,1625		.flags = BPF_F_BEFORE,1626	);1627 1628	err = bpf_prog_detach_opts(0, loopback, target, &optd);1629	ASSERT_OK(err, "prog_detach");1630 1631	assert_mprog_count(target, 1);1632	goto cleanup;1633 1634cleanup1:1635	err = bpf_prog_detach_opts(bpf_program__fd(skel->progs.tc1),1636				   loopback, target, &optd);1637	ASSERT_OK(err, "prog_detach");1638	assert_mprog_count(target, 2);1639 1640cleanup:1641	test_tc_link__destroy(skel);1642	assert_mprog_count(target, 0);1643}1644 1645void serial_test_tc_opts_demixed(void)1646{1647	test_tc_opts_demixed_target(BPF_TCX_INGRESS);1648	test_tc_opts_demixed_target(BPF_TCX_EGRESS);1649}1650 1651static void test_tc_opts_detach_target(int target)1652{1653	LIBBPF_OPTS(bpf_prog_attach_opts, opta);1654	LIBBPF_OPTS(bpf_prog_detach_opts, optd);1655	LIBBPF_OPTS(bpf_prog_query_opts, optq);1656	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;1657	struct test_tc_link *skel;1658	__u32 prog_ids[5];1659	int err;1660 1661	skel = test_tc_link__open_and_load();1662	if (!ASSERT_OK_PTR(skel, "skel_load"))1663		goto cleanup;1664 1665	fd1 = bpf_program__fd(skel->progs.tc1);1666	fd2 = bpf_program__fd(skel->progs.tc2);1667	fd3 = bpf_program__fd(skel->progs.tc3);1668	fd4 = bpf_program__fd(skel->progs.tc4);1669 1670	id1 = id_from_prog_fd(fd1);1671	id2 = id_from_prog_fd(fd2);1672	id3 = id_from_prog_fd(fd3);1673	id4 = id_from_prog_fd(fd4);1674 1675	ASSERT_NEQ(id1, id2, "prog_ids_1_2");1676	ASSERT_NEQ(id3, id4, "prog_ids_3_4");1677	ASSERT_NEQ(id2, id3, "prog_ids_2_3");1678 1679	assert_mprog_count(target, 0);1680 1681	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1682	if (!ASSERT_EQ(err, 0, "prog_attach"))1683		goto cleanup;1684 1685	assert_mprog_count(target, 1);1686 1687	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);1688	if (!ASSERT_EQ(err, 0, "prog_attach"))1689		goto cleanup1;1690 1691	assert_mprog_count(target, 2);1692 1693	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);1694	if (!ASSERT_EQ(err, 0, "prog_attach"))1695		goto cleanup2;1696 1697	assert_mprog_count(target, 3);1698 1699	err = bpf_prog_attach_opts(fd4, loopback, target, &opta);1700	if (!ASSERT_EQ(err, 0, "prog_attach"))1701		goto cleanup3;1702 1703	assert_mprog_count(target, 4);1704 1705	optq.prog_ids = prog_ids;1706 1707	memset(prog_ids, 0, sizeof(prog_ids));1708	optq.count = ARRAY_SIZE(prog_ids);1709 1710	err = bpf_prog_query_opts(loopback, target, &optq);1711	if (!ASSERT_OK(err, "prog_query"))1712		goto cleanup4;1713 1714	ASSERT_EQ(optq.count, 4, "count");1715	ASSERT_EQ(optq.revision, 5, "revision");1716	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");1717	ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");1718	ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");1719	ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");1720	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1721 1722	LIBBPF_OPTS_RESET(optd,1723		.flags = BPF_F_BEFORE,1724	);1725 1726	err = bpf_prog_detach_opts(0, loopback, target, &optd);1727	ASSERT_OK(err, "prog_detach");1728 1729	assert_mprog_count(target, 3);1730 1731	memset(prog_ids, 0, sizeof(prog_ids));1732	optq.count = ARRAY_SIZE(prog_ids);1733 1734	err = bpf_prog_query_opts(loopback, target, &optq);1735	if (!ASSERT_OK(err, "prog_query"))1736		goto cleanup4;1737 1738	ASSERT_EQ(optq.count, 3, "count");1739	ASSERT_EQ(optq.revision, 6, "revision");1740	ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");1741	ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");1742	ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");1743	ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");1744 1745	LIBBPF_OPTS_RESET(optd,1746		.flags = BPF_F_AFTER,1747	);1748 1749	err = bpf_prog_detach_opts(0, loopback, target, &optd);1750	ASSERT_OK(err, "prog_detach");1751 1752	assert_mprog_count(target, 2);1753 1754	memset(prog_ids, 0, sizeof(prog_ids));1755	optq.count = ARRAY_SIZE(prog_ids);1756 1757	err = bpf_prog_query_opts(loopback, target, &optq);1758	if (!ASSERT_OK(err, "prog_query"))1759		goto cleanup4;1760 1761	ASSERT_EQ(optq.count, 2, "count");1762	ASSERT_EQ(optq.revision, 7, "revision");1763	ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");1764	ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");1765	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1766 1767	LIBBPF_OPTS_RESET(optd);1768 1769	err = bpf_prog_detach_opts(fd3, loopback, target, &optd);1770	ASSERT_OK(err, "prog_detach");1771	assert_mprog_count(target, 1);1772 1773	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1774	ASSERT_OK(err, "prog_detach");1775	assert_mprog_count(target, 0);1776 1777	LIBBPF_OPTS_RESET(optd,1778		.flags = BPF_F_BEFORE,1779	);1780 1781	err = bpf_prog_detach_opts(0, loopback, target, &optd);1782	ASSERT_EQ(err, -ENOENT, "prog_detach");1783 1784	LIBBPF_OPTS_RESET(optd,1785		.flags = BPF_F_AFTER,1786	);1787 1788	err = bpf_prog_detach_opts(0, loopback, target, &optd);1789	ASSERT_EQ(err, -ENOENT, "prog_detach");1790	goto cleanup;1791 1792cleanup4:1793	err = bpf_prog_detach_opts(fd4, loopback, target, &optd);1794	ASSERT_OK(err, "prog_detach");1795	assert_mprog_count(target, 3);1796 1797cleanup3:1798	err = bpf_prog_detach_opts(fd3, loopback, target, &optd);1799	ASSERT_OK(err, "prog_detach");1800	assert_mprog_count(target, 2);1801 1802cleanup2:1803	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1804	ASSERT_OK(err, "prog_detach");1805	assert_mprog_count(target, 1);1806 1807cleanup1:1808	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1809	ASSERT_OK(err, "prog_detach");1810	assert_mprog_count(target, 0);1811 1812cleanup:1813	test_tc_link__destroy(skel);1814}1815 1816void serial_test_tc_opts_detach(void)1817{1818	test_tc_opts_detach_target(BPF_TCX_INGRESS);1819	test_tc_opts_detach_target(BPF_TCX_EGRESS);1820}1821 1822static void test_tc_opts_detach_before_target(int target)1823{1824	LIBBPF_OPTS(bpf_prog_attach_opts, opta);1825	LIBBPF_OPTS(bpf_prog_detach_opts, optd);1826	LIBBPF_OPTS(bpf_prog_query_opts, optq);1827	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;1828	struct test_tc_link *skel;1829	__u32 prog_ids[5];1830	int err;1831 1832	skel = test_tc_link__open_and_load();1833	if (!ASSERT_OK_PTR(skel, "skel_load"))1834		goto cleanup;1835 1836	fd1 = bpf_program__fd(skel->progs.tc1);1837	fd2 = bpf_program__fd(skel->progs.tc2);1838	fd3 = bpf_program__fd(skel->progs.tc3);1839	fd4 = bpf_program__fd(skel->progs.tc4);1840 1841	id1 = id_from_prog_fd(fd1);1842	id2 = id_from_prog_fd(fd2);1843	id3 = id_from_prog_fd(fd3);1844	id4 = id_from_prog_fd(fd4);1845 1846	ASSERT_NEQ(id1, id2, "prog_ids_1_2");1847	ASSERT_NEQ(id3, id4, "prog_ids_3_4");1848	ASSERT_NEQ(id2, id3, "prog_ids_2_3");1849 1850	assert_mprog_count(target, 0);1851 1852	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);1853	if (!ASSERT_EQ(err, 0, "prog_attach"))1854		goto cleanup;1855 1856	assert_mprog_count(target, 1);1857 1858	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);1859	if (!ASSERT_EQ(err, 0, "prog_attach"))1860		goto cleanup1;1861 1862	assert_mprog_count(target, 2);1863 1864	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);1865	if (!ASSERT_EQ(err, 0, "prog_attach"))1866		goto cleanup2;1867 1868	assert_mprog_count(target, 3);1869 1870	err = bpf_prog_attach_opts(fd4, loopback, target, &opta);1871	if (!ASSERT_EQ(err, 0, "prog_attach"))1872		goto cleanup3;1873 1874	assert_mprog_count(target, 4);1875 1876	optq.prog_ids = prog_ids;1877 1878	memset(prog_ids, 0, sizeof(prog_ids));1879	optq.count = ARRAY_SIZE(prog_ids);1880 1881	err = bpf_prog_query_opts(loopback, target, &optq);1882	if (!ASSERT_OK(err, "prog_query"))1883		goto cleanup4;1884 1885	ASSERT_EQ(optq.count, 4, "count");1886	ASSERT_EQ(optq.revision, 5, "revision");1887	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");1888	ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");1889	ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");1890	ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");1891	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1892 1893	LIBBPF_OPTS_RESET(optd,1894		.flags = BPF_F_BEFORE,1895		.relative_fd = fd2,1896	);1897 1898	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1899	ASSERT_OK(err, "prog_detach");1900 1901	assert_mprog_count(target, 3);1902 1903	memset(prog_ids, 0, sizeof(prog_ids));1904	optq.count = ARRAY_SIZE(prog_ids);1905 1906	err = bpf_prog_query_opts(loopback, target, &optq);1907	if (!ASSERT_OK(err, "prog_query"))1908		goto cleanup4;1909 1910	ASSERT_EQ(optq.count, 3, "count");1911	ASSERT_EQ(optq.revision, 6, "revision");1912	ASSERT_EQ(optq.prog_ids[0], id2, "prog_ids[0]");1913	ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");1914	ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");1915	ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");1916 1917	LIBBPF_OPTS_RESET(optd,1918		.flags = BPF_F_BEFORE,1919		.relative_fd = fd2,1920	);1921 1922	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);1923	ASSERT_EQ(err, -ENOENT, "prog_detach");1924	assert_mprog_count(target, 3);1925 1926	LIBBPF_OPTS_RESET(optd,1927		.flags = BPF_F_BEFORE,1928		.relative_fd = fd4,1929	);1930 1931	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1932	ASSERT_EQ(err, -ERANGE, "prog_detach");1933	assert_mprog_count(target, 3);1934 1935	LIBBPF_OPTS_RESET(optd,1936		.flags = BPF_F_BEFORE,1937		.relative_fd = fd1,1938	);1939 1940	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1941	ASSERT_EQ(err, -ENOENT, "prog_detach");1942	assert_mprog_count(target, 3);1943 1944	LIBBPF_OPTS_RESET(optd,1945		.flags = BPF_F_BEFORE,1946		.relative_fd = fd3,1947	);1948 1949	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);1950	ASSERT_OK(err, "prog_detach");1951 1952	assert_mprog_count(target, 2);1953 1954	memset(prog_ids, 0, sizeof(prog_ids));1955	optq.count = ARRAY_SIZE(prog_ids);1956 1957	err = bpf_prog_query_opts(loopback, target, &optq);1958	if (!ASSERT_OK(err, "prog_query"))1959		goto cleanup4;1960 1961	ASSERT_EQ(optq.count, 2, "count");1962	ASSERT_EQ(optq.revision, 7, "revision");1963	ASSERT_EQ(optq.prog_ids[0], id3, "prog_ids[0]");1964	ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]");1965	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1966 1967	LIBBPF_OPTS_RESET(optd,1968		.flags = BPF_F_BEFORE,1969		.relative_fd = fd4,1970	);1971 1972	err = bpf_prog_detach_opts(0, loopback, target, &optd);1973	ASSERT_OK(err, "prog_detach");1974 1975	assert_mprog_count(target, 1);1976 1977	memset(prog_ids, 0, sizeof(prog_ids));1978	optq.count = ARRAY_SIZE(prog_ids);1979 1980	err = bpf_prog_query_opts(loopback, target, &optq);1981	if (!ASSERT_OK(err, "prog_query"))1982		goto cleanup4;1983 1984	ASSERT_EQ(optq.count, 1, "count");1985	ASSERT_EQ(optq.revision, 8, "revision");1986	ASSERT_EQ(optq.prog_ids[0], id4, "prog_ids[0]");1987	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");1988 1989	LIBBPF_OPTS_RESET(optd,1990		.flags = BPF_F_BEFORE,1991	);1992 1993	err = bpf_prog_detach_opts(0, loopback, target, &optd);1994	ASSERT_OK(err, "prog_detach");1995 1996	assert_mprog_count(target, 0);1997	goto cleanup;1998 1999cleanup4:2000	err = bpf_prog_detach_opts(fd4, loopback, target, &optd);2001	ASSERT_OK(err, "prog_detach");2002	assert_mprog_count(target, 3);2003 2004cleanup3:2005	err = bpf_prog_detach_opts(fd3, loopback, target, &optd);2006	ASSERT_OK(err, "prog_detach");2007	assert_mprog_count(target, 2);2008 2009cleanup2:2010	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);2011	ASSERT_OK(err, "prog_detach");2012	assert_mprog_count(target, 1);2013 2014cleanup1:2015	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2016	ASSERT_OK(err, "prog_detach");2017	assert_mprog_count(target, 0);2018 2019cleanup:2020	test_tc_link__destroy(skel);2021}2022 2023void serial_test_tc_opts_detach_before(void)2024{2025	test_tc_opts_detach_before_target(BPF_TCX_INGRESS);2026	test_tc_opts_detach_before_target(BPF_TCX_EGRESS);2027}2028 2029static void test_tc_opts_detach_after_target(int target)2030{2031	LIBBPF_OPTS(bpf_prog_attach_opts, opta);2032	LIBBPF_OPTS(bpf_prog_detach_opts, optd);2033	LIBBPF_OPTS(bpf_prog_query_opts, optq);2034	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;2035	struct test_tc_link *skel;2036	__u32 prog_ids[5];2037	int err;2038 2039	skel = test_tc_link__open_and_load();2040	if (!ASSERT_OK_PTR(skel, "skel_load"))2041		goto cleanup;2042 2043	fd1 = bpf_program__fd(skel->progs.tc1);2044	fd2 = bpf_program__fd(skel->progs.tc2);2045	fd3 = bpf_program__fd(skel->progs.tc3);2046	fd4 = bpf_program__fd(skel->progs.tc4);2047 2048	id1 = id_from_prog_fd(fd1);2049	id2 = id_from_prog_fd(fd2);2050	id3 = id_from_prog_fd(fd3);2051	id4 = id_from_prog_fd(fd4);2052 2053	ASSERT_NEQ(id1, id2, "prog_ids_1_2");2054	ASSERT_NEQ(id3, id4, "prog_ids_3_4");2055	ASSERT_NEQ(id2, id3, "prog_ids_2_3");2056 2057	assert_mprog_count(target, 0);2058 2059	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);2060	if (!ASSERT_EQ(err, 0, "prog_attach"))2061		goto cleanup;2062 2063	assert_mprog_count(target, 1);2064 2065	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);2066	if (!ASSERT_EQ(err, 0, "prog_attach"))2067		goto cleanup1;2068 2069	assert_mprog_count(target, 2);2070 2071	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);2072	if (!ASSERT_EQ(err, 0, "prog_attach"))2073		goto cleanup2;2074 2075	assert_mprog_count(target, 3);2076 2077	err = bpf_prog_attach_opts(fd4, loopback, target, &opta);2078	if (!ASSERT_EQ(err, 0, "prog_attach"))2079		goto cleanup3;2080 2081	assert_mprog_count(target, 4);2082 2083	optq.prog_ids = prog_ids;2084 2085	memset(prog_ids, 0, sizeof(prog_ids));2086	optq.count = ARRAY_SIZE(prog_ids);2087 2088	err = bpf_prog_query_opts(loopback, target, &optq);2089	if (!ASSERT_OK(err, "prog_query"))2090		goto cleanup4;2091 2092	ASSERT_EQ(optq.count, 4, "count");2093	ASSERT_EQ(optq.revision, 5, "revision");2094	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2095	ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");2096	ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");2097	ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");2098	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");2099 2100	LIBBPF_OPTS_RESET(optd,2101		.flags = BPF_F_AFTER,2102		.relative_fd = fd1,2103	);2104 2105	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);2106	ASSERT_OK(err, "prog_detach");2107 2108	assert_mprog_count(target, 3);2109 2110	memset(prog_ids, 0, sizeof(prog_ids));2111	optq.count = ARRAY_SIZE(prog_ids);2112 2113	err = bpf_prog_query_opts(loopback, target, &optq);2114	if (!ASSERT_OK(err, "prog_query"))2115		goto cleanup4;2116 2117	ASSERT_EQ(optq.count, 3, "count");2118	ASSERT_EQ(optq.revision, 6, "revision");2119	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2120	ASSERT_EQ(optq.prog_ids[1], id3, "prog_ids[1]");2121	ASSERT_EQ(optq.prog_ids[2], id4, "prog_ids[2]");2122	ASSERT_EQ(optq.prog_ids[3], 0, "prog_ids[3]");2123 2124	LIBBPF_OPTS_RESET(optd,2125		.flags = BPF_F_AFTER,2126		.relative_fd = fd1,2127	);2128 2129	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);2130	ASSERT_EQ(err, -ENOENT, "prog_detach");2131	assert_mprog_count(target, 3);2132 2133	LIBBPF_OPTS_RESET(optd,2134		.flags = BPF_F_AFTER,2135		.relative_fd = fd4,2136	);2137 2138	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2139	ASSERT_EQ(err, -ERANGE, "prog_detach");2140	assert_mprog_count(target, 3);2141 2142	LIBBPF_OPTS_RESET(optd,2143		.flags = BPF_F_AFTER,2144		.relative_fd = fd3,2145	);2146 2147	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2148	ASSERT_EQ(err, -ERANGE, "prog_detach");2149	assert_mprog_count(target, 3);2150 2151	LIBBPF_OPTS_RESET(optd,2152		.flags = BPF_F_AFTER,2153		.relative_fd = fd1,2154	);2155 2156	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2157	ASSERT_EQ(err, -ERANGE, "prog_detach");2158	assert_mprog_count(target, 3);2159 2160	LIBBPF_OPTS_RESET(optd,2161		.flags = BPF_F_AFTER,2162		.relative_fd = fd1,2163	);2164 2165	err = bpf_prog_detach_opts(fd3, loopback, target, &optd);2166	ASSERT_OK(err, "prog_detach");2167 2168	assert_mprog_count(target, 2);2169 2170	memset(prog_ids, 0, sizeof(prog_ids));2171	optq.count = ARRAY_SIZE(prog_ids);2172 2173	err = bpf_prog_query_opts(loopback, target, &optq);2174	if (!ASSERT_OK(err, "prog_query"))2175		goto cleanup4;2176 2177	ASSERT_EQ(optq.count, 2, "count");2178	ASSERT_EQ(optq.revision, 7, "revision");2179	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2180	ASSERT_EQ(optq.prog_ids[1], id4, "prog_ids[1]");2181	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");2182 2183	LIBBPF_OPTS_RESET(optd,2184		.flags = BPF_F_AFTER,2185		.relative_fd = fd1,2186	);2187 2188	err = bpf_prog_detach_opts(0, loopback, target, &optd);2189	ASSERT_OK(err, "prog_detach");2190 2191	assert_mprog_count(target, 1);2192 2193	memset(prog_ids, 0, sizeof(prog_ids));2194	optq.count = ARRAY_SIZE(prog_ids);2195 2196	err = bpf_prog_query_opts(loopback, target, &optq);2197	if (!ASSERT_OK(err, "prog_query"))2198		goto cleanup4;2199 2200	ASSERT_EQ(optq.count, 1, "count");2201	ASSERT_EQ(optq.revision, 8, "revision");2202	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2203	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");2204 2205	LIBBPF_OPTS_RESET(optd,2206		.flags = BPF_F_AFTER,2207	);2208 2209	err = bpf_prog_detach_opts(0, loopback, target, &optd);2210	ASSERT_OK(err, "prog_detach");2211 2212	assert_mprog_count(target, 0);2213	goto cleanup;2214 2215cleanup4:2216	err = bpf_prog_detach_opts(fd4, loopback, target, &optd);2217	ASSERT_OK(err, "prog_detach");2218	assert_mprog_count(target, 3);2219 2220cleanup3:2221	err = bpf_prog_detach_opts(fd3, loopback, target, &optd);2222	ASSERT_OK(err, "prog_detach");2223	assert_mprog_count(target, 2);2224 2225cleanup2:2226	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);2227	ASSERT_OK(err, "prog_detach");2228	assert_mprog_count(target, 1);2229 2230cleanup1:2231	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2232	ASSERT_OK(err, "prog_detach");2233	assert_mprog_count(target, 0);2234 2235cleanup:2236	test_tc_link__destroy(skel);2237}2238 2239void serial_test_tc_opts_detach_after(void)2240{2241	test_tc_opts_detach_after_target(BPF_TCX_INGRESS);2242	test_tc_opts_detach_after_target(BPF_TCX_EGRESS);2243}2244 2245static void test_tc_opts_delete_empty(int target, bool chain_tc_old)2246{2247	LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);2248	LIBBPF_OPTS(bpf_prog_detach_opts, optd);2249	int err;2250 2251	assert_mprog_count(target, 0);2252	if (chain_tc_old) {2253		tc_hook.attach_point = target == BPF_TCX_INGRESS ?2254				       BPF_TC_INGRESS : BPF_TC_EGRESS;2255		err = bpf_tc_hook_create(&tc_hook);2256		ASSERT_OK(err, "bpf_tc_hook_create");2257		assert_mprog_count(target, 0);2258	}2259	err = bpf_prog_detach_opts(0, loopback, target, &optd);2260	ASSERT_EQ(err, -ENOENT, "prog_detach");2261	if (chain_tc_old) {2262		tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;2263		bpf_tc_hook_destroy(&tc_hook);2264	}2265	assert_mprog_count(target, 0);2266}2267 2268void serial_test_tc_opts_delete_empty(void)2269{2270	test_tc_opts_delete_empty(BPF_TCX_INGRESS, false);2271	test_tc_opts_delete_empty(BPF_TCX_EGRESS, false);2272	test_tc_opts_delete_empty(BPF_TCX_INGRESS, true);2273	test_tc_opts_delete_empty(BPF_TCX_EGRESS, true);2274}2275 2276static void test_tc_chain_mixed(int target)2277{2278	LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);2279	LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);2280	LIBBPF_OPTS(bpf_prog_attach_opts, opta);2281	LIBBPF_OPTS(bpf_prog_detach_opts, optd);2282	__u32 fd1, fd2, fd3, id1, id2, id3;2283	struct test_tc_link *skel;2284	int err, detach_fd;2285 2286	skel = test_tc_link__open_and_load();2287	if (!ASSERT_OK_PTR(skel, "skel_load"))2288		goto cleanup;2289 2290	fd1 = bpf_program__fd(skel->progs.tc4);2291	fd2 = bpf_program__fd(skel->progs.tc5);2292	fd3 = bpf_program__fd(skel->progs.tc6);2293 2294	id1 = id_from_prog_fd(fd1);2295	id2 = id_from_prog_fd(fd2);2296	id3 = id_from_prog_fd(fd3);2297 2298	ASSERT_NEQ(id1, id2, "prog_ids_1_2");2299	ASSERT_NEQ(id2, id3, "prog_ids_2_3");2300 2301	assert_mprog_count(target, 0);2302 2303	tc_hook.attach_point = target == BPF_TCX_INGRESS ?2304			       BPF_TC_INGRESS : BPF_TC_EGRESS;2305	err = bpf_tc_hook_create(&tc_hook);2306	err = err == -EEXIST ? 0 : err;2307	if (!ASSERT_OK(err, "bpf_tc_hook_create"))2308		goto cleanup;2309 2310	tc_opts.prog_fd = fd2;2311	err = bpf_tc_attach(&tc_hook, &tc_opts);2312	if (!ASSERT_OK(err, "bpf_tc_attach"))2313		goto cleanup_hook;2314 2315	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);2316	if (!ASSERT_EQ(err, 0, "prog_attach"))2317		goto cleanup_filter;2318 2319	detach_fd = fd3;2320 2321	assert_mprog_count(target, 1);2322 2323	tc_skel_reset_all_seen(skel);2324	ASSERT_OK(system(ping_cmd), ping_cmd);2325 2326	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");2327	ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");2328	ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");2329 2330	LIBBPF_OPTS_RESET(opta,2331		.flags = BPF_F_REPLACE,2332		.replace_prog_fd = fd3,2333	);2334 2335	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);2336	if (!ASSERT_EQ(err, 0, "prog_attach"))2337		goto cleanup_opts;2338 2339	detach_fd = fd1;2340 2341	assert_mprog_count(target, 1);2342 2343	tc_skel_reset_all_seen(skel);2344	ASSERT_OK(system(ping_cmd), ping_cmd);2345 2346	ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");2347	ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");2348	ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");2349 2350cleanup_opts:2351	err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);2352	ASSERT_OK(err, "prog_detach");2353	assert_mprog_count(target, 0);2354 2355	tc_skel_reset_all_seen(skel);2356	ASSERT_OK(system(ping_cmd), ping_cmd);2357 2358	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");2359	ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");2360	ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");2361 2362cleanup_filter:2363	tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;2364	err = bpf_tc_detach(&tc_hook, &tc_opts);2365	ASSERT_OK(err, "bpf_tc_detach");2366 2367cleanup_hook:2368	tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;2369	bpf_tc_hook_destroy(&tc_hook);2370 2371cleanup:2372	test_tc_link__destroy(skel);2373}2374 2375void serial_test_tc_opts_chain_mixed(void)2376{2377	test_tc_chain_mixed(BPF_TCX_INGRESS);2378	test_tc_chain_mixed(BPF_TCX_EGRESS);2379}2380 2381static int generate_dummy_prog(void)2382{2383	const struct bpf_insn prog_insns[] = {2384		BPF_MOV64_IMM(BPF_REG_0, 0),2385		BPF_EXIT_INSN(),2386	};2387	const size_t prog_insn_cnt = ARRAY_SIZE(prog_insns);2388	LIBBPF_OPTS(bpf_prog_load_opts, opts);2389	const size_t log_buf_sz = 256;2390	char log_buf[log_buf_sz];2391	int fd = -1;2392 2393	opts.log_buf = log_buf;2394	opts.log_size = log_buf_sz;2395 2396	log_buf[0] = '\0';2397	opts.log_level = 0;2398	fd = bpf_prog_load(BPF_PROG_TYPE_SCHED_CLS, "tcx_prog", "GPL",2399			   prog_insns, prog_insn_cnt, &opts);2400	ASSERT_STREQ(log_buf, "", "log_0");2401	ASSERT_GE(fd, 0, "prog_fd");2402	return fd;2403}2404 2405static void test_tc_opts_max_target(int target, int flags, bool relative)2406{2407	int err, ifindex, i, prog_fd, last_fd = -1;2408	LIBBPF_OPTS(bpf_prog_attach_opts, opta);2409	const int max_progs = 63;2410 2411	ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");2412	ifindex = if_nametoindex("tcx_opts1");2413	ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");2414 2415	assert_mprog_count_ifindex(ifindex, target, 0);2416 2417	for (i = 0; i < max_progs; i++) {2418		prog_fd = generate_dummy_prog();2419		if (!ASSERT_GE(prog_fd, 0, "dummy_prog"))2420			goto cleanup;2421		err = bpf_prog_attach_opts(prog_fd, ifindex, target, &opta);2422		if (!ASSERT_EQ(err, 0, "prog_attach"))2423			goto cleanup;2424		assert_mprog_count_ifindex(ifindex, target, i + 1);2425		if (i == max_progs - 1 && relative)2426			last_fd = prog_fd;2427		else2428			close(prog_fd);2429	}2430 2431	prog_fd = generate_dummy_prog();2432	if (!ASSERT_GE(prog_fd, 0, "dummy_prog"))2433		goto cleanup;2434	opta.flags = flags;2435	if (last_fd > 0)2436		opta.relative_fd = last_fd;2437	err = bpf_prog_attach_opts(prog_fd, ifindex, target, &opta);2438	ASSERT_EQ(err, -ERANGE, "prog_64_attach");2439	assert_mprog_count_ifindex(ifindex, target, max_progs);2440	close(prog_fd);2441cleanup:2442	if (last_fd > 0)2443		close(last_fd);2444	ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");2445	ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");2446	ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");2447}2448 2449void serial_test_tc_opts_max(void)2450{2451	test_tc_opts_max_target(BPF_TCX_INGRESS, 0, false);2452	test_tc_opts_max_target(BPF_TCX_EGRESS, 0, false);2453 2454	test_tc_opts_max_target(BPF_TCX_INGRESS, BPF_F_BEFORE, false);2455	test_tc_opts_max_target(BPF_TCX_EGRESS, BPF_F_BEFORE, true);2456 2457	test_tc_opts_max_target(BPF_TCX_INGRESS, BPF_F_AFTER, true);2458	test_tc_opts_max_target(BPF_TCX_EGRESS, BPF_F_AFTER, false);2459}2460 2461static void test_tc_opts_query_target(int target)2462{2463	const size_t attr_size = offsetofend(union bpf_attr, query);2464	LIBBPF_OPTS(bpf_prog_attach_opts, opta);2465	LIBBPF_OPTS(bpf_prog_detach_opts, optd);2466	LIBBPF_OPTS(bpf_prog_query_opts, optq);2467	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;2468	struct test_tc_link *skel;2469	union bpf_attr attr;2470	__u32 prog_ids[10];2471	int err;2472 2473	skel = test_tc_link__open_and_load();2474	if (!ASSERT_OK_PTR(skel, "skel_load"))2475		goto cleanup;2476 2477	fd1 = bpf_program__fd(skel->progs.tc1);2478	fd2 = bpf_program__fd(skel->progs.tc2);2479	fd3 = bpf_program__fd(skel->progs.tc3);2480	fd4 = bpf_program__fd(skel->progs.tc4);2481 2482	id1 = id_from_prog_fd(fd1);2483	id2 = id_from_prog_fd(fd2);2484	id3 = id_from_prog_fd(fd3);2485	id4 = id_from_prog_fd(fd4);2486 2487	assert_mprog_count(target, 0);2488 2489	LIBBPF_OPTS_RESET(opta,2490		.expected_revision = 1,2491	);2492 2493	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);2494	if (!ASSERT_EQ(err, 0, "prog_attach"))2495		goto cleanup;2496 2497	assert_mprog_count(target, 1);2498 2499	LIBBPF_OPTS_RESET(opta,2500		.expected_revision = 2,2501	);2502 2503	err = bpf_prog_attach_opts(fd2, loopback, target, &opta);2504	if (!ASSERT_EQ(err, 0, "prog_attach"))2505		goto cleanup1;2506 2507	assert_mprog_count(target, 2);2508 2509	LIBBPF_OPTS_RESET(opta,2510		.expected_revision = 3,2511	);2512 2513	err = bpf_prog_attach_opts(fd3, loopback, target, &opta);2514	if (!ASSERT_EQ(err, 0, "prog_attach"))2515		goto cleanup2;2516 2517	assert_mprog_count(target, 3);2518 2519	LIBBPF_OPTS_RESET(opta,2520		.expected_revision = 4,2521	);2522 2523	err = bpf_prog_attach_opts(fd4, loopback, target, &opta);2524	if (!ASSERT_EQ(err, 0, "prog_attach"))2525		goto cleanup3;2526 2527	assert_mprog_count(target, 4);2528 2529	/* Test 1: Double query via libbpf API */2530	err = bpf_prog_query_opts(loopback, target, &optq);2531	if (!ASSERT_OK(err, "prog_query"))2532		goto cleanup4;2533 2534	ASSERT_EQ(optq.count, 4, "count");2535	ASSERT_EQ(optq.revision, 5, "revision");2536	ASSERT_EQ(optq.prog_ids, NULL, "prog_ids");2537	ASSERT_EQ(optq.link_ids, NULL, "link_ids");2538 2539	memset(prog_ids, 0, sizeof(prog_ids));2540	optq.prog_ids = prog_ids;2541 2542	err = bpf_prog_query_opts(loopback, target, &optq);2543	if (!ASSERT_OK(err, "prog_query"))2544		goto cleanup4;2545 2546	ASSERT_EQ(optq.count, 4, "count");2547	ASSERT_EQ(optq.revision, 5, "revision");2548	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2549	ASSERT_EQ(optq.prog_ids[1], id2, "prog_ids[1]");2550	ASSERT_EQ(optq.prog_ids[2], id3, "prog_ids[2]");2551	ASSERT_EQ(optq.prog_ids[3], id4, "prog_ids[3]");2552	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");2553	ASSERT_EQ(optq.link_ids, NULL, "link_ids");2554 2555	/* Test 2: Double query via bpf_attr & bpf(2) directly */2556	memset(&attr, 0, attr_size);2557	attr.query.target_ifindex = loopback;2558	attr.query.attach_type = target;2559 2560	err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2561	if (!ASSERT_OK(err, "prog_query"))2562		goto cleanup4;2563 2564	ASSERT_EQ(attr.query.count, 4, "count");2565	ASSERT_EQ(attr.query.revision, 5, "revision");2566	ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2567	ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2568	ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2569	ASSERT_EQ(attr.query.attach_type, target, "attach_type");2570	ASSERT_EQ(attr.query.prog_ids, 0, "prog_ids");2571	ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2572	ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2573	ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2574 2575	memset(prog_ids, 0, sizeof(prog_ids));2576	attr.query.prog_ids = ptr_to_u64(prog_ids);2577 2578	err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2579	if (!ASSERT_OK(err, "prog_query"))2580		goto cleanup4;2581 2582	ASSERT_EQ(attr.query.count, 4, "count");2583	ASSERT_EQ(attr.query.revision, 5, "revision");2584	ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2585	ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2586	ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2587	ASSERT_EQ(attr.query.attach_type, target, "attach_type");2588	ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");2589	ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");2590	ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");2591	ASSERT_EQ(prog_ids[2], id3, "prog_ids[2]");2592	ASSERT_EQ(prog_ids[3], id4, "prog_ids[3]");2593	ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");2594	ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2595	ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2596	ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2597 2598	/* Test 3: Query with smaller prog_ids array */2599	memset(&attr, 0, attr_size);2600	attr.query.target_ifindex = loopback;2601	attr.query.attach_type = target;2602 2603	memset(prog_ids, 0, sizeof(prog_ids));2604	attr.query.prog_ids = ptr_to_u64(prog_ids);2605	attr.query.count = 2;2606 2607	err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2608	ASSERT_EQ(err, -1, "prog_query_should_fail");2609	ASSERT_EQ(errno, ENOSPC, "prog_query_should_fail");2610 2611	ASSERT_EQ(attr.query.count, 4, "count");2612	ASSERT_EQ(attr.query.revision, 5, "revision");2613	ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2614	ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2615	ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2616	ASSERT_EQ(attr.query.attach_type, target, "attach_type");2617	ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");2618	ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");2619	ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");2620	ASSERT_EQ(prog_ids[2], 0, "prog_ids[2]");2621	ASSERT_EQ(prog_ids[3], 0, "prog_ids[3]");2622	ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");2623	ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2624	ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2625	ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2626 2627	/* Test 4: Query with larger prog_ids array */2628	memset(&attr, 0, attr_size);2629	attr.query.target_ifindex = loopback;2630	attr.query.attach_type = target;2631 2632	memset(prog_ids, 0, sizeof(prog_ids));2633	attr.query.prog_ids = ptr_to_u64(prog_ids);2634	attr.query.count = 10;2635 2636	err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2637	if (!ASSERT_OK(err, "prog_query"))2638		goto cleanup4;2639 2640	ASSERT_EQ(attr.query.count, 4, "count");2641	ASSERT_EQ(attr.query.revision, 5, "revision");2642	ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2643	ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2644	ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2645	ASSERT_EQ(attr.query.attach_type, target, "attach_type");2646	ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");2647	ASSERT_EQ(prog_ids[0], id1, "prog_ids[0]");2648	ASSERT_EQ(prog_ids[1], id2, "prog_ids[1]");2649	ASSERT_EQ(prog_ids[2], id3, "prog_ids[2]");2650	ASSERT_EQ(prog_ids[3], id4, "prog_ids[3]");2651	ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");2652	ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2653	ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2654	ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2655 2656	/* Test 5: Query with NULL prog_ids array but with count > 0 */2657	memset(&attr, 0, attr_size);2658	attr.query.target_ifindex = loopback;2659	attr.query.attach_type = target;2660 2661	memset(prog_ids, 0, sizeof(prog_ids));2662	attr.query.count = sizeof(prog_ids);2663 2664	err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2665	if (!ASSERT_OK(err, "prog_query"))2666		goto cleanup4;2667 2668	ASSERT_EQ(attr.query.count, 4, "count");2669	ASSERT_EQ(attr.query.revision, 5, "revision");2670	ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2671	ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2672	ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2673	ASSERT_EQ(attr.query.attach_type, target, "attach_type");2674	ASSERT_EQ(prog_ids[0], 0, "prog_ids[0]");2675	ASSERT_EQ(prog_ids[1], 0, "prog_ids[1]");2676	ASSERT_EQ(prog_ids[2], 0, "prog_ids[2]");2677	ASSERT_EQ(prog_ids[3], 0, "prog_ids[3]");2678	ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");2679	ASSERT_EQ(attr.query.prog_ids, 0, "prog_ids");2680	ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2681	ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2682	ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2683 2684	/* Test 6: Query with non-NULL prog_ids array but with count == 0 */2685	memset(&attr, 0, attr_size);2686	attr.query.target_ifindex = loopback;2687	attr.query.attach_type = target;2688 2689	memset(prog_ids, 0, sizeof(prog_ids));2690	attr.query.prog_ids = ptr_to_u64(prog_ids);2691 2692	err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2693	if (!ASSERT_OK(err, "prog_query"))2694		goto cleanup4;2695 2696	ASSERT_EQ(attr.query.count, 4, "count");2697	ASSERT_EQ(attr.query.revision, 5, "revision");2698	ASSERT_EQ(attr.query.query_flags, 0, "query_flags");2699	ASSERT_EQ(attr.query.attach_flags, 0, "attach_flags");2700	ASSERT_EQ(attr.query.target_ifindex, loopback, "target_ifindex");2701	ASSERT_EQ(attr.query.attach_type, target, "attach_type");2702	ASSERT_EQ(prog_ids[0], 0, "prog_ids[0]");2703	ASSERT_EQ(prog_ids[1], 0, "prog_ids[1]");2704	ASSERT_EQ(prog_ids[2], 0, "prog_ids[2]");2705	ASSERT_EQ(prog_ids[3], 0, "prog_ids[3]");2706	ASSERT_EQ(prog_ids[4], 0, "prog_ids[4]");2707	ASSERT_EQ(attr.query.prog_ids, ptr_to_u64(prog_ids), "prog_ids");2708	ASSERT_EQ(attr.query.prog_attach_flags, 0, "prog_attach_flags");2709	ASSERT_EQ(attr.query.link_ids, 0, "link_ids");2710	ASSERT_EQ(attr.query.link_attach_flags, 0, "link_attach_flags");2711 2712	/* Test 7: Query with invalid flags */2713	attr.query.attach_flags = 0;2714	attr.query.query_flags = 1;2715 2716	err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2717	ASSERT_EQ(err, -1, "prog_query_should_fail");2718	ASSERT_EQ(errno, EINVAL, "prog_query_should_fail");2719 2720	attr.query.attach_flags = 1;2721	attr.query.query_flags = 0;2722 2723	err = syscall(__NR_bpf, BPF_PROG_QUERY, &attr, attr_size);2724	ASSERT_EQ(err, -1, "prog_query_should_fail");2725	ASSERT_EQ(errno, EINVAL, "prog_query_should_fail");2726 2727cleanup4:2728	err = bpf_prog_detach_opts(fd4, loopback, target, &optd);2729	ASSERT_OK(err, "prog_detach");2730	assert_mprog_count(target, 3);2731 2732cleanup3:2733	err = bpf_prog_detach_opts(fd3, loopback, target, &optd);2734	ASSERT_OK(err, "prog_detach");2735	assert_mprog_count(target, 2);2736 2737cleanup2:2738	err = bpf_prog_detach_opts(fd2, loopback, target, &optd);2739	ASSERT_OK(err, "prog_detach");2740	assert_mprog_count(target, 1);2741 2742cleanup1:2743	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2744	ASSERT_OK(err, "prog_detach");2745	assert_mprog_count(target, 0);2746 2747cleanup:2748	test_tc_link__destroy(skel);2749}2750 2751void serial_test_tc_opts_query(void)2752{2753	test_tc_opts_query_target(BPF_TCX_INGRESS);2754	test_tc_opts_query_target(BPF_TCX_EGRESS);2755}2756 2757static void test_tc_opts_query_attach_target(int target)2758{2759	LIBBPF_OPTS(bpf_prog_attach_opts, opta);2760	LIBBPF_OPTS(bpf_prog_detach_opts, optd);2761	LIBBPF_OPTS(bpf_prog_query_opts, optq);2762	struct test_tc_link *skel;2763	__u32 prog_ids[2];2764	__u32 fd1, id1;2765	int err;2766 2767	skel = test_tc_link__open_and_load();2768	if (!ASSERT_OK_PTR(skel, "skel_load"))2769		goto cleanup;2770 2771	fd1 = bpf_program__fd(skel->progs.tc1);2772	id1 = id_from_prog_fd(fd1);2773 2774	err = bpf_prog_query_opts(loopback, target, &optq);2775	if (!ASSERT_OK(err, "prog_query"))2776		goto cleanup;2777 2778	ASSERT_EQ(optq.count, 0, "count");2779	ASSERT_EQ(optq.revision, 1, "revision");2780 2781	LIBBPF_OPTS_RESET(opta,2782		.expected_revision = optq.revision,2783	);2784 2785	err = bpf_prog_attach_opts(fd1, loopback, target, &opta);2786	if (!ASSERT_EQ(err, 0, "prog_attach"))2787		goto cleanup;2788 2789	memset(prog_ids, 0, sizeof(prog_ids));2790	optq.prog_ids = prog_ids;2791	optq.count = ARRAY_SIZE(prog_ids);2792 2793	err = bpf_prog_query_opts(loopback, target, &optq);2794	if (!ASSERT_OK(err, "prog_query"))2795		goto cleanup1;2796 2797	ASSERT_EQ(optq.count, 1, "count");2798	ASSERT_EQ(optq.revision, 2, "revision");2799	ASSERT_EQ(optq.prog_ids[0], id1, "prog_ids[0]");2800	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");2801 2802cleanup1:2803	err = bpf_prog_detach_opts(fd1, loopback, target, &optd);2804	ASSERT_OK(err, "prog_detach");2805	assert_mprog_count(target, 0);2806cleanup:2807	test_tc_link__destroy(skel);2808}2809 2810void serial_test_tc_opts_query_attach(void)2811{2812	test_tc_opts_query_attach_target(BPF_TCX_INGRESS);2813	test_tc_opts_query_attach_target(BPF_TCX_EGRESS);2814}2815