brintos

brintos / linux-shallow public Read only

0
0
Text · 54.5 KiB · 1af9ec1 Raw
1963 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2023 Isovalent */3#include <uapi/linux/if_link.h>4#include <uapi/linux/pkt_sched.h>5#include <net/if.h>6#include <test_progs.h>7 8#define loopback 19#define ping_cmd "ping -q -c1 -w1 127.0.0.1 > /dev/null"10 11#include "test_tc_link.skel.h"12 13#include "netlink_helpers.h"14#include "tc_helpers.h"15 16void serial_test_tc_links_basic(void)17{18	LIBBPF_OPTS(bpf_prog_query_opts, optq);19	LIBBPF_OPTS(bpf_tcx_opts, optl);20	__u32 prog_ids[2], link_ids[2];21	__u32 pid1, pid2, lid1, lid2;22	struct test_tc_link *skel;23	struct bpf_link *link;24	int err;25 26	skel = test_tc_link__open_and_load();27	if (!ASSERT_OK_PTR(skel, "skel_load"))28		goto cleanup;29 30	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));31	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));32 33	ASSERT_NEQ(pid1, pid2, "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	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);42	if (!ASSERT_OK_PTR(link, "link_attach"))43		goto cleanup;44 45	skel->links.tc1 = link;46 47	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));48 49	assert_mprog_count(BPF_TCX_INGRESS, 1);50	assert_mprog_count(BPF_TCX_EGRESS, 0);51 52	optq.prog_ids = prog_ids;53	optq.link_ids = link_ids;54 55	memset(prog_ids, 0, sizeof(prog_ids));56	memset(link_ids, 0, sizeof(link_ids));57	optq.count = ARRAY_SIZE(prog_ids);58 59	err = bpf_prog_query_opts(loopback, BPF_TCX_INGRESS, &optq);60	if (!ASSERT_OK(err, "prog_query"))61		goto cleanup;62 63	ASSERT_EQ(optq.count, 1, "count");64	ASSERT_EQ(optq.revision, 2, "revision");65	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");66	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");67	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");68	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");69 70	tc_skel_reset_all_seen(skel);71	ASSERT_OK(system(ping_cmd), ping_cmd);72 73	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");74	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");75 76	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);77	if (!ASSERT_OK_PTR(link, "link_attach"))78		goto cleanup;79 80	skel->links.tc2 = link;81 82	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));83	ASSERT_NEQ(lid1, lid2, "link_ids_1_2");84 85	assert_mprog_count(BPF_TCX_INGRESS, 1);86	assert_mprog_count(BPF_TCX_EGRESS, 1);87 88	memset(prog_ids, 0, sizeof(prog_ids));89	memset(link_ids, 0, sizeof(link_ids));90	optq.count = ARRAY_SIZE(prog_ids);91 92	err = bpf_prog_query_opts(loopback, BPF_TCX_EGRESS, &optq);93	if (!ASSERT_OK(err, "prog_query"))94		goto cleanup;95 96	ASSERT_EQ(optq.count, 1, "count");97	ASSERT_EQ(optq.revision, 2, "revision");98	ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");99	ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");100	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");101	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");102 103	tc_skel_reset_all_seen(skel);104	ASSERT_OK(system(ping_cmd), ping_cmd);105 106	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");107	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");108cleanup:109	test_tc_link__destroy(skel);110 111	assert_mprog_count(BPF_TCX_INGRESS, 0);112	assert_mprog_count(BPF_TCX_EGRESS, 0);113}114 115static void test_tc_links_before_target(int target)116{117	LIBBPF_OPTS(bpf_prog_query_opts, optq);118	LIBBPF_OPTS(bpf_tcx_opts, optl);119	__u32 prog_ids[5], link_ids[5];120	__u32 pid1, pid2, pid3, pid4;121	__u32 lid1, lid2, lid3, lid4;122	struct test_tc_link *skel;123	struct bpf_link *link;124	int err;125 126	skel = test_tc_link__open();127	if (!ASSERT_OK_PTR(skel, "skel_open"))128		goto cleanup;129 130	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),131		  0, "tc1_attach_type");132	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),133		  0, "tc2_attach_type");134	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),135		  0, "tc3_attach_type");136	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),137		  0, "tc4_attach_type");138 139	err = test_tc_link__load(skel);140	if (!ASSERT_OK(err, "skel_load"))141		goto cleanup;142 143	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));144	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));145	pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));146	pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));147 148	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");149	ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");150	ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");151 152	assert_mprog_count(target, 0);153 154	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);155	if (!ASSERT_OK_PTR(link, "link_attach"))156		goto cleanup;157 158	skel->links.tc1 = link;159 160	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));161 162	assert_mprog_count(target, 1);163 164	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);165	if (!ASSERT_OK_PTR(link, "link_attach"))166		goto cleanup;167 168	skel->links.tc2 = link;169 170	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));171 172	assert_mprog_count(target, 2);173 174	optq.prog_ids = prog_ids;175	optq.link_ids = link_ids;176 177	memset(prog_ids, 0, sizeof(prog_ids));178	memset(link_ids, 0, sizeof(link_ids));179	optq.count = ARRAY_SIZE(prog_ids);180 181	err = bpf_prog_query_opts(loopback, target, &optq);182	if (!ASSERT_OK(err, "prog_query"))183		goto cleanup;184 185	ASSERT_EQ(optq.count, 2, "count");186	ASSERT_EQ(optq.revision, 3, "revision");187	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");188	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");189	ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");190	ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");191	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");192	ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");193 194	tc_skel_reset_all_seen(skel);195	ASSERT_OK(system(ping_cmd), ping_cmd);196 197	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");198	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");199	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");200	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");201 202	LIBBPF_OPTS_RESET(optl,203		.flags = BPF_F_BEFORE,204		.relative_fd = bpf_program__fd(skel->progs.tc2),205	);206 207	link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);208	if (!ASSERT_OK_PTR(link, "link_attach"))209		goto cleanup;210 211	skel->links.tc3 = link;212 213	lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));214 215	LIBBPF_OPTS_RESET(optl,216		.flags = BPF_F_BEFORE | BPF_F_LINK,217		.relative_id = lid1,218	);219 220	link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);221	if (!ASSERT_OK_PTR(link, "link_attach"))222		goto cleanup;223 224	skel->links.tc4 = link;225 226	lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));227 228	assert_mprog_count(target, 4);229 230	memset(prog_ids, 0, sizeof(prog_ids));231	memset(link_ids, 0, sizeof(link_ids));232	optq.count = ARRAY_SIZE(prog_ids);233 234	err = bpf_prog_query_opts(loopback, target, &optq);235	if (!ASSERT_OK(err, "prog_query"))236		goto cleanup;237 238	ASSERT_EQ(optq.count, 4, "count");239	ASSERT_EQ(optq.revision, 5, "revision");240	ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]");241	ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]");242	ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");243	ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");244	ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]");245	ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]");246	ASSERT_EQ(optq.prog_ids[3], pid2, "prog_ids[3]");247	ASSERT_EQ(optq.link_ids[3], lid2, "link_ids[3]");248	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");249	ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");250 251	tc_skel_reset_all_seen(skel);252	ASSERT_OK(system(ping_cmd), ping_cmd);253 254	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");255	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");256	ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");257	ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");258cleanup:259	test_tc_link__destroy(skel);260	assert_mprog_count(target, 0);261}262 263void serial_test_tc_links_before(void)264{265	test_tc_links_before_target(BPF_TCX_INGRESS);266	test_tc_links_before_target(BPF_TCX_EGRESS);267}268 269static void test_tc_links_after_target(int target)270{271	LIBBPF_OPTS(bpf_prog_query_opts, optq);272	LIBBPF_OPTS(bpf_tcx_opts, optl);273	__u32 prog_ids[5], link_ids[5];274	__u32 pid1, pid2, pid3, pid4;275	__u32 lid1, lid2, lid3, lid4;276	struct test_tc_link *skel;277	struct bpf_link *link;278	int err;279 280	skel = test_tc_link__open();281	if (!ASSERT_OK_PTR(skel, "skel_open"))282		goto cleanup;283 284	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),285		  0, "tc1_attach_type");286	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),287		  0, "tc2_attach_type");288	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),289		  0, "tc3_attach_type");290	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),291		  0, "tc4_attach_type");292 293	err = test_tc_link__load(skel);294	if (!ASSERT_OK(err, "skel_load"))295		goto cleanup;296 297	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));298	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));299	pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));300	pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));301 302	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");303	ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");304	ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");305 306	assert_mprog_count(target, 0);307 308	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);309	if (!ASSERT_OK_PTR(link, "link_attach"))310		goto cleanup;311 312	skel->links.tc1 = link;313 314	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));315 316	assert_mprog_count(target, 1);317 318	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);319	if (!ASSERT_OK_PTR(link, "link_attach"))320		goto cleanup;321 322	skel->links.tc2 = link;323 324	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));325 326	assert_mprog_count(target, 2);327 328	optq.prog_ids = prog_ids;329	optq.link_ids = link_ids;330 331	memset(prog_ids, 0, sizeof(prog_ids));332	memset(link_ids, 0, sizeof(link_ids));333	optq.count = ARRAY_SIZE(prog_ids);334 335	err = bpf_prog_query_opts(loopback, target, &optq);336	if (!ASSERT_OK(err, "prog_query"))337		goto cleanup;338 339	ASSERT_EQ(optq.count, 2, "count");340	ASSERT_EQ(optq.revision, 3, "revision");341	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");342	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");343	ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");344	ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");345	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");346	ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");347 348	tc_skel_reset_all_seen(skel);349	ASSERT_OK(system(ping_cmd), ping_cmd);350 351	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");352	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");353	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");354	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");355 356	LIBBPF_OPTS_RESET(optl,357		.flags = BPF_F_AFTER,358		.relative_fd = bpf_program__fd(skel->progs.tc1),359	);360 361	link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);362	if (!ASSERT_OK_PTR(link, "link_attach"))363		goto cleanup;364 365	skel->links.tc3 = link;366 367	lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));368 369	LIBBPF_OPTS_RESET(optl,370		.flags = BPF_F_AFTER | BPF_F_LINK,371		.relative_fd = bpf_link__fd(skel->links.tc2),372	);373 374	link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);375	if (!ASSERT_OK_PTR(link, "link_attach"))376		goto cleanup;377 378	skel->links.tc4 = link;379 380	lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));381 382	assert_mprog_count(target, 4);383 384	memset(prog_ids, 0, sizeof(prog_ids));385	memset(link_ids, 0, sizeof(link_ids));386	optq.count = ARRAY_SIZE(prog_ids);387 388	err = bpf_prog_query_opts(loopback, target, &optq);389	if (!ASSERT_OK(err, "prog_query"))390		goto cleanup;391 392	ASSERT_EQ(optq.count, 4, "count");393	ASSERT_EQ(optq.revision, 5, "revision");394	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");395	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");396	ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]");397	ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]");398	ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]");399	ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]");400	ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]");401	ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]");402	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");403	ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");404 405	tc_skel_reset_all_seen(skel);406	ASSERT_OK(system(ping_cmd), ping_cmd);407 408	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");409	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");410	ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");411	ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");412cleanup:413	test_tc_link__destroy(skel);414	assert_mprog_count(target, 0);415}416 417void serial_test_tc_links_after(void)418{419	test_tc_links_after_target(BPF_TCX_INGRESS);420	test_tc_links_after_target(BPF_TCX_EGRESS);421}422 423static void test_tc_links_revision_target(int target)424{425	LIBBPF_OPTS(bpf_prog_query_opts, optq);426	LIBBPF_OPTS(bpf_tcx_opts, optl);427	__u32 prog_ids[3], link_ids[3];428	__u32 pid1, pid2, lid1, lid2;429	struct test_tc_link *skel;430	struct bpf_link *link;431	int err;432 433	skel = test_tc_link__open();434	if (!ASSERT_OK_PTR(skel, "skel_open"))435		goto cleanup;436 437	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),438		  0, "tc1_attach_type");439	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),440		  0, "tc2_attach_type");441 442	err = test_tc_link__load(skel);443	if (!ASSERT_OK(err, "skel_load"))444		goto cleanup;445 446	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));447	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));448 449	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");450 451	assert_mprog_count(target, 0);452 453	optl.expected_revision = 1;454 455	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);456	if (!ASSERT_OK_PTR(link, "link_attach"))457		goto cleanup;458 459	skel->links.tc1 = link;460 461	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));462 463	assert_mprog_count(target, 1);464 465	optl.expected_revision = 1;466 467	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);468	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {469		bpf_link__destroy(link);470		goto cleanup;471	}472 473	assert_mprog_count(target, 1);474 475	optl.expected_revision = 2;476 477	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);478	if (!ASSERT_OK_PTR(link, "link_attach"))479		goto cleanup;480 481	skel->links.tc2 = link;482 483	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));484 485	assert_mprog_count(target, 2);486 487	optq.prog_ids = prog_ids;488	optq.link_ids = link_ids;489 490	memset(prog_ids, 0, sizeof(prog_ids));491	memset(link_ids, 0, sizeof(link_ids));492	optq.count = ARRAY_SIZE(prog_ids);493 494	err = bpf_prog_query_opts(loopback, target, &optq);495	if (!ASSERT_OK(err, "prog_query"))496		goto cleanup;497 498	ASSERT_EQ(optq.count, 2, "count");499	ASSERT_EQ(optq.revision, 3, "revision");500	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");501	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");502	ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");503	ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");504	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");505	ASSERT_EQ(optq.link_ids[2], 0, "prog_ids[2]");506 507	tc_skel_reset_all_seen(skel);508	ASSERT_OK(system(ping_cmd), ping_cmd);509 510	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");511	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");512cleanup:513	test_tc_link__destroy(skel);514	assert_mprog_count(target, 0);515}516 517void serial_test_tc_links_revision(void)518{519	test_tc_links_revision_target(BPF_TCX_INGRESS);520	test_tc_links_revision_target(BPF_TCX_EGRESS);521}522 523static void test_tc_chain_classic(int target, bool chain_tc_old)524{525	LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);526	LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);527	bool hook_created = false, tc_attached = false;528	LIBBPF_OPTS(bpf_tcx_opts, optl);529	__u32 pid1, pid2, pid3;530	struct test_tc_link *skel;531	struct bpf_link *link;532	int err;533 534	skel = test_tc_link__open();535	if (!ASSERT_OK_PTR(skel, "skel_open"))536		goto cleanup;537 538	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),539		  0, "tc1_attach_type");540	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),541		  0, "tc2_attach_type");542 543	err = test_tc_link__load(skel);544	if (!ASSERT_OK(err, "skel_load"))545		goto cleanup;546 547	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));548	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));549	pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));550 551	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");552	ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");553 554	assert_mprog_count(target, 0);555 556	if (chain_tc_old) {557		tc_hook.attach_point = target == BPF_TCX_INGRESS ?558				       BPF_TC_INGRESS : BPF_TC_EGRESS;559		err = bpf_tc_hook_create(&tc_hook);560		if (err == 0)561			hook_created = true;562		err = err == -EEXIST ? 0 : err;563		if (!ASSERT_OK(err, "bpf_tc_hook_create"))564			goto cleanup;565 566		tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3);567		err = bpf_tc_attach(&tc_hook, &tc_opts);568		if (!ASSERT_OK(err, "bpf_tc_attach"))569			goto cleanup;570		tc_attached = true;571	}572 573	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);574	if (!ASSERT_OK_PTR(link, "link_attach"))575		goto cleanup;576 577	skel->links.tc1 = link;578 579	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);580	if (!ASSERT_OK_PTR(link, "link_attach"))581		goto cleanup;582 583	skel->links.tc2 = link;584 585	assert_mprog_count(target, 2);586 587	tc_skel_reset_all_seen(skel);588	ASSERT_OK(system(ping_cmd), ping_cmd);589 590	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");591	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");592	ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");593 594	err = bpf_link__detach(skel->links.tc2);595	if (!ASSERT_OK(err, "prog_detach"))596		goto cleanup;597 598	assert_mprog_count(target, 1);599 600	tc_skel_reset_all_seen(skel);601	ASSERT_OK(system(ping_cmd), ping_cmd);602 603	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");604	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");605	ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");606cleanup:607	if (tc_attached) {608		tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;609		err = bpf_tc_detach(&tc_hook, &tc_opts);610		ASSERT_OK(err, "bpf_tc_detach");611	}612	if (hook_created) {613		tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;614		bpf_tc_hook_destroy(&tc_hook);615	}616	assert_mprog_count(target, 1);617	test_tc_link__destroy(skel);618	assert_mprog_count(target, 0);619}620 621void serial_test_tc_links_chain_classic(void)622{623	test_tc_chain_classic(BPF_TCX_INGRESS, false);624	test_tc_chain_classic(BPF_TCX_EGRESS, false);625	test_tc_chain_classic(BPF_TCX_INGRESS, true);626	test_tc_chain_classic(BPF_TCX_EGRESS, true);627}628 629static void test_tc_links_replace_target(int target)630{631	LIBBPF_OPTS(bpf_prog_query_opts, optq);632	LIBBPF_OPTS(bpf_tcx_opts, optl);633	__u32 pid1, pid2, pid3, lid1, lid2;634	__u32 prog_ids[4], link_ids[4];635	struct test_tc_link *skel;636	struct bpf_link *link;637	int err;638 639	skel = test_tc_link__open();640	if (!ASSERT_OK_PTR(skel, "skel_open"))641		goto cleanup;642 643	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),644		  0, "tc1_attach_type");645	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),646		  0, "tc2_attach_type");647	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),648		  0, "tc3_attach_type");649 650	err = test_tc_link__load(skel);651	if (!ASSERT_OK(err, "skel_load"))652		goto cleanup;653 654	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));655	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));656	pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));657 658	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");659	ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");660 661	assert_mprog_count(target, 0);662 663	optl.expected_revision = 1;664 665	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);666	if (!ASSERT_OK_PTR(link, "link_attach"))667		goto cleanup;668 669	skel->links.tc1 = link;670 671	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));672 673	assert_mprog_count(target, 1);674 675	LIBBPF_OPTS_RESET(optl,676		.flags = BPF_F_BEFORE,677		.relative_id = pid1,678		.expected_revision = 2,679	);680 681	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);682	if (!ASSERT_OK_PTR(link, "link_attach"))683		goto cleanup;684 685	skel->links.tc2 = link;686 687	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));688 689	assert_mprog_count(target, 2);690 691	optq.prog_ids = prog_ids;692	optq.link_ids = link_ids;693 694	memset(prog_ids, 0, sizeof(prog_ids));695	memset(link_ids, 0, sizeof(link_ids));696	optq.count = ARRAY_SIZE(prog_ids);697 698	err = bpf_prog_query_opts(loopback, target, &optq);699	if (!ASSERT_OK(err, "prog_query"))700		goto cleanup;701 702	ASSERT_EQ(optq.count, 2, "count");703	ASSERT_EQ(optq.revision, 3, "revision");704	ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");705	ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");706	ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");707	ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");708	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");709	ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");710 711	tc_skel_reset_all_seen(skel);712	ASSERT_OK(system(ping_cmd), ping_cmd);713 714	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");715	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");716	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");717 718	LIBBPF_OPTS_RESET(optl,719		.flags = BPF_F_REPLACE,720		.relative_fd = bpf_program__fd(skel->progs.tc2),721		.expected_revision = 3,722	);723 724	link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);725	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {726		bpf_link__destroy(link);727		goto cleanup;728	}729 730	assert_mprog_count(target, 2);731 732	LIBBPF_OPTS_RESET(optl,733		.flags = BPF_F_REPLACE | BPF_F_LINK,734		.relative_fd = bpf_link__fd(skel->links.tc2),735		.expected_revision = 3,736	);737 738	link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);739	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {740		bpf_link__destroy(link);741		goto cleanup;742	}743 744	assert_mprog_count(target, 2);745 746	LIBBPF_OPTS_RESET(optl,747		.flags = BPF_F_REPLACE | BPF_F_LINK | BPF_F_AFTER,748		.relative_id = lid2,749	);750 751	link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);752	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {753		bpf_link__destroy(link);754		goto cleanup;755	}756 757	assert_mprog_count(target, 2);758 759	err = bpf_link__update_program(skel->links.tc2, skel->progs.tc3);760	if (!ASSERT_OK(err, "link_update"))761		goto cleanup;762 763	assert_mprog_count(target, 2);764 765	memset(prog_ids, 0, sizeof(prog_ids));766	memset(link_ids, 0, sizeof(link_ids));767	optq.count = ARRAY_SIZE(prog_ids);768 769	err = bpf_prog_query_opts(loopback, target, &optq);770	if (!ASSERT_OK(err, "prog_query"))771		goto cleanup;772 773	ASSERT_EQ(optq.count, 2, "count");774	ASSERT_EQ(optq.revision, 4, "revision");775	ASSERT_EQ(optq.prog_ids[0], pid3, "prog_ids[0]");776	ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");777	ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");778	ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");779	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");780	ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");781 782	tc_skel_reset_all_seen(skel);783	ASSERT_OK(system(ping_cmd), ping_cmd);784 785	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");786	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");787	ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");788 789	err = bpf_link__detach(skel->links.tc2);790	if (!ASSERT_OK(err, "link_detach"))791		goto cleanup;792 793	assert_mprog_count(target, 1);794 795	memset(prog_ids, 0, sizeof(prog_ids));796	memset(link_ids, 0, sizeof(link_ids));797	optq.count = ARRAY_SIZE(prog_ids);798 799	err = bpf_prog_query_opts(loopback, target, &optq);800	if (!ASSERT_OK(err, "prog_query"))801		goto cleanup;802 803	ASSERT_EQ(optq.count, 1, "count");804	ASSERT_EQ(optq.revision, 5, "revision");805	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");806	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");807	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");808	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");809 810	tc_skel_reset_all_seen(skel);811	ASSERT_OK(system(ping_cmd), ping_cmd);812 813	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");814	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");815	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");816 817	err = bpf_link__update_program(skel->links.tc1, skel->progs.tc1);818	if (!ASSERT_OK(err, "link_update_self"))819		goto cleanup;820 821	assert_mprog_count(target, 1);822 823	memset(prog_ids, 0, sizeof(prog_ids));824	memset(link_ids, 0, sizeof(link_ids));825	optq.count = ARRAY_SIZE(prog_ids);826 827	err = bpf_prog_query_opts(loopback, target, &optq);828	if (!ASSERT_OK(err, "prog_query"))829		goto cleanup;830 831	ASSERT_EQ(optq.count, 1, "count");832	ASSERT_EQ(optq.revision, 5, "revision");833	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");834	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");835	ASSERT_EQ(optq.prog_ids[1], 0, "prog_ids[1]");836	ASSERT_EQ(optq.link_ids[1], 0, "link_ids[1]");837 838	tc_skel_reset_all_seen(skel);839	ASSERT_OK(system(ping_cmd), ping_cmd);840 841	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");842	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");843	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");844cleanup:845	test_tc_link__destroy(skel);846	assert_mprog_count(target, 0);847}848 849void serial_test_tc_links_replace(void)850{851	test_tc_links_replace_target(BPF_TCX_INGRESS);852	test_tc_links_replace_target(BPF_TCX_EGRESS);853}854 855static void test_tc_links_invalid_target(int target)856{857	LIBBPF_OPTS(bpf_prog_query_opts, optq);858	LIBBPF_OPTS(bpf_tcx_opts, optl);859	__u32 pid1, pid2, lid1;860	struct test_tc_link *skel;861	struct bpf_link *link;862	int err;863 864	skel = test_tc_link__open();865	if (!ASSERT_OK_PTR(skel, "skel_open"))866		goto cleanup;867 868	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),869		  0, "tc1_attach_type");870	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),871		  0, "tc2_attach_type");872 873	err = test_tc_link__load(skel);874	if (!ASSERT_OK(err, "skel_load"))875		goto cleanup;876 877	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));878	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));879 880	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");881 882	assert_mprog_count(target, 0);883 884	optl.flags = BPF_F_BEFORE | BPF_F_AFTER;885 886	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);887	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {888		bpf_link__destroy(link);889		goto cleanup;890	}891 892	assert_mprog_count(target, 0);893 894	LIBBPF_OPTS_RESET(optl,895		.flags = BPF_F_BEFORE | BPF_F_ID,896	);897 898	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);899	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {900		bpf_link__destroy(link);901		goto cleanup;902	}903 904	assert_mprog_count(target, 0);905 906	LIBBPF_OPTS_RESET(optl,907		.flags = BPF_F_AFTER | BPF_F_ID,908	);909 910	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);911	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {912		bpf_link__destroy(link);913		goto cleanup;914	}915 916	assert_mprog_count(target, 0);917 918	LIBBPF_OPTS_RESET(optl,919		.flags = BPF_F_ID,920	);921 922	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);923	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {924		bpf_link__destroy(link);925		goto cleanup;926	}927 928	assert_mprog_count(target, 0);929 930	LIBBPF_OPTS_RESET(optl,931		.flags = BPF_F_LINK,932		.relative_fd = bpf_program__fd(skel->progs.tc2),933	);934 935	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);936	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {937		bpf_link__destroy(link);938		goto cleanup;939	}940 941	assert_mprog_count(target, 0);942 943	LIBBPF_OPTS_RESET(optl,944		.flags = BPF_F_LINK,945	);946 947	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);948	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {949		bpf_link__destroy(link);950		goto cleanup;951	}952 953	assert_mprog_count(target, 0);954 955	LIBBPF_OPTS_RESET(optl,956		.relative_fd = bpf_program__fd(skel->progs.tc2),957	);958 959	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);960	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {961		bpf_link__destroy(link);962		goto cleanup;963	}964 965	assert_mprog_count(target, 0);966 967	LIBBPF_OPTS_RESET(optl,968		.flags = BPF_F_BEFORE | BPF_F_AFTER,969		.relative_fd = bpf_program__fd(skel->progs.tc2),970	);971 972	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);973	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {974		bpf_link__destroy(link);975		goto cleanup;976	}977 978	assert_mprog_count(target, 0);979 980	LIBBPF_OPTS_RESET(optl,981		.flags = BPF_F_BEFORE,982		.relative_fd = bpf_program__fd(skel->progs.tc1),983	);984 985	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);986	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {987		bpf_link__destroy(link);988		goto cleanup;989	}990 991	assert_mprog_count(target, 0);992 993	LIBBPF_OPTS_RESET(optl,994		.flags = BPF_F_ID,995		.relative_id = pid2,996	);997 998	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);999	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1000		bpf_link__destroy(link);1001		goto cleanup;1002	}1003 1004	assert_mprog_count(target, 0);1005 1006	LIBBPF_OPTS_RESET(optl,1007		.flags = BPF_F_ID,1008		.relative_id = 42,1009	);1010 1011	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1012	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1013		bpf_link__destroy(link);1014		goto cleanup;1015	}1016 1017	assert_mprog_count(target, 0);1018 1019	LIBBPF_OPTS_RESET(optl,1020		.flags = BPF_F_BEFORE,1021		.relative_fd = bpf_program__fd(skel->progs.tc1),1022	);1023 1024	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1025	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1026		bpf_link__destroy(link);1027		goto cleanup;1028	}1029 1030	assert_mprog_count(target, 0);1031 1032	LIBBPF_OPTS_RESET(optl,1033		.flags = BPF_F_BEFORE | BPF_F_LINK,1034		.relative_fd = bpf_program__fd(skel->progs.tc1),1035	);1036 1037	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1038	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1039		bpf_link__destroy(link);1040		goto cleanup;1041	}1042 1043	assert_mprog_count(target, 0);1044 1045	LIBBPF_OPTS_RESET(optl,1046		.flags = BPF_F_AFTER,1047		.relative_fd = bpf_program__fd(skel->progs.tc1),1048	);1049 1050	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1051	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1052		bpf_link__destroy(link);1053		goto cleanup;1054	}1055 1056	assert_mprog_count(target, 0);1057 1058	LIBBPF_OPTS_RESET(optl);1059 1060	link = bpf_program__attach_tcx(skel->progs.tc1, 0, &optl);1061	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1062		bpf_link__destroy(link);1063		goto cleanup;1064	}1065 1066	assert_mprog_count(target, 0);1067 1068	LIBBPF_OPTS_RESET(optl,1069		.flags = BPF_F_AFTER | BPF_F_LINK,1070		.relative_fd = bpf_program__fd(skel->progs.tc1),1071	);1072 1073	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1074	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1075		bpf_link__destroy(link);1076		goto cleanup;1077	}1078 1079	assert_mprog_count(target, 0);1080 1081	LIBBPF_OPTS_RESET(optl);1082 1083	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1084	if (!ASSERT_OK_PTR(link, "link_attach"))1085		goto cleanup;1086 1087	skel->links.tc1 = link;1088 1089	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));1090 1091	assert_mprog_count(target, 1);1092 1093	LIBBPF_OPTS_RESET(optl,1094		.flags = BPF_F_AFTER | BPF_F_LINK,1095		.relative_fd = bpf_program__fd(skel->progs.tc1),1096	);1097 1098	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1099	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1100		bpf_link__destroy(link);1101		goto cleanup;1102	}1103 1104	assert_mprog_count(target, 1);1105 1106	LIBBPF_OPTS_RESET(optl,1107		.flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,1108		.relative_id = ~0,1109	);1110 1111	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1112	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1113		bpf_link__destroy(link);1114		goto cleanup;1115	}1116 1117	assert_mprog_count(target, 1);1118 1119	LIBBPF_OPTS_RESET(optl,1120		.flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,1121		.relative_id = lid1,1122	);1123 1124	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1125	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1126		bpf_link__destroy(link);1127		goto cleanup;1128	}1129 1130	assert_mprog_count(target, 1);1131 1132	LIBBPF_OPTS_RESET(optl,1133		.flags = BPF_F_BEFORE | BPF_F_ID,1134		.relative_id = pid1,1135	);1136 1137	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1138	if (!ASSERT_ERR_PTR(link, "link_attach_should_fail")) {1139		bpf_link__destroy(link);1140		goto cleanup;1141	}1142	assert_mprog_count(target, 1);1143 1144	LIBBPF_OPTS_RESET(optl,1145		.flags = BPF_F_BEFORE | BPF_F_LINK | BPF_F_ID,1146		.relative_id = lid1,1147	);1148 1149	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1150	if (!ASSERT_OK_PTR(link, "link_attach"))1151		goto cleanup;1152 1153	skel->links.tc2 = link;1154 1155	assert_mprog_count(target, 2);1156cleanup:1157	test_tc_link__destroy(skel);1158	assert_mprog_count(target, 0);1159}1160 1161void serial_test_tc_links_invalid(void)1162{1163	test_tc_links_invalid_target(BPF_TCX_INGRESS);1164	test_tc_links_invalid_target(BPF_TCX_EGRESS);1165}1166 1167static void test_tc_links_prepend_target(int target)1168{1169	LIBBPF_OPTS(bpf_prog_query_opts, optq);1170	LIBBPF_OPTS(bpf_tcx_opts, optl);1171	__u32 prog_ids[5], link_ids[5];1172	__u32 pid1, pid2, pid3, pid4;1173	__u32 lid1, lid2, lid3, lid4;1174	struct test_tc_link *skel;1175	struct bpf_link *link;1176	int err;1177 1178	skel = test_tc_link__open();1179	if (!ASSERT_OK_PTR(skel, "skel_open"))1180		goto cleanup;1181 1182	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1183		  0, "tc1_attach_type");1184	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1185		  0, "tc2_attach_type");1186	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),1187		  0, "tc3_attach_type");1188	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1189		  0, "tc4_attach_type");1190 1191	err = test_tc_link__load(skel);1192	if (!ASSERT_OK(err, "skel_load"))1193		goto cleanup;1194 1195	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1196	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1197	pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1198	pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1199 1200	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1201	ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");1202	ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1203 1204	assert_mprog_count(target, 0);1205 1206	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1207	if (!ASSERT_OK_PTR(link, "link_attach"))1208		goto cleanup;1209 1210	skel->links.tc1 = link;1211 1212	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));1213 1214	assert_mprog_count(target, 1);1215 1216	LIBBPF_OPTS_RESET(optl,1217		.flags = BPF_F_BEFORE,1218	);1219 1220	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1221	if (!ASSERT_OK_PTR(link, "link_attach"))1222		goto cleanup;1223 1224	skel->links.tc2 = link;1225 1226	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));1227 1228	assert_mprog_count(target, 2);1229 1230	optq.prog_ids = prog_ids;1231	optq.link_ids = link_ids;1232 1233	memset(prog_ids, 0, sizeof(prog_ids));1234	memset(link_ids, 0, sizeof(link_ids));1235	optq.count = ARRAY_SIZE(prog_ids);1236 1237	err = bpf_prog_query_opts(loopback, target, &optq);1238	if (!ASSERT_OK(err, "prog_query"))1239		goto cleanup;1240 1241	ASSERT_EQ(optq.count, 2, "count");1242	ASSERT_EQ(optq.revision, 3, "revision");1243	ASSERT_EQ(optq.prog_ids[0], pid2, "prog_ids[0]");1244	ASSERT_EQ(optq.link_ids[0], lid2, "link_ids[0]");1245	ASSERT_EQ(optq.prog_ids[1], pid1, "prog_ids[1]");1246	ASSERT_EQ(optq.link_ids[1], lid1, "link_ids[1]");1247	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1248	ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");1249 1250	tc_skel_reset_all_seen(skel);1251	ASSERT_OK(system(ping_cmd), ping_cmd);1252 1253	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1254	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1255	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");1256	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1257 1258	LIBBPF_OPTS_RESET(optl,1259		.flags = BPF_F_BEFORE,1260	);1261 1262	link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);1263	if (!ASSERT_OK_PTR(link, "link_attach"))1264		goto cleanup;1265 1266	skel->links.tc3 = link;1267 1268	lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));1269 1270	LIBBPF_OPTS_RESET(optl,1271		.flags = BPF_F_BEFORE,1272	);1273 1274	link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);1275	if (!ASSERT_OK_PTR(link, "link_attach"))1276		goto cleanup;1277 1278	skel->links.tc4 = link;1279 1280	lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));1281 1282	assert_mprog_count(target, 4);1283 1284	memset(prog_ids, 0, sizeof(prog_ids));1285	memset(link_ids, 0, sizeof(link_ids));1286	optq.count = ARRAY_SIZE(prog_ids);1287 1288	err = bpf_prog_query_opts(loopback, target, &optq);1289	if (!ASSERT_OK(err, "prog_query"))1290		goto cleanup;1291 1292	ASSERT_EQ(optq.count, 4, "count");1293	ASSERT_EQ(optq.revision, 5, "revision");1294	ASSERT_EQ(optq.prog_ids[0], pid4, "prog_ids[0]");1295	ASSERT_EQ(optq.link_ids[0], lid4, "link_ids[0]");1296	ASSERT_EQ(optq.prog_ids[1], pid3, "prog_ids[1]");1297	ASSERT_EQ(optq.link_ids[1], lid3, "link_ids[1]");1298	ASSERT_EQ(optq.prog_ids[2], pid2, "prog_ids[2]");1299	ASSERT_EQ(optq.link_ids[2], lid2, "link_ids[2]");1300	ASSERT_EQ(optq.prog_ids[3], pid1, "prog_ids[3]");1301	ASSERT_EQ(optq.link_ids[3], lid1, "link_ids[3]");1302	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1303	ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");1304 1305	tc_skel_reset_all_seen(skel);1306	ASSERT_OK(system(ping_cmd), ping_cmd);1307 1308	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1309	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1310	ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");1311	ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");1312cleanup:1313	test_tc_link__destroy(skel);1314	assert_mprog_count(target, 0);1315}1316 1317void serial_test_tc_links_prepend(void)1318{1319	test_tc_links_prepend_target(BPF_TCX_INGRESS);1320	test_tc_links_prepend_target(BPF_TCX_EGRESS);1321}1322 1323static void test_tc_links_append_target(int target)1324{1325	LIBBPF_OPTS(bpf_prog_query_opts, optq);1326	LIBBPF_OPTS(bpf_tcx_opts, optl);1327	__u32 prog_ids[5], link_ids[5];1328	__u32 pid1, pid2, pid3, pid4;1329	__u32 lid1, lid2, lid3, lid4;1330	struct test_tc_link *skel;1331	struct bpf_link *link;1332	int err;1333 1334	skel = test_tc_link__open();1335	if (!ASSERT_OK_PTR(skel, "skel_open"))1336		goto cleanup;1337 1338	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1339		  0, "tc1_attach_type");1340	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1341		  0, "tc2_attach_type");1342	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),1343		  0, "tc3_attach_type");1344	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1345		  0, "tc4_attach_type");1346 1347	err = test_tc_link__load(skel);1348	if (!ASSERT_OK(err, "skel_load"))1349		goto cleanup;1350 1351	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1352	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1353	pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1354	pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1355 1356	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1357	ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");1358	ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1359 1360	assert_mprog_count(target, 0);1361 1362	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1363	if (!ASSERT_OK_PTR(link, "link_attach"))1364		goto cleanup;1365 1366	skel->links.tc1 = link;1367 1368	lid1 = id_from_link_fd(bpf_link__fd(skel->links.tc1));1369 1370	assert_mprog_count(target, 1);1371 1372	LIBBPF_OPTS_RESET(optl,1373		.flags = BPF_F_AFTER,1374	);1375 1376	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1377	if (!ASSERT_OK_PTR(link, "link_attach"))1378		goto cleanup;1379 1380	skel->links.tc2 = link;1381 1382	lid2 = id_from_link_fd(bpf_link__fd(skel->links.tc2));1383 1384	assert_mprog_count(target, 2);1385 1386	optq.prog_ids = prog_ids;1387	optq.link_ids = link_ids;1388 1389	memset(prog_ids, 0, sizeof(prog_ids));1390	memset(link_ids, 0, sizeof(link_ids));1391	optq.count = ARRAY_SIZE(prog_ids);1392 1393	err = bpf_prog_query_opts(loopback, target, &optq);1394	if (!ASSERT_OK(err, "prog_query"))1395		goto cleanup;1396 1397	ASSERT_EQ(optq.count, 2, "count");1398	ASSERT_EQ(optq.revision, 3, "revision");1399	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");1400	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");1401	ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");1402	ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");1403	ASSERT_EQ(optq.prog_ids[2], 0, "prog_ids[2]");1404	ASSERT_EQ(optq.link_ids[2], 0, "link_ids[2]");1405 1406	tc_skel_reset_all_seen(skel);1407	ASSERT_OK(system(ping_cmd), ping_cmd);1408 1409	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1410	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1411	ASSERT_EQ(skel->bss->seen_tc3, false, "seen_tc3");1412	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1413 1414	LIBBPF_OPTS_RESET(optl,1415		.flags = BPF_F_AFTER,1416	);1417 1418	link = bpf_program__attach_tcx(skel->progs.tc3, loopback, &optl);1419	if (!ASSERT_OK_PTR(link, "link_attach"))1420		goto cleanup;1421 1422	skel->links.tc3 = link;1423 1424	lid3 = id_from_link_fd(bpf_link__fd(skel->links.tc3));1425 1426	LIBBPF_OPTS_RESET(optl,1427		.flags = BPF_F_AFTER,1428	);1429 1430	link = bpf_program__attach_tcx(skel->progs.tc4, loopback, &optl);1431	if (!ASSERT_OK_PTR(link, "link_attach"))1432		goto cleanup;1433 1434	skel->links.tc4 = link;1435 1436	lid4 = id_from_link_fd(bpf_link__fd(skel->links.tc4));1437 1438	assert_mprog_count(target, 4);1439 1440	memset(prog_ids, 0, sizeof(prog_ids));1441	memset(link_ids, 0, sizeof(link_ids));1442	optq.count = ARRAY_SIZE(prog_ids);1443 1444	err = bpf_prog_query_opts(loopback, target, &optq);1445	if (!ASSERT_OK(err, "prog_query"))1446		goto cleanup;1447 1448	ASSERT_EQ(optq.count, 4, "count");1449	ASSERT_EQ(optq.revision, 5, "revision");1450	ASSERT_EQ(optq.prog_ids[0], pid1, "prog_ids[0]");1451	ASSERT_EQ(optq.link_ids[0], lid1, "link_ids[0]");1452	ASSERT_EQ(optq.prog_ids[1], pid2, "prog_ids[1]");1453	ASSERT_EQ(optq.link_ids[1], lid2, "link_ids[1]");1454	ASSERT_EQ(optq.prog_ids[2], pid3, "prog_ids[2]");1455	ASSERT_EQ(optq.link_ids[2], lid3, "link_ids[2]");1456	ASSERT_EQ(optq.prog_ids[3], pid4, "prog_ids[3]");1457	ASSERT_EQ(optq.link_ids[3], lid4, "link_ids[3]");1458	ASSERT_EQ(optq.prog_ids[4], 0, "prog_ids[4]");1459	ASSERT_EQ(optq.link_ids[4], 0, "link_ids[4]");1460 1461	tc_skel_reset_all_seen(skel);1462	ASSERT_OK(system(ping_cmd), ping_cmd);1463 1464	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1465	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1466	ASSERT_EQ(skel->bss->seen_tc3, true, "seen_tc3");1467	ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");1468cleanup:1469	test_tc_link__destroy(skel);1470	assert_mprog_count(target, 0);1471}1472 1473void serial_test_tc_links_append(void)1474{1475	test_tc_links_append_target(BPF_TCX_INGRESS);1476	test_tc_links_append_target(BPF_TCX_EGRESS);1477}1478 1479static void test_tc_links_dev_cleanup_target(int target)1480{1481	LIBBPF_OPTS(bpf_tcx_opts, optl);1482	LIBBPF_OPTS(bpf_prog_query_opts, optq);1483	__u32 pid1, pid2, pid3, pid4;1484	struct test_tc_link *skel;1485	struct bpf_link *link;1486	int err, ifindex;1487 1488	ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");1489	ifindex = if_nametoindex("tcx_opts1");1490	ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");1491 1492	skel = test_tc_link__open();1493	if (!ASSERT_OK_PTR(skel, "skel_open"))1494		goto cleanup;1495 1496	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1497		  0, "tc1_attach_type");1498	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1499		  0, "tc2_attach_type");1500	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),1501		  0, "tc3_attach_type");1502	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1503		  0, "tc4_attach_type");1504 1505	err = test_tc_link__load(skel);1506	if (!ASSERT_OK(err, "skel_load"))1507		goto cleanup;1508 1509	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1510	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1511	pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1512	pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1513 1514	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1515	ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");1516	ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1517 1518	assert_mprog_count(target, 0);1519 1520	link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);1521	if (!ASSERT_OK_PTR(link, "link_attach"))1522		goto cleanup;1523 1524	skel->links.tc1 = link;1525 1526	assert_mprog_count_ifindex(ifindex, target, 1);1527 1528	link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);1529	if (!ASSERT_OK_PTR(link, "link_attach"))1530		goto cleanup;1531 1532	skel->links.tc2 = link;1533 1534	assert_mprog_count_ifindex(ifindex, target, 2);1535 1536	link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);1537	if (!ASSERT_OK_PTR(link, "link_attach"))1538		goto cleanup;1539 1540	skel->links.tc3 = link;1541 1542	assert_mprog_count_ifindex(ifindex, target, 3);1543 1544	link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);1545	if (!ASSERT_OK_PTR(link, "link_attach"))1546		goto cleanup;1547 1548	skel->links.tc4 = link;1549 1550	assert_mprog_count_ifindex(ifindex, target, 4);1551 1552	ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1553	ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1554	ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1555 1556	ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex");1557	ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex");1558	ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex");1559	ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex");1560 1561	test_tc_link__destroy(skel);1562	return;1563cleanup:1564	test_tc_link__destroy(skel);1565 1566	ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1567	ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1568	ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1569}1570 1571void serial_test_tc_links_dev_cleanup(void)1572{1573	test_tc_links_dev_cleanup_target(BPF_TCX_INGRESS);1574	test_tc_links_dev_cleanup_target(BPF_TCX_EGRESS);1575}1576 1577static void test_tc_chain_mixed(int target)1578{1579	LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);1580	LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);1581	LIBBPF_OPTS(bpf_tcx_opts, optl);1582	struct test_tc_link *skel;1583	struct bpf_link *link;1584	__u32 pid1, pid2, pid3;1585	int err;1586 1587	skel = test_tc_link__open();1588	if (!ASSERT_OK_PTR(skel, "skel_open"))1589		goto cleanup;1590 1591	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1592		  0, "tc4_attach_type");1593	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc5, target),1594		  0, "tc5_attach_type");1595	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc6, target),1596		  0, "tc6_attach_type");1597 1598	err = test_tc_link__load(skel);1599	if (!ASSERT_OK(err, "skel_load"))1600		goto cleanup;1601 1602	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1603	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc5));1604	pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc6));1605 1606	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1607	ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1608 1609	assert_mprog_count(target, 0);1610 1611	tc_hook.attach_point = target == BPF_TCX_INGRESS ?1612			       BPF_TC_INGRESS : BPF_TC_EGRESS;1613	err = bpf_tc_hook_create(&tc_hook);1614	err = err == -EEXIST ? 0 : err;1615	if (!ASSERT_OK(err, "bpf_tc_hook_create"))1616		goto cleanup;1617 1618	tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);1619	err = bpf_tc_attach(&tc_hook, &tc_opts);1620	if (!ASSERT_OK(err, "bpf_tc_attach"))1621		goto cleanup;1622 1623	link = bpf_program__attach_tcx(skel->progs.tc6, loopback, &optl);1624	if (!ASSERT_OK_PTR(link, "link_attach"))1625		goto cleanup;1626 1627	skel->links.tc6 = link;1628 1629	assert_mprog_count(target, 1);1630 1631	tc_skel_reset_all_seen(skel);1632	ASSERT_OK(system(ping_cmd), ping_cmd);1633 1634	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1635	ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");1636	ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");1637 1638	err = bpf_link__update_program(skel->links.tc6, skel->progs.tc4);1639	if (!ASSERT_OK(err, "link_update"))1640		goto cleanup;1641 1642	assert_mprog_count(target, 1);1643 1644	tc_skel_reset_all_seen(skel);1645	ASSERT_OK(system(ping_cmd), ping_cmd);1646 1647	ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");1648	ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");1649	ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");1650 1651	err = bpf_link__detach(skel->links.tc6);1652	if (!ASSERT_OK(err, "prog_detach"))1653		goto cleanup;1654 1655	assert_mprog_count(target, 0);1656 1657	tc_skel_reset_all_seen(skel);1658	ASSERT_OK(system(ping_cmd), ping_cmd);1659 1660	ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");1661	ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");1662	ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");1663 1664cleanup:1665	tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;1666	err = bpf_tc_detach(&tc_hook, &tc_opts);1667	ASSERT_OK(err, "bpf_tc_detach");1668 1669	tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;1670	bpf_tc_hook_destroy(&tc_hook);1671 1672	test_tc_link__destroy(skel);1673}1674 1675void serial_test_tc_links_chain_mixed(void)1676{1677	test_tc_chain_mixed(BPF_TCX_INGRESS);1678	test_tc_chain_mixed(BPF_TCX_EGRESS);1679}1680 1681static void test_tc_links_ingress(int target, bool chain_tc_old,1682				  bool tcx_teardown_first)1683{1684	LIBBPF_OPTS(bpf_tc_opts, tc_opts,1685		.handle		= 1,1686		.priority	= 1,1687	);1688	LIBBPF_OPTS(bpf_tc_hook, tc_hook,1689		.ifindex	= loopback,1690		.attach_point	= BPF_TC_CUSTOM,1691		.parent		= TC_H_INGRESS,1692	);1693	bool hook_created = false, tc_attached = false;1694	LIBBPF_OPTS(bpf_tcx_opts, optl);1695	__u32 pid1, pid2, pid3;1696	struct test_tc_link *skel;1697	struct bpf_link *link;1698	int err;1699 1700	skel = test_tc_link__open();1701	if (!ASSERT_OK_PTR(skel, "skel_open"))1702		goto cleanup;1703 1704	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1705		  0, "tc1_attach_type");1706	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1707		  0, "tc2_attach_type");1708 1709	err = test_tc_link__load(skel);1710	if (!ASSERT_OK(err, "skel_load"))1711		goto cleanup;1712 1713	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1714	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1715	pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1716 1717	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1718	ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1719 1720	assert_mprog_count(target, 0);1721 1722	if (chain_tc_old) {1723		ASSERT_OK(system("tc qdisc add dev lo ingress"), "add_ingress");1724		hook_created = true;1725 1726		tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3);1727		err = bpf_tc_attach(&tc_hook, &tc_opts);1728		if (!ASSERT_OK(err, "bpf_tc_attach"))1729			goto cleanup;1730		tc_attached = true;1731	}1732 1733	link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);1734	if (!ASSERT_OK_PTR(link, "link_attach"))1735		goto cleanup;1736 1737	skel->links.tc1 = link;1738 1739	link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);1740	if (!ASSERT_OK_PTR(link, "link_attach"))1741		goto cleanup;1742 1743	skel->links.tc2 = link;1744 1745	assert_mprog_count(target, 2);1746 1747	tc_skel_reset_all_seen(skel);1748	ASSERT_OK(system(ping_cmd), ping_cmd);1749 1750	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1751	ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");1752	ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");1753 1754	err = bpf_link__detach(skel->links.tc2);1755	if (!ASSERT_OK(err, "prog_detach"))1756		goto cleanup;1757 1758	assert_mprog_count(target, 1);1759 1760	tc_skel_reset_all_seen(skel);1761	ASSERT_OK(system(ping_cmd), ping_cmd);1762 1763	ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");1764	ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");1765	ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");1766cleanup:1767	if (tc_attached) {1768		tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;1769		err = bpf_tc_detach(&tc_hook, &tc_opts);1770		ASSERT_OK(err, "bpf_tc_detach");1771	}1772	ASSERT_OK(system(ping_cmd), ping_cmd);1773	assert_mprog_count(target, 1);1774	if (hook_created && tcx_teardown_first)1775		ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");1776	ASSERT_OK(system(ping_cmd), ping_cmd);1777	test_tc_link__destroy(skel);1778	ASSERT_OK(system(ping_cmd), ping_cmd);1779	if (hook_created && !tcx_teardown_first)1780		ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");1781	ASSERT_OK(system(ping_cmd), ping_cmd);1782	assert_mprog_count(target, 0);1783}1784 1785void serial_test_tc_links_ingress(void)1786{1787	test_tc_links_ingress(BPF_TCX_INGRESS, true, true);1788	test_tc_links_ingress(BPF_TCX_INGRESS, true, false);1789	test_tc_links_ingress(BPF_TCX_INGRESS, false, false);1790}1791 1792struct qdisc_req {1793	struct nlmsghdr  n;1794	struct tcmsg     t;1795	char             buf[1024];1796};1797 1798static int qdisc_replace(int ifindex, const char *kind, bool block)1799{1800	struct rtnl_handle rth = { .fd = -1 };1801	struct qdisc_req req;1802	int err;1803 1804	err = rtnl_open(&rth, 0);1805	if (!ASSERT_OK(err, "open_rtnetlink"))1806		return err;1807 1808	memset(&req, 0, sizeof(req));1809	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));1810	req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE | NLM_F_REQUEST;1811	req.n.nlmsg_type = RTM_NEWQDISC;1812	req.t.tcm_family = AF_UNSPEC;1813	req.t.tcm_ifindex = ifindex;1814	req.t.tcm_parent = 0xfffffff1;1815 1816	addattr_l(&req.n, sizeof(req), TCA_KIND, kind, strlen(kind) + 1);1817	if (block)1818		addattr32(&req.n, sizeof(req), TCA_INGRESS_BLOCK, 1);1819 1820	err = rtnl_talk(&rth, &req.n, NULL);1821	ASSERT_OK(err, "talk_rtnetlink");1822	rtnl_close(&rth);1823	return err;1824}1825 1826void serial_test_tc_links_dev_chain0(void)1827{1828	int err, ifindex;1829 1830	ASSERT_OK(system("ip link add dev foo type veth peer name bar"), "add veth");1831	ifindex = if_nametoindex("foo");1832	ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");1833	err = qdisc_replace(ifindex, "ingress", true);1834	if (!ASSERT_OK(err, "attaching ingress"))1835		goto cleanup;1836	ASSERT_OK(system("tc filter add block 1 matchall action skbmod swap mac"), "add block");1837	err = qdisc_replace(ifindex, "clsact", false);1838	if (!ASSERT_OK(err, "attaching clsact"))1839		goto cleanup;1840	/* Heuristic: kern_sync_rcu() alone does not work; a wait-time of ~5s1841	 * triggered the issue without the fix reliably 100% of the time.1842	 */1843	sleep(5);1844	ASSERT_OK(system("tc filter add dev foo ingress matchall action skbmod swap mac"), "add filter");1845cleanup:1846	ASSERT_OK(system("ip link del dev foo"), "del veth");1847	ASSERT_EQ(if_nametoindex("foo"), 0, "foo removed");1848	ASSERT_EQ(if_nametoindex("bar"), 0, "bar removed");1849}1850 1851static void test_tc_links_dev_mixed(int target)1852{1853	LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);1854	LIBBPF_OPTS(bpf_tc_hook, tc_hook);1855	LIBBPF_OPTS(bpf_tcx_opts, optl);1856	__u32 pid1, pid2, pid3, pid4;1857	struct test_tc_link *skel;1858	struct bpf_link *link;1859	int err, ifindex;1860 1861	ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");1862	ifindex = if_nametoindex("tcx_opts1");1863	ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");1864 1865	skel = test_tc_link__open();1866	if (!ASSERT_OK_PTR(skel, "skel_open"))1867		goto cleanup;1868 1869	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),1870		  0, "tc1_attach_type");1871	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),1872		  0, "tc2_attach_type");1873	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),1874		  0, "tc3_attach_type");1875	ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),1876		  0, "tc4_attach_type");1877 1878	err = test_tc_link__load(skel);1879	if (!ASSERT_OK(err, "skel_load"))1880		goto cleanup;1881 1882	pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));1883	pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));1884	pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));1885	pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));1886 1887	ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");1888	ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");1889	ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");1890 1891	assert_mprog_count(target, 0);1892 1893	link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);1894	if (!ASSERT_OK_PTR(link, "link_attach"))1895		goto cleanup;1896 1897	skel->links.tc1 = link;1898 1899	assert_mprog_count_ifindex(ifindex, target, 1);1900 1901	link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);1902	if (!ASSERT_OK_PTR(link, "link_attach"))1903		goto cleanup;1904 1905	skel->links.tc2 = link;1906 1907	assert_mprog_count_ifindex(ifindex, target, 2);1908 1909	link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);1910	if (!ASSERT_OK_PTR(link, "link_attach"))1911		goto cleanup;1912 1913	skel->links.tc3 = link;1914 1915	assert_mprog_count_ifindex(ifindex, target, 3);1916 1917	link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);1918	if (!ASSERT_OK_PTR(link, "link_attach"))1919		goto cleanup;1920 1921	skel->links.tc4 = link;1922 1923	assert_mprog_count_ifindex(ifindex, target, 4);1924 1925	tc_hook.ifindex = ifindex;1926	tc_hook.attach_point = target == BPF_TCX_INGRESS ?1927			       BPF_TC_INGRESS : BPF_TC_EGRESS;1928 1929	err = bpf_tc_hook_create(&tc_hook);1930	err = err == -EEXIST ? 0 : err;1931	if (!ASSERT_OK(err, "bpf_tc_hook_create"))1932		goto cleanup;1933 1934	tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);1935	err = bpf_tc_attach(&tc_hook, &tc_opts);1936	if (!ASSERT_OK(err, "bpf_tc_attach"))1937		goto cleanup;1938 1939	ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1940	ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1941	ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1942 1943	ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex");1944	ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex");1945	ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex");1946	ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex");1947 1948	test_tc_link__destroy(skel);1949	return;1950cleanup:1951	test_tc_link__destroy(skel);1952 1953	ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");1954	ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");1955	ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");1956}1957 1958void serial_test_tc_links_dev_mixed(void)1959{1960	test_tc_links_dev_mixed(BPF_TCX_INGRESS);1961	test_tc_links_dev_mixed(BPF_TCX_EGRESS);1962}1963