@@ -293,15 +293,90 @@ bpf_program_complete_dev (struct bpf_program *program, libcrun_error_t *err arg_
293
293
return program ;
294
294
}
295
295
296
+ static int
297
+ ebpf_attach_program (int fd , int dirfd , libcrun_error_t * err )
298
+ {
299
+ const int MAX_ATTEMPTS = 20 ;
300
+ int attempt ;
301
+
302
+ for (attempt = 0 ;; attempt ++ )
303
+ {
304
+ cleanup_close int replacefd = -1 ;
305
+ union bpf_attr attr ;
306
+ uint32_t progs [2 ];
307
+ int ret ;
308
+
309
+ memset (& attr , 0 , sizeof (attr ));
310
+ attr .query .target_fd = dirfd ;
311
+ attr .query .attach_type = BPF_CGROUP_DEVICE ;
312
+ attr .query .prog_cnt = sizeof (progs ) / sizeof (progs [0 ]);
313
+ attr .query .prog_ids = (uint64_t ) & progs ;
314
+
315
+ ret = bpf (BPF_PROG_QUERY , & attr , sizeof (attr ));
316
+ if (UNLIKELY (ret < 0 ))
317
+ return crun_make_error (err , errno , "bpf query" );
318
+
319
+ if (attr .query .prog_cnt > 1 )
320
+ return crun_make_error (err , 0 , "invalid device cgroup state, more than one program installed" );
321
+
322
+ if (attr .query .prog_cnt == 1 )
323
+ {
324
+ #ifdef BPF_F_REPLACE
325
+ memset (& attr , 0 , sizeof (attr ));
326
+ attr .prog_id = progs [0 ];
327
+ replacefd = bpf (BPF_PROG_GET_FD_BY_ID , & attr , sizeof (attr ));
328
+ if (UNLIKELY (replacefd < 0 ))
329
+ {
330
+ if (errno == ENOENT && attempt < MAX_ATTEMPTS )
331
+ {
332
+ /* Another update might have raced and updated, try again. */
333
+ continue ;
334
+ }
335
+ return crun_make_error (err , errno , "cannot open existing eBPF program" );
336
+ }
337
+ #else
338
+ return crun_make_error (err , 0 , "eBPF program already configured" );
339
+ #endif
340
+ }
341
+
342
+ memset (& attr , 0 , sizeof (attr ));
343
+ attr .attach_type = BPF_CGROUP_DEVICE ;
344
+ attr .target_fd = dirfd ;
345
+ attr .attach_bpf_fd = fd ;
346
+ #ifdef BPF_F_REPLACE
347
+ attr .attach_flags = BPF_F_ALLOW_MULTI | ((replacefd >= 0 ) ? BPF_F_REPLACE : 0 );
348
+ attr .replace_bpf_fd = replacefd ;
349
+ #else
350
+ attr .attach_flags = BPF_F_ALLOW_MULTI ;
351
+ #endif
352
+
353
+ ret = bpf (BPF_PROG_ATTACH , & attr , sizeof (attr ));
354
+ if (UNLIKELY (ret < 0 ))
355
+ {
356
+ if (errno == ENOENT && replacefd >= 0 && attempt < MAX_ATTEMPTS )
357
+ {
358
+ /* Another update might have already updated the cgroup, try again. */
359
+ continue ;
360
+ }
361
+ if (errno == EINVAL && replacefd >= 0 )
362
+ return crun_make_error (err , errno , "bpf attach. The kernel might not support BPF_F_REPLACE" );
363
+ return crun_make_error (err , errno , "bpf attach" );
364
+ }
365
+
366
+ return 0 ;
367
+ }
368
+ }
369
+
296
370
int
297
371
libcrun_ebpf_load (struct bpf_program * program , int dirfd , const char * pin , libcrun_error_t * err )
298
372
{
299
373
#ifndef HAVE_EBPF
300
374
return crun_make_error (err , 0 , "eBPF not supported" );
301
375
#else
302
- int fd , ret ;
376
+ cleanup_close int fd = -1 ;
303
377
union bpf_attr attr ;
304
378
struct rlimit limit ;
379
+ int ret ;
305
380
306
381
limit .rlim_cur = RLIM_INFINITY ;
307
382
limit .rlim_max = RLIM_INFINITY ;
@@ -329,30 +404,26 @@ libcrun_ebpf_load (struct bpf_program *program, int dirfd, const char *pin, libc
329
404
330
405
fd = bpf (BPF_PROG_LOAD , & attr , sizeof (attr ));
331
406
if (fd < 0 )
332
- return crun_make_error (err , errno , "bpf create %s " , log );
407
+ return crun_make_error (err , errno , "bpf create `%s` " , log );
333
408
}
334
409
335
- memset (& attr , 0 , sizeof (attr ));
336
- attr .attach_type = BPF_CGROUP_DEVICE ;
337
- attr .target_fd = dirfd ;
338
- attr .attach_bpf_fd = fd ;
339
- attr .attach_flags = BPF_F_ALLOW_MULTI ;
340
-
341
- ret = bpf (BPF_PROG_ATTACH , & attr , sizeof (attr ));
342
- if (ret < 0 )
343
- return crun_make_error (err , errno , "bpf attach" );
410
+ ret = ebpf_attach_program (fd , dirfd , err );
411
+ if (UNLIKELY (ret < 0 ))
412
+ return ret ;
344
413
345
414
/* Optionally pin the program to the specified path. */
346
415
if (pin )
347
416
{
417
+ unlink (pin );
418
+
348
419
memset (& attr , 0 , sizeof (attr ));
349
420
attr .pathname = (uint64_t ) pin ;
350
421
attr .bpf_fd = fd ;
351
422
ret = bpf (BPF_OBJ_PIN , & attr , sizeof (attr ));
352
423
if (ret < 0 )
353
- return crun_make_error (err , errno , "bpf pin to %s " , pin );
424
+ return crun_make_error (err , errno , "bpf pin to `%s` " , pin );
354
425
}
355
426
356
- return fd ;
427
+ return 0 ;
357
428
#endif
358
429
}
0 commit comments