@@ -2462,3 +2462,170 @@ void serial_test_tc_opts_max(void)
24622462 test_tc_opts_max_target (BPF_TCX_INGRESS , BPF_F_AFTER , true);
24632463 test_tc_opts_max_target (BPF_TCX_EGRESS , BPF_F_AFTER , false);
24642464}
2465+
2466+ static void test_tc_opts_query_target (int target )
2467+ {
2468+ const size_t attr_size = offsetofend (union bpf_attr , query );
2469+ LIBBPF_OPTS (bpf_prog_attach_opts , opta );
2470+ LIBBPF_OPTS (bpf_prog_detach_opts , optd );
2471+ LIBBPF_OPTS (bpf_prog_query_opts , optq );
2472+ __u32 fd1 , fd2 , fd3 , fd4 , id1 , id2 , id3 , id4 ;
2473+ struct test_tc_link * skel ;
2474+ union bpf_attr attr ;
2475+ __u32 prog_ids [5 ];
2476+ int err ;
2477+
2478+ skel = test_tc_link__open_and_load ();
2479+ if (!ASSERT_OK_PTR (skel , "skel_load" ))
2480+ goto cleanup ;
2481+
2482+ fd1 = bpf_program__fd (skel -> progs .tc1 );
2483+ fd2 = bpf_program__fd (skel -> progs .tc2 );
2484+ fd3 = bpf_program__fd (skel -> progs .tc3 );
2485+ fd4 = bpf_program__fd (skel -> progs .tc4 );
2486+
2487+ id1 = id_from_prog_fd (fd1 );
2488+ id2 = id_from_prog_fd (fd2 );
2489+ id3 = id_from_prog_fd (fd3 );
2490+ id4 = id_from_prog_fd (fd4 );
2491+
2492+ assert_mprog_count (target , 0 );
2493+
2494+ LIBBPF_OPTS_RESET (opta ,
2495+ .expected_revision = 1 ,
2496+ );
2497+
2498+ err = bpf_prog_attach_opts (fd1 , loopback , target , & opta );
2499+ if (!ASSERT_EQ (err , 0 , "prog_attach" ))
2500+ goto cleanup ;
2501+
2502+ assert_mprog_count (target , 1 );
2503+
2504+ LIBBPF_OPTS_RESET (opta ,
2505+ .expected_revision = 2 ,
2506+ );
2507+
2508+ err = bpf_prog_attach_opts (fd2 , loopback , target , & opta );
2509+ if (!ASSERT_EQ (err , 0 , "prog_attach" ))
2510+ goto cleanup1 ;
2511+
2512+ assert_mprog_count (target , 2 );
2513+
2514+ LIBBPF_OPTS_RESET (opta ,
2515+ .expected_revision = 3 ,
2516+ );
2517+
2518+ err = bpf_prog_attach_opts (fd3 , loopback , target , & opta );
2519+ if (!ASSERT_EQ (err , 0 , "prog_attach" ))
2520+ goto cleanup2 ;
2521+
2522+ assert_mprog_count (target , 3 );
2523+
2524+ LIBBPF_OPTS_RESET (opta ,
2525+ .expected_revision = 4 ,
2526+ );
2527+
2528+ err = bpf_prog_attach_opts (fd4 , loopback , target , & opta );
2529+ if (!ASSERT_EQ (err , 0 , "prog_attach" ))
2530+ goto cleanup3 ;
2531+
2532+ assert_mprog_count (target , 4 );
2533+
2534+ /* Test 1: Double query via libbpf API */
2535+ err = bpf_prog_query_opts (loopback , target , & optq );
2536+ if (!ASSERT_OK (err , "prog_query" ))
2537+ goto cleanup4 ;
2538+
2539+ ASSERT_EQ (optq .count , 4 , "count" );
2540+ ASSERT_EQ (optq .revision , 5 , "revision" );
2541+ ASSERT_EQ (optq .prog_ids , NULL , "prog_ids" );
2542+ ASSERT_EQ (optq .link_ids , NULL , "link_ids" );
2543+
2544+ memset (prog_ids , 0 , sizeof (prog_ids ));
2545+ optq .prog_ids = prog_ids ;
2546+
2547+ err = bpf_prog_query_opts (loopback , target , & optq );
2548+ if (!ASSERT_OK (err , "prog_query" ))
2549+ goto cleanup4 ;
2550+
2551+ ASSERT_EQ (optq .count , 4 , "count" );
2552+ ASSERT_EQ (optq .revision , 5 , "revision" );
2553+ ASSERT_EQ (optq .prog_ids [0 ], id1 , "prog_ids[0]" );
2554+ ASSERT_EQ (optq .prog_ids [1 ], id2 , "prog_ids[1]" );
2555+ ASSERT_EQ (optq .prog_ids [2 ], id3 , "prog_ids[2]" );
2556+ ASSERT_EQ (optq .prog_ids [3 ], id4 , "prog_ids[3]" );
2557+ ASSERT_EQ (optq .prog_ids [4 ], 0 , "prog_ids[4]" );
2558+ ASSERT_EQ (optq .link_ids , NULL , "link_ids" );
2559+
2560+ /* Test 2: Double query via bpf_attr & bpf(2) directly */
2561+ memset (& attr , 0 , attr_size );
2562+ attr .query .target_ifindex = loopback ;
2563+ attr .query .attach_type = target ;
2564+
2565+ err = syscall (__NR_bpf , BPF_PROG_QUERY , & attr , attr_size );
2566+ if (!ASSERT_OK (err , "prog_query" ))
2567+ goto cleanup4 ;
2568+
2569+ ASSERT_EQ (attr .query .count , 4 , "count" );
2570+ ASSERT_EQ (attr .query .revision , 5 , "revision" );
2571+ ASSERT_EQ (attr .query .query_flags , 0 , "query_flags" );
2572+ ASSERT_EQ (attr .query .attach_flags , 0 , "attach_flags" );
2573+ ASSERT_EQ (attr .query .target_ifindex , loopback , "target_ifindex" );
2574+ ASSERT_EQ (attr .query .attach_type , target , "attach_type" );
2575+ ASSERT_EQ (attr .query .prog_ids , 0 , "prog_ids" );
2576+ ASSERT_EQ (attr .query .prog_attach_flags , 0 , "prog_attach_flags" );
2577+ ASSERT_EQ (attr .query .link_ids , 0 , "link_ids" );
2578+ ASSERT_EQ (attr .query .link_attach_flags , 0 , "link_attach_flags" );
2579+
2580+ memset (prog_ids , 0 , sizeof (prog_ids ));
2581+ attr .query .prog_ids = ptr_to_u64 (prog_ids );
2582+
2583+ err = syscall (__NR_bpf , BPF_PROG_QUERY , & attr , attr_size );
2584+ if (!ASSERT_OK (err , "prog_query" ))
2585+ goto cleanup4 ;
2586+
2587+ ASSERT_EQ (attr .query .count , 4 , "count" );
2588+ ASSERT_EQ (attr .query .revision , 5 , "revision" );
2589+ ASSERT_EQ (attr .query .query_flags , 0 , "query_flags" );
2590+ ASSERT_EQ (attr .query .attach_flags , 0 , "attach_flags" );
2591+ ASSERT_EQ (attr .query .target_ifindex , loopback , "target_ifindex" );
2592+ ASSERT_EQ (attr .query .attach_type , target , "attach_type" );
2593+ ASSERT_EQ (attr .query .prog_ids , ptr_to_u64 (prog_ids ), "prog_ids" );
2594+ ASSERT_EQ (prog_ids [0 ], id1 , "prog_ids[0]" );
2595+ ASSERT_EQ (prog_ids [1 ], id2 , "prog_ids[1]" );
2596+ ASSERT_EQ (prog_ids [2 ], id3 , "prog_ids[2]" );
2597+ ASSERT_EQ (prog_ids [3 ], id4 , "prog_ids[3]" );
2598+ ASSERT_EQ (prog_ids [4 ], 0 , "prog_ids[4]" );
2599+ ASSERT_EQ (attr .query .prog_attach_flags , 0 , "prog_attach_flags" );
2600+ ASSERT_EQ (attr .query .link_ids , 0 , "link_ids" );
2601+ ASSERT_EQ (attr .query .link_attach_flags , 0 , "link_attach_flags" );
2602+
2603+ cleanup4 :
2604+ err = bpf_prog_detach_opts (fd4 , loopback , target , & optd );
2605+ ASSERT_OK (err , "prog_detach" );
2606+ assert_mprog_count (target , 3 );
2607+
2608+ cleanup3 :
2609+ err = bpf_prog_detach_opts (fd3 , loopback , target , & optd );
2610+ ASSERT_OK (err , "prog_detach" );
2611+ assert_mprog_count (target , 2 );
2612+
2613+ cleanup2 :
2614+ err = bpf_prog_detach_opts (fd2 , loopback , target , & optd );
2615+ ASSERT_OK (err , "prog_detach" );
2616+ assert_mprog_count (target , 1 );
2617+
2618+ cleanup1 :
2619+ err = bpf_prog_detach_opts (fd1 , loopback , target , & optd );
2620+ ASSERT_OK (err , "prog_detach" );
2621+ assert_mprog_count (target , 0 );
2622+
2623+ cleanup :
2624+ test_tc_link__destroy (skel );
2625+ }
2626+
2627+ void serial_test_tc_opts_query (void )
2628+ {
2629+ test_tc_opts_query_target (BPF_TCX_INGRESS );
2630+ test_tc_opts_query_target (BPF_TCX_EGRESS );
2631+ }
0 commit comments