@@ -587,6 +587,95 @@ int bpf_firewall_compile(Unit *u) {
587587 return 0 ;
588588}
589589
590+ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR (filter_prog_hash_ops , void , trivial_hash_func , trivial_compare_func , BPFProgram , bpf_program_unref );
591+
592+ static int load_bpf_progs_from_fs_to_set (Unit * u , char * * filter_paths , Set * * set ) {
593+ char * * bpf_fs_path ;
594+
595+ set_clear (* set );
596+
597+ STRV_FOREACH (bpf_fs_path , filter_paths ) {
598+ _cleanup_free_ BPFProgram * prog = NULL ;
599+ int r ;
600+
601+ r = bpf_program_new (BPF_PROG_TYPE_CGROUP_SKB , & prog );
602+ if (r < 0 )
603+ return log_unit_error_errno (u , r , "Can't allocate CGROUP SKB BPF program: %m" );
604+
605+ r = bpf_program_load_from_bpf_fs (prog , * bpf_fs_path );
606+ if (r < 0 )
607+ return log_unit_error_errno (u , r , "Loading of ingress BPF program %s failed: %m" , * bpf_fs_path );
608+
609+ r = set_ensure_allocated (set , & filter_prog_hash_ops );
610+ if (r < 0 )
611+ return log_unit_error_errno (u , r , "Can't allocate BPF program set: %m" );
612+
613+ r = set_put (* set , prog );
614+ if (r < 0 )
615+ return log_unit_error_errno (u , r , "Can't add program to BPF program set: %m" );
616+ TAKE_PTR (prog );
617+ }
618+
619+ return 0 ;
620+ }
621+
622+ int bpf_firewall_load_custom (Unit * u ) {
623+ CGroupContext * cc ;
624+ int r , supported ;
625+
626+ assert (u );
627+
628+ cc = unit_get_cgroup_context (u );
629+ if (!cc )
630+ return 0 ;
631+
632+ if (!(cc -> ip_filters_ingress || cc -> ip_filters_egress ))
633+ return 0 ;
634+
635+ supported = bpf_firewall_supported ();
636+ if (supported < 0 )
637+ return supported ;
638+
639+ if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI )
640+ return log_unit_debug_errno (u , SYNTHETIC_ERRNO (EOPNOTSUPP ), "BPF_F_ALLOW_MULTI not supported on this manager, cannot attach custom BPF programs." );
641+
642+ r = load_bpf_progs_from_fs_to_set (u , cc -> ip_filters_ingress , & u -> ip_bpf_custom_ingress );
643+ if (r < 0 )
644+ return r ;
645+ r = load_bpf_progs_from_fs_to_set (u , cc -> ip_filters_egress , & u -> ip_bpf_custom_egress );
646+ if (r < 0 )
647+ return r ;
648+
649+ return 0 ;
650+ }
651+
652+ static int attach_custom_bpf_progs (Unit * u , const char * path , int attach_type , Set * * set , Set * * set_installed ) {
653+ BPFProgram * prog ;
654+ Iterator i ;
655+ int r ;
656+
657+ assert (u );
658+
659+ set_clear (* set_installed );
660+
661+ SET_FOREACH (prog , * set , i ) {
662+ r = bpf_program_cgroup_attach (prog , attach_type , path , BPF_F_ALLOW_MULTI );
663+ if (r < 0 )
664+ return log_unit_error_errno (u , r , "Attaching custom egress BPF program to cgroup %s failed: %m" , path );
665+ /* Remember that these BPF programs are installed now. */
666+ r = set_ensure_allocated (set_installed , & filter_prog_hash_ops );
667+ if (r < 0 )
668+ return log_unit_error_errno (u , r , "Can't allocate BPF program set: %m" );
669+
670+ r = set_put (* set_installed , prog );
671+ if (r < 0 )
672+ return log_unit_error_errno (u , r , "Can't add program to BPF program set: %m" );
673+ bpf_program_ref (prog );
674+ }
675+
676+ return 0 ;
677+ }
678+
590679int bpf_firewall_install (Unit * u ) {
591680 _cleanup_free_ char * path = NULL ;
592681 CGroupContext * cc ;
@@ -614,6 +703,9 @@ int bpf_firewall_install(Unit *u) {
614703 log_unit_debug (u , "BPF_F_ALLOW_MULTI is not supported on this manager, not doing BPF firewall on slice units." );
615704 return - EOPNOTSUPP ;
616705 }
706+ if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI &&
707+ (!set_isempty (u -> ip_bpf_custom_ingress ) || !set_isempty (u -> ip_bpf_custom_egress )))
708+ return log_unit_debug_errno (u , SYNTHETIC_ERRNO (EOPNOTSUPP ), "BPF_F_ALLOW_MULTI not supported on this manager, cannot attach custom BPF programs." );
617709
618710 r = cg_get_path (SYSTEMD_CGROUP_CONTROLLER , u -> cgroup_path , NULL , & path );
619711 if (r < 0 )
@@ -628,7 +720,8 @@ int bpf_firewall_install(Unit *u) {
628720 u -> ip_bpf_ingress_installed = bpf_program_unref (u -> ip_bpf_ingress_installed );
629721
630722 if (u -> ip_bpf_egress ) {
631- r = bpf_program_cgroup_attach (u -> ip_bpf_egress , BPF_CGROUP_INET_EGRESS , path , flags );
723+ r = bpf_program_cgroup_attach (u -> ip_bpf_egress , BPF_CGROUP_INET_EGRESS , path ,
724+ flags | (set_isempty (u -> ip_bpf_custom_egress ) ? 0 : BPF_F_ALLOW_MULTI ));
632725 if (r < 0 )
633726 return log_unit_error_errno (u , r , "Attaching egress BPF program to cgroup %s failed: %m" , path );
634727
@@ -637,13 +730,22 @@ int bpf_firewall_install(Unit *u) {
637730 }
638731
639732 if (u -> ip_bpf_ingress ) {
640- r = bpf_program_cgroup_attach (u -> ip_bpf_ingress , BPF_CGROUP_INET_INGRESS , path , flags );
733+ r = bpf_program_cgroup_attach (u -> ip_bpf_ingress , BPF_CGROUP_INET_INGRESS , path ,
734+ flags | (set_isempty (u -> ip_bpf_custom_ingress ) ? 0 : BPF_F_ALLOW_MULTI ));
641735 if (r < 0 )
642736 return log_unit_error_errno (u , r , "Attaching ingress BPF program to cgroup %s failed: %m" , path );
643737
644738 u -> ip_bpf_ingress_installed = bpf_program_ref (u -> ip_bpf_ingress );
645739 }
646740
741+ r = attach_custom_bpf_progs (u , path , BPF_CGROUP_INET_EGRESS , & u -> ip_bpf_custom_egress , & u -> ip_bpf_custom_egress_installed );
742+ if (r < 0 )
743+ return r ;
744+
745+ r = attach_custom_bpf_progs (u , path , BPF_CGROUP_INET_INGRESS , & u -> ip_bpf_custom_ingress , & u -> ip_bpf_custom_ingress_installed );
746+ if (r < 0 )
747+ return r ;
748+
647749 return 0 ;
648750}
649751
0 commit comments