@@ -2378,3 +2378,87 @@ void serial_test_tc_opts_chain_mixed(void)
2378
2378
test_tc_chain_mixed (BPF_TCX_INGRESS );
2379
2379
test_tc_chain_mixed (BPF_TCX_EGRESS );
2380
2380
}
2381
+
2382
+ static int generate_dummy_prog (void )
2383
+ {
2384
+ const struct bpf_insn prog_insns [] = {
2385
+ BPF_MOV64_IMM (BPF_REG_0 , 0 ),
2386
+ BPF_EXIT_INSN (),
2387
+ };
2388
+ const size_t prog_insn_cnt = sizeof (prog_insns ) / sizeof (struct bpf_insn );
2389
+ LIBBPF_OPTS (bpf_prog_load_opts , opts );
2390
+ const size_t log_buf_sz = 256 ;
2391
+ char * log_buf ;
2392
+ int fd = -1 ;
2393
+
2394
+ log_buf = malloc (log_buf_sz );
2395
+ if (!ASSERT_OK_PTR (log_buf , "log_buf_alloc" ))
2396
+ return fd ;
2397
+ opts .log_buf = log_buf ;
2398
+ opts .log_size = log_buf_sz ;
2399
+
2400
+ log_buf [0 ] = '\0' ;
2401
+ opts .log_level = 0 ;
2402
+ fd = bpf_prog_load (BPF_PROG_TYPE_SCHED_CLS , "tcx_prog" , "GPL" ,
2403
+ prog_insns , prog_insn_cnt , & opts );
2404
+ ASSERT_STREQ (log_buf , "" , "log_0" );
2405
+ ASSERT_GE (fd , 0 , "prog_fd" );
2406
+ free (log_buf );
2407
+ return fd ;
2408
+ }
2409
+
2410
+ static void test_tc_opts_max_target (int target , int flags , bool relative )
2411
+ {
2412
+ int err , ifindex , i , prog_fd , last_fd = -1 ;
2413
+ LIBBPF_OPTS (bpf_prog_attach_opts , opta );
2414
+ const int max_progs = 63 ;
2415
+
2416
+ ASSERT_OK (system ("ip link add dev tcx_opts1 type veth peer name tcx_opts2" ), "add veth" );
2417
+ ifindex = if_nametoindex ("tcx_opts1" );
2418
+ ASSERT_NEQ (ifindex , 0 , "non_zero_ifindex" );
2419
+
2420
+ assert_mprog_count_ifindex (ifindex , target , 0 );
2421
+
2422
+ for (i = 0 ; i < max_progs ; i ++ ) {
2423
+ prog_fd = generate_dummy_prog ();
2424
+ if (!ASSERT_GE (prog_fd , 0 , "dummy_prog" ))
2425
+ goto cleanup ;
2426
+ err = bpf_prog_attach_opts (prog_fd , ifindex , target , & opta );
2427
+ if (!ASSERT_EQ (err , 0 , "prog_attach" ))
2428
+ goto cleanup ;
2429
+ assert_mprog_count_ifindex (ifindex , target , i + 1 );
2430
+ if (i == max_progs - 1 && relative )
2431
+ last_fd = prog_fd ;
2432
+ else
2433
+ close (prog_fd );
2434
+ }
2435
+
2436
+ prog_fd = generate_dummy_prog ();
2437
+ if (!ASSERT_GE (prog_fd , 0 , "dummy_prog" ))
2438
+ goto cleanup ;
2439
+ opta .flags = flags ;
2440
+ if (last_fd > 0 )
2441
+ opta .relative_fd = last_fd ;
2442
+ err = bpf_prog_attach_opts (prog_fd , ifindex , target , & opta );
2443
+ ASSERT_EQ (err , - ERANGE , "prog_64_attach" );
2444
+ assert_mprog_count_ifindex (ifindex , target , max_progs );
2445
+ close (prog_fd );
2446
+ cleanup :
2447
+ if (last_fd > 0 )
2448
+ close (last_fd );
2449
+ ASSERT_OK (system ("ip link del dev tcx_opts1" ), "del veth" );
2450
+ ASSERT_EQ (if_nametoindex ("tcx_opts1" ), 0 , "dev1_removed" );
2451
+ ASSERT_EQ (if_nametoindex ("tcx_opts2" ), 0 , "dev2_removed" );
2452
+ }
2453
+
2454
+ void serial_test_tc_opts_max (void )
2455
+ {
2456
+ test_tc_opts_max_target (BPF_TCX_INGRESS , 0 , false);
2457
+ test_tc_opts_max_target (BPF_TCX_EGRESS , 0 , false);
2458
+
2459
+ test_tc_opts_max_target (BPF_TCX_INGRESS , BPF_F_BEFORE , false);
2460
+ test_tc_opts_max_target (BPF_TCX_EGRESS , BPF_F_BEFORE , true);
2461
+
2462
+ test_tc_opts_max_target (BPF_TCX_INGRESS , BPF_F_AFTER , true);
2463
+ test_tc_opts_max_target (BPF_TCX_EGRESS , BPF_F_AFTER , false);
2464
+ }
0 commit comments