Explorar o código

Merge pull request #985 from reyzell/main

Add the option to support multiple and overrideable programs per cgroup
Alessandro Decina hai 6 meses
pai
achega
40f303205f

+ 11 - 7
aya/src/programs/cgroup_device.rs

@@ -5,8 +5,8 @@ use std::os::fd::AsFd;
 use crate::{
     generated::{bpf_attach_type::BPF_CGROUP_DEVICE, bpf_prog_type::BPF_PROG_TYPE_CGROUP_DEVICE},
     programs::{
-        bpf_prog_get_fd_by_id, define_link_wrapper, load_program, query, FdLink, Link,
-        ProgAttachLink, ProgramData, ProgramError, ProgramFd,
+        bpf_prog_get_fd_by_id, define_link_wrapper, load_program, query, CgroupAttachMode, FdLink,
+        Link, ProgAttachLink, ProgramData, ProgramError, ProgramFd,
     },
     sys::{bpf_link_create, LinkTarget, SyscallError},
     util::KernelVersion,
@@ -38,12 +38,12 @@ use crate::{
 /// #     Ebpf(#[from] aya::EbpfError)
 /// # }
 /// # let mut bpf = aya::Ebpf::load(&[])?;
-/// use aya::programs::CgroupDevice;
+/// use aya::programs::{CgroupAttachMode, CgroupDevice};
 ///
 /// let cgroup = std::fs::File::open("/sys/fs/cgroup/unified")?;
 /// let program: &mut CgroupDevice = bpf.program_mut("cgroup_dev").unwrap().try_into()?;
 /// program.load()?;
-/// program.attach(cgroup)?;
+/// program.attach(cgroup, CgroupAttachMode::Single)?;
 /// # Ok::<(), Error>(())
 /// ```
 #[derive(Debug)]
@@ -61,7 +61,11 @@ impl CgroupDevice {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [CgroupDevice::detach]
-    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<CgroupDeviceLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(
+        &mut self,
+        cgroup: T,
+        mode: CgroupAttachMode,
+    ) -> Result<CgroupDeviceLinkId, ProgramError> {
         let prog_fd = self.fd()?;
         let prog_fd = prog_fd.as_fd();
         let cgroup_fd = cgroup.as_fd();
@@ -72,7 +76,7 @@ impl CgroupDevice {
                 LinkTarget::Fd(cgroup_fd),
                 BPF_CGROUP_DEVICE,
                 None,
-                0,
+                mode.into(),
             )
             .map_err(|(_, io_error)| SyscallError {
                 call: "bpf_link_create",
@@ -84,7 +88,7 @@ impl CgroupDevice {
                     FdLink::new(link_fd),
                 )))
         } else {
-            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE)?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE, mode)?;
 
             self.data
                 .links

+ 17 - 9
aya/src/programs/cgroup_skb.rs

@@ -8,7 +8,8 @@ use crate::{
         bpf_prog_type::BPF_PROG_TYPE_CGROUP_SKB,
     },
     programs::{
-        define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
+        define_link_wrapper, load_program, CgroupAttachMode, FdLink, Link, ProgAttachLink,
+        ProgramData, ProgramError,
     },
     sys::{bpf_link_create, LinkTarget, SyscallError},
     util::KernelVersion,
@@ -43,12 +44,12 @@ use crate::{
 /// # }
 /// # let mut bpf = aya::Ebpf::load(&[])?;
 /// use std::fs::File;
-/// use aya::programs::{CgroupSkb, CgroupSkbAttachType};
+/// use aya::programs::{CgroupAttachMode, CgroupSkb, CgroupSkbAttachType};
 ///
 /// let file = File::open("/sys/fs/cgroup/unified")?;
 /// let egress: &mut CgroupSkb = bpf.program_mut("egress_filter").unwrap().try_into()?;
 /// egress.load()?;
-/// egress.attach(file, CgroupSkbAttachType::Egress)?;
+/// egress.attach(file, CgroupSkbAttachType::Egress, CgroupAttachMode::Single)?;
 /// # Ok::<(), Error>(())
 /// ```
 #[derive(Debug)]
@@ -87,6 +88,7 @@ impl CgroupSkb {
         &mut self,
         cgroup: T,
         attach_type: CgroupSkbAttachType,
+        mode: CgroupAttachMode,
     ) -> Result<CgroupSkbLinkId, ProgramError> {
         let prog_fd = self.fd()?;
         let prog_fd = prog_fd.as_fd();
@@ -97,18 +99,24 @@ impl CgroupSkb {
             CgroupSkbAttachType::Egress => BPF_CGROUP_INET_EGRESS,
         };
         if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
-            let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0)
-                .map_err(|(_, io_error)| SyscallError {
-                    call: "bpf_link_create",
-                    io_error,
-                })?;
+            let link_fd = bpf_link_create(
+                prog_fd,
+                LinkTarget::Fd(cgroup_fd),
+                attach_type,
+                None,
+                mode.into(),
+            )
+            .map_err(|(_, io_error)| SyscallError {
+                call: "bpf_link_create",
+                io_error,
+            })?;
             self.data
                 .links
                 .insert(CgroupSkbLink::new(CgroupSkbLinkInner::Fd(FdLink::new(
                     link_fd,
                 ))))
         } else {
-            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type, mode)?;
 
             self.data
                 .links

+ 21 - 10
aya/src/programs/cgroup_sock.rs

@@ -7,7 +7,8 @@ pub use aya_obj::programs::CgroupSockAttachType;
 use crate::{
     generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK,
     programs::{
-        define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
+        define_link_wrapper, load_program, CgroupAttachMode, FdLink, Link, ProgAttachLink,
+        ProgramData, ProgramError,
     },
     sys::{bpf_link_create, LinkTarget, SyscallError},
     util::KernelVersion,
@@ -41,12 +42,12 @@ use crate::{
 /// # }
 /// # let mut bpf = aya::Ebpf::load(&[])?;
 /// use std::fs::File;
-/// use aya::programs::{CgroupSock, CgroupSockAttachType};
+/// use aya::programs::{CgroupAttachMode, CgroupSock, CgroupSockAttachType};
 ///
 /// let file = File::open("/sys/fs/cgroup/unified")?;
 /// let bind: &mut CgroupSock = bpf.program_mut("bind").unwrap().try_into()?;
 /// bind.load()?;
-/// bind.attach(file)?;
+/// bind.attach(file, CgroupAttachMode::Single)?;
 /// # Ok::<(), Error>(())
 /// ```
 #[derive(Debug)]
@@ -66,24 +67,34 @@ impl CgroupSock {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [CgroupSock::detach].
-    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<CgroupSockLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(
+        &mut self,
+        cgroup: T,
+        mode: CgroupAttachMode,
+    ) -> Result<CgroupSockLinkId, ProgramError> {
         let prog_fd = self.fd()?;
         let prog_fd = prog_fd.as_fd();
         let cgroup_fd = cgroup.as_fd();
         let attach_type = self.data.expected_attach_type.unwrap();
         if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
-            let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0)
-                .map_err(|(_, io_error)| SyscallError {
-                    call: "bpf_link_create",
-                    io_error,
-                })?;
+            let link_fd = bpf_link_create(
+                prog_fd,
+                LinkTarget::Fd(cgroup_fd),
+                attach_type,
+                None,
+                mode.into(),
+            )
+            .map_err(|(_, io_error)| SyscallError {
+                call: "bpf_link_create",
+                io_error,
+            })?;
             self.data
                 .links
                 .insert(CgroupSockLink::new(CgroupSockLinkInner::Fd(FdLink::new(
                     link_fd,
                 ))))
         } else {
-            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type, mode)?;
 
             self.data
                 .links

+ 21 - 10
aya/src/programs/cgroup_sock_addr.rs

@@ -7,7 +7,8 @@ pub use aya_obj::programs::CgroupSockAddrAttachType;
 use crate::{
     generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
     programs::{
-        define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
+        define_link_wrapper, load_program, CgroupAttachMode, FdLink, Link, ProgAttachLink,
+        ProgramData, ProgramError,
     },
     sys::{bpf_link_create, LinkTarget, SyscallError},
     util::KernelVersion,
@@ -42,12 +43,12 @@ use crate::{
 /// # }
 /// # let mut bpf = aya::Ebpf::load(&[])?;
 /// use std::fs::File;
-/// use aya::programs::{CgroupSockAddr, CgroupSockAddrAttachType};
+/// use aya::programs::{CgroupAttachMode, CgroupSockAddr, CgroupSockAddrAttachType};
 ///
 /// let file = File::open("/sys/fs/cgroup/unified")?;
 /// let egress: &mut CgroupSockAddr = bpf.program_mut("connect4").unwrap().try_into()?;
 /// egress.load()?;
-/// egress.attach(file)?;
+/// egress.attach(file, CgroupAttachMode::Single)?;
 /// # Ok::<(), Error>(())
 /// ```
 #[derive(Debug)]
@@ -67,24 +68,34 @@ impl CgroupSockAddr {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [CgroupSockAddr::detach].
-    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<CgroupSockAddrLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(
+        &mut self,
+        cgroup: T,
+        mode: CgroupAttachMode,
+    ) -> Result<CgroupSockAddrLinkId, ProgramError> {
         let prog_fd = self.fd()?;
         let prog_fd = prog_fd.as_fd();
         let cgroup_fd = cgroup.as_fd();
         let attach_type = self.data.expected_attach_type.unwrap();
         if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
-            let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0)
-                .map_err(|(_, io_error)| SyscallError {
-                    call: "bpf_link_create",
-                    io_error,
-                })?;
+            let link_fd = bpf_link_create(
+                prog_fd,
+                LinkTarget::Fd(cgroup_fd),
+                attach_type,
+                None,
+                mode.into(),
+            )
+            .map_err(|(_, io_error)| SyscallError {
+                call: "bpf_link_create",
+                io_error,
+            })?;
             self.data
                 .links
                 .insert(CgroupSockAddrLink::new(CgroupSockAddrLinkInner::Fd(
                     FdLink::new(link_fd),
                 )))
         } else {
-            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type, mode)?;
 
             self.data.links.insert(CgroupSockAddrLink::new(
                 CgroupSockAddrLinkInner::ProgAttach(link),

+ 21 - 10
aya/src/programs/cgroup_sockopt.rs

@@ -7,7 +7,8 @@ pub use aya_obj::programs::CgroupSockoptAttachType;
 use crate::{
     generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCKOPT,
     programs::{
-        define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
+        define_link_wrapper, load_program, CgroupAttachMode, FdLink, Link, ProgAttachLink,
+        ProgramData, ProgramError,
     },
     sys::{bpf_link_create, LinkTarget, SyscallError},
     util::KernelVersion,
@@ -39,12 +40,12 @@ use crate::{
 /// # }
 /// # let mut bpf = aya::Ebpf::load(&[])?;
 /// use std::fs::File;
-/// use aya::programs::CgroupSockopt;
+/// use aya::programs::{CgroupAttachMode, CgroupSockopt};
 ///
 /// let file = File::open("/sys/fs/cgroup/unified")?;
 /// let program: &mut CgroupSockopt = bpf.program_mut("cgroup_sockopt").unwrap().try_into()?;
 /// program.load()?;
-/// program.attach(file)?;
+/// program.attach(file, CgroupAttachMode::Single)?;
 /// # Ok::<(), Error>(())
 /// ```
 #[derive(Debug)]
@@ -64,24 +65,34 @@ impl CgroupSockopt {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [CgroupSockopt::detach].
-    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<CgroupSockoptLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(
+        &mut self,
+        cgroup: T,
+        mode: CgroupAttachMode,
+    ) -> Result<CgroupSockoptLinkId, ProgramError> {
         let prog_fd = self.fd()?;
         let prog_fd = prog_fd.as_fd();
         let cgroup_fd = cgroup.as_fd();
         let attach_type = self.data.expected_attach_type.unwrap();
         if KernelVersion::current().unwrap() >= KernelVersion::new(5, 7, 0) {
-            let link_fd = bpf_link_create(prog_fd, LinkTarget::Fd(cgroup_fd), attach_type, None, 0)
-                .map_err(|(_, io_error)| SyscallError {
-                    call: "bpf_link_create",
-                    io_error,
-                })?;
+            let link_fd = bpf_link_create(
+                prog_fd,
+                LinkTarget::Fd(cgroup_fd),
+                attach_type,
+                None,
+                mode.into(),
+            )
+            .map_err(|(_, io_error)| SyscallError {
+                call: "bpf_link_create",
+                io_error,
+            })?;
             self.data
                 .links
                 .insert(CgroupSockoptLink::new(CgroupSockoptLinkInner::Fd(
                     FdLink::new(link_fd),
                 )))
         } else {
-            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type)?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, attach_type, mode)?;
 
             self.data
                 .links

+ 11 - 6
aya/src/programs/cgroup_sysctl.rs

@@ -5,7 +5,8 @@ use std::{hash::Hash, os::fd::AsFd};
 use crate::{
     generated::{bpf_attach_type::BPF_CGROUP_SYSCTL, bpf_prog_type::BPF_PROG_TYPE_CGROUP_SYSCTL},
     programs::{
-        define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
+        define_link_wrapper, load_program, CgroupAttachMode, FdLink, Link, ProgAttachLink,
+        ProgramData, ProgramError,
     },
     sys::{bpf_link_create, LinkTarget, SyscallError},
     util::KernelVersion,
@@ -36,12 +37,12 @@ use crate::{
 /// # }
 /// # let mut bpf = aya::Ebpf::load(&[])?;
 /// use std::fs::File;
-/// use aya::programs::CgroupSysctl;
+/// use aya::programs::{CgroupAttachMode, CgroupSysctl};
 ///
 /// let file = File::open("/sys/fs/cgroup/unified")?;
 /// let program: &mut CgroupSysctl = bpf.program_mut("cgroup_sysctl").unwrap().try_into()?;
 /// program.load()?;
-/// program.attach(file)?;
+/// program.attach(file, CgroupAttachMode::Single)?;
 /// # Ok::<(), Error>(())
 /// ```
 #[derive(Debug)]
@@ -59,7 +60,11 @@ impl CgroupSysctl {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [CgroupSysctl::detach].
-    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<CgroupSysctlLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(
+        &mut self,
+        cgroup: T,
+        mode: CgroupAttachMode,
+    ) -> Result<CgroupSysctlLinkId, ProgramError> {
         let prog_fd = self.fd()?;
         let prog_fd = prog_fd.as_fd();
         let cgroup_fd = cgroup.as_fd();
@@ -70,7 +75,7 @@ impl CgroupSysctl {
                 LinkTarget::Fd(cgroup_fd),
                 BPF_CGROUP_SYSCTL,
                 None,
-                0,
+                mode.into(),
             )
             .map_err(|(_, io_error)| SyscallError {
                 call: "bpf_link_create",
@@ -82,7 +87,7 @@ impl CgroupSysctl {
                     FdLink::new(link_fd),
                 )))
         } else {
-            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL)?;
+            let link = ProgAttachLink::attach(prog_fd, cgroup_fd, BPF_CGROUP_SYSCTL, mode)?;
 
             self.data
                 .links

+ 45 - 3
aya/src/programs/links.rs

@@ -10,7 +10,7 @@ use std::{
 use thiserror::Error;
 
 use crate::{
-    generated::bpf_attach_type,
+    generated::{bpf_attach_type, BPF_F_ALLOW_MULTI, BPF_F_ALLOW_OVERRIDE},
     pin::PinError,
     programs::{ProgramError, ProgramFd},
     sys::{bpf_get_object, bpf_pin_object, bpf_prog_attach, bpf_prog_detach, SyscallError},
@@ -28,6 +28,30 @@ pub trait Link: std::fmt::Debug + 'static {
     fn detach(self) -> Result<(), ProgramError>;
 }
 
+/// Program attachment mode.
+#[derive(Clone, Copy, Debug, Default)]
+pub enum CgroupAttachMode {
+    /// Allows only one BPF program in the cgroup subtree.
+    #[default]
+    Single,
+
+    /// Allows the program to be overridden by one in a sub-cgroup.
+    AllowOverride,
+
+    /// Allows multiple programs to be run in the cgroup subtree.
+    AllowMultiple,
+}
+
+impl From<CgroupAttachMode> for u32 {
+    fn from(mode: CgroupAttachMode) -> Self {
+        match mode {
+            CgroupAttachMode::Single => 0,
+            CgroupAttachMode::AllowOverride => BPF_F_ALLOW_OVERRIDE,
+            CgroupAttachMode::AllowMultiple => BPF_F_ALLOW_MULTI,
+        }
+    }
+}
+
 #[derive(Debug)]
 pub(crate) struct LinkMap<T: Link> {
     links: HashMap<T::Id, T>,
@@ -252,6 +276,7 @@ impl ProgAttachLink {
         prog_fd: BorrowedFd<'_>,
         target_fd: BorrowedFd<'_>,
         attach_type: bpf_attach_type,
+        mode: CgroupAttachMode,
     ) -> Result<Self, ProgramError> {
         // The link is going to own this new file descriptor so we are
         // going to need a duplicate whose lifetime we manage. Let's
@@ -261,7 +286,7 @@ impl ProgAttachLink {
         let prog_fd = crate::MockableFd::from_fd(prog_fd);
         let target_fd = target_fd.try_clone_to_owned()?;
         let target_fd = crate::MockableFd::from_fd(target_fd);
-        bpf_prog_attach(prog_fd.as_fd(), target_fd.as_fd(), attach_type)?;
+        bpf_prog_attach(prog_fd.as_fd(), target_fd.as_fd(), attach_type, mode.into())?;
 
         let prog_fd = ProgramFd(prog_fd);
         Ok(Self {
@@ -377,7 +402,11 @@ mod tests {
     use tempfile::tempdir;
 
     use super::{FdLink, Link, LinkMap};
-    use crate::{programs::ProgramError, sys::override_syscall};
+    use crate::{
+        generated::{BPF_F_ALLOW_MULTI, BPF_F_ALLOW_OVERRIDE},
+        programs::{CgroupAttachMode, ProgramError},
+        sys::override_syscall,
+    };
 
     #[derive(Debug, Hash, Eq, PartialEq)]
     struct TestLinkId(u8, u8);
@@ -523,4 +552,17 @@ mod tests {
         pinned_link.unpin().expect("unpin failed");
         assert!(!pin.exists());
     }
+
+    #[test]
+    fn test_cgroup_attach_flag() {
+        assert_eq!(u32::from(CgroupAttachMode::Single), 0);
+        assert_eq!(
+            u32::from(CgroupAttachMode::AllowOverride),
+            BPF_F_ALLOW_OVERRIDE
+        );
+        assert_eq!(
+            u32::from(CgroupAttachMode::AllowMultiple),
+            BPF_F_ALLOW_MULTI
+        );
+    }
 }

+ 10 - 2
aya/src/programs/lirc_mode2.rs

@@ -3,7 +3,10 @@ use std::os::fd::{AsFd, AsRawFd as _, RawFd};
 
 use crate::{
     generated::{bpf_attach_type::BPF_LIRC_MODE2, bpf_prog_type::BPF_PROG_TYPE_LIRC_MODE2},
-    programs::{load_program, query, Link, ProgramData, ProgramError, ProgramFd, ProgramInfo},
+    programs::{
+        load_program, query, CgroupAttachMode, Link, ProgramData, ProgramError, ProgramFd,
+        ProgramInfo,
+    },
     sys::{bpf_prog_attach, bpf_prog_detach, bpf_prog_get_fd_by_id},
 };
 
@@ -69,7 +72,12 @@ impl LircMode2 {
         let lircdev_fd = lircdev.as_fd().try_clone_to_owned()?;
         let lircdev_fd = crate::MockableFd::from_fd(lircdev_fd);
 
-        bpf_prog_attach(prog_fd.as_fd(), lircdev_fd.as_fd(), BPF_LIRC_MODE2)?;
+        bpf_prog_attach(
+            prog_fd.as_fd(),
+            lircdev_fd.as_fd(),
+            BPF_LIRC_MODE2,
+            CgroupAttachMode::Single.into(),
+        )?;
 
         self.data.links.insert(LircLink::new(prog_fd, lircdev_fd))
     }

+ 1 - 1
aya/src/programs/mod.rs

@@ -94,7 +94,7 @@ pub use crate::programs::{
     fentry::FEntry,
     fexit::FExit,
     kprobe::{KProbe, KProbeError},
-    links::Link,
+    links::{CgroupAttachMode, Link},
     lirc_mode2::LircMode2,
     lsm::Lsm,
     perf_event::{PerfEvent, PerfEventScope, PerfTypeId, SamplePolicy},

+ 8 - 3
aya/src/programs/sk_msg.rs

@@ -6,8 +6,8 @@ use crate::{
     generated::{bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG},
     maps::sock::SockMapFd,
     programs::{
-        define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
-        ProgramError,
+        define_link_wrapper, load_program, CgroupAttachMode, ProgAttachLink, ProgAttachLinkId,
+        ProgramData, ProgramError,
     },
 };
 
@@ -80,7 +80,12 @@ impl SkMsg {
     pub fn attach(&mut self, map: &SockMapFd) -> Result<SkMsgLinkId, ProgramError> {
         let prog_fd = self.fd()?;
         let prog_fd = prog_fd.as_fd();
-        let link = ProgAttachLink::attach(prog_fd, map.as_fd(), BPF_SK_MSG_VERDICT)?;
+        let link = ProgAttachLink::attach(
+            prog_fd,
+            map.as_fd(),
+            BPF_SK_MSG_VERDICT,
+            CgroupAttachMode::Single,
+        )?;
 
         self.data.links.insert(SkMsgLink::new(link))
     }

+ 4 - 3
aya/src/programs/sk_skb.rs

@@ -9,8 +9,8 @@ use crate::{
     },
     maps::sock::SockMapFd,
     programs::{
-        define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
-        ProgramError,
+        define_link_wrapper, load_program, CgroupAttachMode, ProgAttachLink, ProgAttachLinkId,
+        ProgramData, ProgramError,
     },
     VerifierLogLevel,
 };
@@ -90,7 +90,8 @@ impl SkSkb {
             SkSkbKind::StreamVerdict => BPF_SK_SKB_STREAM_VERDICT,
         };
 
-        let link = ProgAttachLink::attach(prog_fd, map.as_fd(), attach_type)?;
+        let link =
+            ProgAttachLink::attach(prog_fd, map.as_fd(), attach_type, CgroupAttachMode::Single)?;
 
         self.data.links.insert(SkSkbLink::new(link))
     }

+ 11 - 6
aya/src/programs/sock_ops.rs

@@ -4,8 +4,8 @@ use std::os::fd::AsFd;
 use crate::{
     generated::{bpf_attach_type::BPF_CGROUP_SOCK_OPS, bpf_prog_type::BPF_PROG_TYPE_SOCK_OPS},
     programs::{
-        define_link_wrapper, load_program, ProgAttachLink, ProgAttachLinkId, ProgramData,
-        ProgramError,
+        define_link_wrapper, load_program, CgroupAttachMode, ProgAttachLink, ProgAttachLinkId,
+        ProgramData, ProgramError,
     },
 };
 
@@ -35,12 +35,12 @@ use crate::{
 /// # }
 /// # let mut bpf = aya::Ebpf::load(&[])?;
 /// use std::fs::File;
-/// use aya::programs::SockOps;
+/// use aya::programs::{CgroupAttachMode, SockOps};
 ///
 /// let file = File::open("/sys/fs/cgroup/unified")?;
 /// let prog: &mut SockOps = bpf.program_mut("intercept_active_sockets").unwrap().try_into()?;
 /// prog.load()?;
-/// prog.attach(file)?;
+/// prog.attach(file, CgroupAttachMode::Single)?;
 /// # Ok::<(), Error>(())
 #[derive(Debug)]
 #[doc(alias = "BPF_PROG_TYPE_SOCK_OPS")]
@@ -57,10 +57,15 @@ impl SockOps {
     /// Attaches the program to the given cgroup.
     ///
     /// The returned value can be used to detach, see [SockOps::detach].
-    pub fn attach<T: AsFd>(&mut self, cgroup: T) -> Result<SockOpsLinkId, ProgramError> {
+    pub fn attach<T: AsFd>(
+        &mut self,
+        cgroup: T,
+        mode: CgroupAttachMode,
+    ) -> Result<SockOpsLinkId, ProgramError> {
         let prog_fd = self.fd()?;
 
-        let link = ProgAttachLink::attach(prog_fd.as_fd(), cgroup.as_fd(), BPF_CGROUP_SOCK_OPS)?;
+        let link =
+            ProgAttachLink::attach(prog_fd.as_fd(), cgroup.as_fd(), BPF_CGROUP_SOCK_OPS, mode)?;
         self.data.links.insert(SockOpsLink::new(link))
     }
 

+ 45 - 0
aya/src/sys/bpf.rs

@@ -433,12 +433,14 @@ pub(crate) fn bpf_prog_attach(
     prog_fd: BorrowedFd<'_>,
     target_fd: BorrowedFd<'_>,
     attach_type: bpf_attach_type,
+    flags: u32,
 ) -> Result<(), SyscallError> {
     let mut attr = unsafe { mem::zeroed::<bpf_attr>() };
 
     attr.__bindgen_anon_5.attach_bpf_fd = prog_fd.as_raw_fd() as u32;
     attr.__bindgen_anon_5.__bindgen_anon_1.target_fd = target_fd.as_raw_fd() as u32;
     attr.__bindgen_anon_5.attach_type = attach_type as u32;
+    attr.__bindgen_anon_5.attach_flags = flags;
 
     let ret = sys_bpf(bpf_cmd::BPF_PROG_ATTACH, &mut attr).map_err(|(code, io_error)| {
         assert_eq!(code, -1);
@@ -1228,6 +1230,49 @@ mod tests {
     use super::*;
     use crate::sys::override_syscall;
 
+    #[test]
+    fn test_attach_with_attributes() {
+        const FAKE_FLAGS: u32 = 1234;
+        const FAKE_FD: i32 = 4321;
+
+        // Test attach flags propagated to system call.
+        override_syscall(|call| match call {
+            Syscall::Ebpf {
+                cmd: bpf_cmd::BPF_PROG_ATTACH,
+                attr,
+            } => {
+                assert_eq!(unsafe { attr.__bindgen_anon_5.attach_flags }, FAKE_FLAGS);
+                Ok(0)
+            }
+            _ => Err((-1, io::Error::from_raw_os_error(EINVAL))),
+        });
+
+        let prog_fd = unsafe { BorrowedFd::borrow_raw(FAKE_FD) };
+        let tgt_fd = unsafe { BorrowedFd::borrow_raw(FAKE_FD) };
+        let mut result = bpf_prog_attach(
+            prog_fd,
+            tgt_fd,
+            bpf_attach_type::BPF_CGROUP_SOCK_OPS,
+            FAKE_FLAGS,
+        );
+        result.unwrap();
+
+        // Test with no flags.
+        override_syscall(|call| match call {
+            Syscall::Ebpf {
+                cmd: bpf_cmd::BPF_PROG_ATTACH,
+                attr,
+            } => {
+                assert_eq!(unsafe { attr.__bindgen_anon_5.attach_flags }, 0);
+                Ok(0)
+            }
+            _ => Err((-1, io::Error::from_raw_os_error(EINVAL))),
+        });
+
+        result = bpf_prog_attach(prog_fd, tgt_fd, bpf_attach_type::BPF_CGROUP_SOCK_OPS, 0);
+        result.unwrap();
+    }
+
     #[test]
     fn test_perf_link_supported() {
         override_syscall(|call| match call {

+ 96 - 14
xtask/public-api/aya.txt

@@ -2524,7 +2524,7 @@ pub use aya::programs::CgroupSockoptAttachType
 pub mod aya::programs::cgroup_device
 pub struct aya::programs::cgroup_device::CgroupDevice
 impl aya::programs::cgroup_device::CgroupDevice
-pub fn aya::programs::cgroup_device::CgroupDevice::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_device::CgroupDeviceLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_device::CgroupDevice::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_device::CgroupDeviceLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_device::CgroupDevice::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_device::CgroupDevice::query<T: std::os::fd::owned::AsFd>(target_fd: T) -> core::result::Result<alloc::vec::Vec<aya::programs::cgroup_device::CgroupDeviceLink>, aya::programs::ProgramError>
@@ -2677,7 +2677,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_skb::CgroupSkbAttachTyp
 pub fn aya::programs::cgroup_skb::CgroupSkbAttachType::from(t: T) -> T
 pub struct aya::programs::cgroup_skb::CgroupSkb
 impl aya::programs::cgroup_skb::CgroupSkb
-pub fn aya::programs::cgroup_skb::CgroupSkb::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result<aya::programs::cgroup_skb::CgroupSkbLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_skb::CgroupSkb::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_skb::CgroupSkbLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::detach(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::expected_attach_type(&self) -> &core::option::Option<aya::programs::cgroup_skb::CgroupSkbAttachType>
 pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, expected_attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
@@ -2794,7 +2794,7 @@ pub mod aya::programs::cgroup_sock
 pub use aya::programs::cgroup_sock::CgroupSockAttachType
 pub struct aya::programs::cgroup_sock::CgroupSock
 impl aya::programs::cgroup_sock::CgroupSock
-pub fn aya::programs::cgroup_sock::CgroupSock::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock::CgroupSockLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sock::CgroupSock::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_sock::CgroupSockLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::detach(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sock::CgroupSockAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -2910,7 +2910,7 @@ pub mod aya::programs::cgroup_sock_addr
 pub use aya::programs::cgroup_sock_addr::CgroupSockAddrAttachType
 pub struct aya::programs::cgroup_sock_addr::CgroupSockAddr
 impl aya::programs::cgroup_sock_addr::CgroupSockAddr
-pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::detach(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sock_addr::CgroupSockAddrAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -3026,7 +3026,7 @@ pub mod aya::programs::cgroup_sockopt
 pub use aya::programs::cgroup_sockopt::CgroupSockoptAttachType
 pub struct aya::programs::cgroup_sockopt::CgroupSockopt
 impl aya::programs::cgroup_sockopt::CgroupSockopt
-pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sockopt::CgroupSockoptLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_sockopt::CgroupSockoptLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::detach(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -3141,7 +3141,7 @@ pub fn aya::programs::cgroup_sockopt::CgroupSockoptLinkId::from(t: T) -> T
 pub mod aya::programs::cgroup_sysctl
 pub struct aya::programs::cgroup_sysctl::CgroupSysctl
 impl aya::programs::cgroup_sysctl::CgroupSysctl
-pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::take_link(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLink, aya::programs::ProgramError>
@@ -3807,6 +3807,47 @@ pub fn aya::programs::kprobe::KProbeLinkId::borrow_mut(&mut self) -> &mut T
 impl<T> core::convert::From<T> for aya::programs::kprobe::KProbeLinkId
 pub fn aya::programs::kprobe::KProbeLinkId::from(t: T) -> T
 pub mod aya::programs::links
+pub enum aya::programs::links::CgroupAttachMode
+pub aya::programs::links::CgroupAttachMode::AllowMultiple
+pub aya::programs::links::CgroupAttachMode::AllowOverride
+pub aya::programs::links::CgroupAttachMode::Single
+impl core::clone::Clone for aya::programs::links::CgroupAttachMode
+pub fn aya::programs::links::CgroupAttachMode::clone(&self) -> aya::programs::links::CgroupAttachMode
+impl core::convert::From<aya::programs::links::CgroupAttachMode> for u32
+pub fn u32::from(mode: aya::programs::links::CgroupAttachMode) -> Self
+impl core::default::Default for aya::programs::links::CgroupAttachMode
+pub fn aya::programs::links::CgroupAttachMode::default() -> aya::programs::links::CgroupAttachMode
+impl core::fmt::Debug for aya::programs::links::CgroupAttachMode
+pub fn aya::programs::links::CgroupAttachMode::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+impl core::marker::Copy for aya::programs::links::CgroupAttachMode
+impl core::marker::Freeze for aya::programs::links::CgroupAttachMode
+impl core::marker::Send for aya::programs::links::CgroupAttachMode
+impl core::marker::Sync for aya::programs::links::CgroupAttachMode
+impl core::marker::Unpin for aya::programs::links::CgroupAttachMode
+impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::links::CgroupAttachMode
+impl core::panic::unwind_safe::UnwindSafe for aya::programs::links::CgroupAttachMode
+impl<T, U> core::convert::Into<U> for aya::programs::links::CgroupAttachMode where U: core::convert::From<T>
+pub fn aya::programs::links::CgroupAttachMode::into(self) -> U
+impl<T, U> core::convert::TryFrom<U> for aya::programs::links::CgroupAttachMode where U: core::convert::Into<T>
+pub type aya::programs::links::CgroupAttachMode::Error = core::convert::Infallible
+pub fn aya::programs::links::CgroupAttachMode::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
+impl<T, U> core::convert::TryInto<U> for aya::programs::links::CgroupAttachMode where U: core::convert::TryFrom<T>
+pub type aya::programs::links::CgroupAttachMode::Error = <U as core::convert::TryFrom<T>>::Error
+pub fn aya::programs::links::CgroupAttachMode::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
+impl<T> alloc::borrow::ToOwned for aya::programs::links::CgroupAttachMode where T: core::clone::Clone
+pub type aya::programs::links::CgroupAttachMode::Owned = T
+pub fn aya::programs::links::CgroupAttachMode::clone_into(&self, target: &mut T)
+pub fn aya::programs::links::CgroupAttachMode::to_owned(&self) -> T
+impl<T> core::any::Any for aya::programs::links::CgroupAttachMode where T: 'static + core::marker::Sized
+pub fn aya::programs::links::CgroupAttachMode::type_id(&self) -> core::any::TypeId
+impl<T> core::borrow::Borrow<T> for aya::programs::links::CgroupAttachMode where T: core::marker::Sized
+pub fn aya::programs::links::CgroupAttachMode::borrow(&self) -> &T
+impl<T> core::borrow::BorrowMut<T> for aya::programs::links::CgroupAttachMode where T: core::marker::Sized
+pub fn aya::programs::links::CgroupAttachMode::borrow_mut(&mut self) -> &mut T
+impl<T> core::clone::CloneToUninit for aya::programs::links::CgroupAttachMode where T: core::clone::Clone
+pub unsafe fn aya::programs::links::CgroupAttachMode::clone_to_uninit(&self, dst: *mut T)
+impl<T> core::convert::From<T> for aya::programs::links::CgroupAttachMode
+pub fn aya::programs::links::CgroupAttachMode::from(t: T) -> T
 pub enum aya::programs::links::LinkError
 pub aya::programs::links::LinkError::InvalidLink
 pub aya::programs::links::LinkError::SyscallError(aya::sys::SyscallError)
@@ -5250,7 +5291,7 @@ pub fn aya::programs::sk_skb::SkSkbLinkId::from(t: T) -> T
 pub mod aya::programs::sock_ops
 pub struct aya::programs::sock_ops::SockOps
 impl aya::programs::sock_ops::SockOps
-pub fn aya::programs::sock_ops::SockOps::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::sock_ops::SockOpsLinkId, aya::programs::ProgramError>
+pub fn aya::programs::sock_ops::SockOps::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::sock_ops::SockOpsLinkId, aya::programs::ProgramError>
 pub fn aya::programs::sock_ops::SockOps::detach(&mut self, link_id: aya::programs::sock_ops::SockOpsLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::sock_ops::SockOps::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::sock_ops::SockOps::take_link(&mut self, link_id: aya::programs::sock_ops::SockOpsLinkId) -> core::result::Result<aya::programs::sock_ops::SockOpsLink, aya::programs::ProgramError>
@@ -6464,6 +6505,47 @@ impl<T> core::borrow::BorrowMut<T> for aya::programs::xdp::XdpLinkId where T: co
 pub fn aya::programs::xdp::XdpLinkId::borrow_mut(&mut self) -> &mut T
 impl<T> core::convert::From<T> for aya::programs::xdp::XdpLinkId
 pub fn aya::programs::xdp::XdpLinkId::from(t: T) -> T
+pub enum aya::programs::CgroupAttachMode
+pub aya::programs::CgroupAttachMode::AllowMultiple
+pub aya::programs::CgroupAttachMode::AllowOverride
+pub aya::programs::CgroupAttachMode::Single
+impl core::clone::Clone for aya::programs::links::CgroupAttachMode
+pub fn aya::programs::links::CgroupAttachMode::clone(&self) -> aya::programs::links::CgroupAttachMode
+impl core::convert::From<aya::programs::links::CgroupAttachMode> for u32
+pub fn u32::from(mode: aya::programs::links::CgroupAttachMode) -> Self
+impl core::default::Default for aya::programs::links::CgroupAttachMode
+pub fn aya::programs::links::CgroupAttachMode::default() -> aya::programs::links::CgroupAttachMode
+impl core::fmt::Debug for aya::programs::links::CgroupAttachMode
+pub fn aya::programs::links::CgroupAttachMode::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+impl core::marker::Copy for aya::programs::links::CgroupAttachMode
+impl core::marker::Freeze for aya::programs::links::CgroupAttachMode
+impl core::marker::Send for aya::programs::links::CgroupAttachMode
+impl core::marker::Sync for aya::programs::links::CgroupAttachMode
+impl core::marker::Unpin for aya::programs::links::CgroupAttachMode
+impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::links::CgroupAttachMode
+impl core::panic::unwind_safe::UnwindSafe for aya::programs::links::CgroupAttachMode
+impl<T, U> core::convert::Into<U> for aya::programs::links::CgroupAttachMode where U: core::convert::From<T>
+pub fn aya::programs::links::CgroupAttachMode::into(self) -> U
+impl<T, U> core::convert::TryFrom<U> for aya::programs::links::CgroupAttachMode where U: core::convert::Into<T>
+pub type aya::programs::links::CgroupAttachMode::Error = core::convert::Infallible
+pub fn aya::programs::links::CgroupAttachMode::try_from(value: U) -> core::result::Result<T, <T as core::convert::TryFrom<U>>::Error>
+impl<T, U> core::convert::TryInto<U> for aya::programs::links::CgroupAttachMode where U: core::convert::TryFrom<T>
+pub type aya::programs::links::CgroupAttachMode::Error = <U as core::convert::TryFrom<T>>::Error
+pub fn aya::programs::links::CgroupAttachMode::try_into(self) -> core::result::Result<U, <U as core::convert::TryFrom<T>>::Error>
+impl<T> alloc::borrow::ToOwned for aya::programs::links::CgroupAttachMode where T: core::clone::Clone
+pub type aya::programs::links::CgroupAttachMode::Owned = T
+pub fn aya::programs::links::CgroupAttachMode::clone_into(&self, target: &mut T)
+pub fn aya::programs::links::CgroupAttachMode::to_owned(&self) -> T
+impl<T> core::any::Any for aya::programs::links::CgroupAttachMode where T: 'static + core::marker::Sized
+pub fn aya::programs::links::CgroupAttachMode::type_id(&self) -> core::any::TypeId
+impl<T> core::borrow::Borrow<T> for aya::programs::links::CgroupAttachMode where T: core::marker::Sized
+pub fn aya::programs::links::CgroupAttachMode::borrow(&self) -> &T
+impl<T> core::borrow::BorrowMut<T> for aya::programs::links::CgroupAttachMode where T: core::marker::Sized
+pub fn aya::programs::links::CgroupAttachMode::borrow_mut(&mut self) -> &mut T
+impl<T> core::clone::CloneToUninit for aya::programs::links::CgroupAttachMode where T: core::clone::Clone
+pub unsafe fn aya::programs::links::CgroupAttachMode::clone_to_uninit(&self, dst: *mut T)
+impl<T> core::convert::From<T> for aya::programs::links::CgroupAttachMode
+pub fn aya::programs::links::CgroupAttachMode::from(t: T) -> T
 pub enum aya::programs::CgroupSkbAttachType
 pub aya::programs::CgroupSkbAttachType::Egress
 pub aya::programs::CgroupSkbAttachType::Ingress
@@ -7393,7 +7475,7 @@ impl<T> core::convert::From<T> for aya::programs::tp_btf::BtfTracePoint
 pub fn aya::programs::tp_btf::BtfTracePoint::from(t: T) -> T
 pub struct aya::programs::CgroupDevice
 impl aya::programs::cgroup_device::CgroupDevice
-pub fn aya::programs::cgroup_device::CgroupDevice::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_device::CgroupDeviceLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_device::CgroupDevice::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_device::CgroupDeviceLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_device::CgroupDevice::detach(&mut self, link_id: aya::programs::cgroup_device::CgroupDeviceLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_device::CgroupDevice::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_device::CgroupDevice::query<T: std::os::fd::owned::AsFd>(target_fd: T) -> core::result::Result<alloc::vec::Vec<aya::programs::cgroup_device::CgroupDeviceLink>, aya::programs::ProgramError>
@@ -7443,7 +7525,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_device::CgroupDevice
 pub fn aya::programs::cgroup_device::CgroupDevice::from(t: T) -> T
 pub struct aya::programs::CgroupSkb
 impl aya::programs::cgroup_skb::CgroupSkb
-pub fn aya::programs::cgroup_skb::CgroupSkb::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result<aya::programs::cgroup_skb::CgroupSkbLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_skb::CgroupSkb::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_skb::CgroupSkbLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::detach(&mut self, link_id: aya::programs::cgroup_skb::CgroupSkbLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_skb::CgroupSkb::expected_attach_type(&self) -> &core::option::Option<aya::programs::cgroup_skb::CgroupSkbAttachType>
 pub fn aya::programs::cgroup_skb::CgroupSkb::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, expected_attach_type: aya::programs::cgroup_skb::CgroupSkbAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
@@ -7492,7 +7574,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_skb::CgroupSkb
 pub fn aya::programs::cgroup_skb::CgroupSkb::from(t: T) -> T
 pub struct aya::programs::CgroupSock
 impl aya::programs::cgroup_sock::CgroupSock
-pub fn aya::programs::cgroup_sock::CgroupSock::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock::CgroupSockLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sock::CgroupSock::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_sock::CgroupSockLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::detach(&mut self, link_id: aya::programs::cgroup_sock::CgroupSockLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sock::CgroupSockAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock::CgroupSock::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -7540,7 +7622,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_sock::CgroupSock
 pub fn aya::programs::cgroup_sock::CgroupSock::from(t: T) -> T
 pub struct aya::programs::CgroupSockAddr
 impl aya::programs::cgroup_sock_addr::CgroupSockAddr
-pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::detach(&mut self, link_id: aya::programs::cgroup_sock_addr::CgroupSockAddrLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sock_addr::CgroupSockAddrAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -7588,7 +7670,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_sock_addr::CgroupSockAd
 pub fn aya::programs::cgroup_sock_addr::CgroupSockAddr::from(t: T) -> T
 pub struct aya::programs::CgroupSockopt
 impl aya::programs::cgroup_sockopt::CgroupSockopt
-pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sockopt::CgroupSockoptLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sockopt::CgroupSockopt::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_sockopt::CgroupSockoptLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::detach(&mut self, link_id: aya::programs::cgroup_sockopt::CgroupSockoptLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from_pin<P: core::convert::AsRef<std::path::Path>>(path: P, attach_type: aya_obj::programs::cgroup_sockopt::CgroupSockoptAttachType) -> core::result::Result<Self, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
@@ -7636,7 +7718,7 @@ impl<T> core::convert::From<T> for aya::programs::cgroup_sockopt::CgroupSockopt
 pub fn aya::programs::cgroup_sockopt::CgroupSockopt::from(t: T) -> T
 pub struct aya::programs::CgroupSysctl
 impl aya::programs::cgroup_sysctl::CgroupSysctl
-pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLinkId, aya::programs::ProgramError>
+pub fn aya::programs::cgroup_sysctl::CgroupSysctl::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLinkId, aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::detach(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::cgroup_sysctl::CgroupSysctl::take_link(&mut self, link_id: aya::programs::cgroup_sysctl::CgroupSysctlLinkId) -> core::result::Result<aya::programs::cgroup_sysctl::CgroupSysctlLink, aya::programs::ProgramError>
@@ -8348,7 +8430,7 @@ impl<T> core::convert::From<T> for aya::programs::sk_skb::SkSkb
 pub fn aya::programs::sk_skb::SkSkb::from(t: T) -> T
 pub struct aya::programs::SockOps
 impl aya::programs::sock_ops::SockOps
-pub fn aya::programs::sock_ops::SockOps::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T) -> core::result::Result<aya::programs::sock_ops::SockOpsLinkId, aya::programs::ProgramError>
+pub fn aya::programs::sock_ops::SockOps::attach<T: std::os::fd::owned::AsFd>(&mut self, cgroup: T, mode: aya::programs::links::CgroupAttachMode) -> core::result::Result<aya::programs::sock_ops::SockOpsLinkId, aya::programs::ProgramError>
 pub fn aya::programs::sock_ops::SockOps::detach(&mut self, link_id: aya::programs::sock_ops::SockOpsLinkId) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::sock_ops::SockOps::load(&mut self) -> core::result::Result<(), aya::programs::ProgramError>
 pub fn aya::programs::sock_ops::SockOps::take_link(&mut self, link_id: aya::programs::sock_ops::SockOpsLinkId) -> core::result::Result<aya::programs::sock_ops::SockOpsLink, aya::programs::ProgramError>