mirror of https://github.com/aya-rs/aya
				
				
				
			Add support for BPF_PROG_TYPE_CGROUP_SOCKOPT
This patch adds support for `BPF_PROG_TYPE_CGROUP_SOCKOPT`.pull/268/head
							parent
							
								
									63b6286bd9
								
							
						
					
					
						commit
						f42f7c4361
					
				| @ -0,0 +1,193 @@ | |||||||
|  | use thiserror::Error; | ||||||
|  | 
 | ||||||
|  | use std::{ | ||||||
|  |     hash::Hash, | ||||||
|  |     os::unix::prelude::{AsRawFd, RawFd}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | use crate::{ | ||||||
|  |     generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCKOPT, | ||||||
|  |     programs::{ | ||||||
|  |         bpf_attach_type, define_link_wrapper, load_program, FdLink, Link, OwnedLink, | ||||||
|  |         ProgAttachLink, ProgramData, ProgramError, | ||||||
|  |     }, | ||||||
|  |     sys::{bpf_link_create, bpf_prog_attach, kernel_version}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /// A program that can be used to get or set options on sockets.
 | ||||||
|  | ///
 | ||||||
|  | /// [`SockAddr`] programs can be used to inspect or modify socket addresses passed to
 | ||||||
|  | /// various syscalls within a [cgroup]. They can be attached to a number of different
 | ||||||
|  | /// places as described in [`SockAddrAttachType`].
 | ||||||
|  | ///
 | ||||||
|  | /// [`CgroupSockopt`] programs can be attached to a cgroup and will be called every
 | ||||||
|  | /// time a process executes getsockopt or getsockopt system call.
 | ||||||
|  | ///
 | ||||||
|  | /// # Minimum kernel version
 | ||||||
|  | ///
 | ||||||
|  | /// The minimum kernel version required to use this feature is 5.3.
 | ||||||
|  | ///
 | ||||||
|  | /// # Examples
 | ||||||
|  | ///
 | ||||||
|  | /// ```no_run
 | ||||||
|  | /// # #[derive(Debug, thiserror::Error)]
 | ||||||
|  | /// # enum Error {
 | ||||||
|  | /// #     #[error(transparent)]
 | ||||||
|  | /// #     IO(#[from] std::io::Error),
 | ||||||
|  | /// #     #[error(transparent)]
 | ||||||
|  | /// #     Map(#[from] aya::maps::MapError),
 | ||||||
|  | /// #     #[error(transparent)]
 | ||||||
|  | /// #     Program(#[from] aya::programs::ProgramError),
 | ||||||
|  | /// #     #[error(transparent)]
 | ||||||
|  | /// #     Bpf(#[from] aya::BpfError)
 | ||||||
|  | /// # }
 | ||||||
|  | /// # let mut bpf = aya::Bpf::load(&[])?;
 | ||||||
|  | /// use std::fs::File;
 | ||||||
|  | /// use std::convert::TryInto;
 | ||||||
|  | /// use aya::programs::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)?;
 | ||||||
|  | /// # Ok::<(), Error>(())
 | ||||||
|  | /// ```
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | #[doc(alias = "BPF_PROG_TYPE_CGROUP_SOCKOPT")] | ||||||
|  | pub struct CgroupSockopt { | ||||||
|  |     pub(crate) data: ProgramData<CgroupSockoptLink>, | ||||||
|  |     pub(crate) attach_type: CgroupSockoptAttachType, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl CgroupSockopt { | ||||||
|  |     /// Loads the program inside the kernel.
 | ||||||
|  |     pub fn load(&mut self) -> Result<(), ProgramError> { | ||||||
|  |         self.data.expected_attach_type = Some(self.attach_type.into()); | ||||||
|  |         load_program(BPF_PROG_TYPE_CGROUP_SOCKOPT, &mut self.data) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Attaches the program to the given cgroup.
 | ||||||
|  |     ///
 | ||||||
|  |     /// The returned value can be used to detach, see [CgroupSockopt::detach].
 | ||||||
|  |     pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSockoptLinkId, ProgramError> { | ||||||
|  |         let prog_fd = self.data.fd_or_err()?; | ||||||
|  |         let cgroup_fd = cgroup.as_raw_fd(); | ||||||
|  |         let attach_type = self.data.expected_attach_type.unwrap(); | ||||||
|  |         let k_ver = kernel_version().unwrap(); | ||||||
|  |         if k_ver >= (5, 7, 0) { | ||||||
|  |             let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err( | ||||||
|  |                 |(_, io_error)| ProgramError::SyscallError { | ||||||
|  |                     call: "bpf_link_create".to_owned(), | ||||||
|  |                     io_error, | ||||||
|  |                 }, | ||||||
|  |             )? as RawFd; | ||||||
|  |             self.data | ||||||
|  |                 .links | ||||||
|  |                 .insert(CgroupSockoptLink(CgroupSockoptLinkInner::Fd(FdLink::new( | ||||||
|  |                     link_fd, | ||||||
|  |                 )))) | ||||||
|  |         } else { | ||||||
|  |             bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| { | ||||||
|  |                 ProgramError::SyscallError { | ||||||
|  |                     call: "bpf_prog_attach".to_owned(), | ||||||
|  |                     io_error, | ||||||
|  |                 } | ||||||
|  |             })?; | ||||||
|  | 
 | ||||||
|  |             self.data | ||||||
|  |                 .links | ||||||
|  |                 .insert(CgroupSockoptLink(CgroupSockoptLinkInner::ProgAttach( | ||||||
|  |                     ProgAttachLink::new(prog_fd, cgroup_fd, attach_type), | ||||||
|  |                 ))) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Takes ownership of the link referenced by the provided link_id.
 | ||||||
|  |     ///
 | ||||||
|  |     /// The link will be detached on `Drop` and the caller is now responsible
 | ||||||
|  |     /// for managing its lifetime.
 | ||||||
|  |     pub fn forget_link( | ||||||
|  |         &mut self, | ||||||
|  |         link_id: CgroupSockoptLinkId, | ||||||
|  |     ) -> Result<OwnedLink<CgroupSockoptLink>, ProgramError> { | ||||||
|  |         Ok(OwnedLink::new(self.data.forget_link(link_id)?)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Detaches the program.
 | ||||||
|  |     ///
 | ||||||
|  |     /// See [CgroupSockopt::attach].
 | ||||||
|  |     pub fn detach(&mut self, link_id: CgroupSockoptLinkId) -> Result<(), ProgramError> { | ||||||
|  |         self.data.links.remove(link_id) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Hash, Eq, PartialEq)] | ||||||
|  | enum CgroupSockoptLinkIdInner { | ||||||
|  |     Fd(<FdLink as Link>::Id), | ||||||
|  |     ProgAttach(<ProgAttachLink as Link>::Id), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | enum CgroupSockoptLinkInner { | ||||||
|  |     Fd(FdLink), | ||||||
|  |     ProgAttach(ProgAttachLink), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Link for CgroupSockoptLinkInner { | ||||||
|  |     type Id = CgroupSockoptLinkIdInner; | ||||||
|  | 
 | ||||||
|  |     fn id(&self) -> Self::Id { | ||||||
|  |         match self { | ||||||
|  |             CgroupSockoptLinkInner::Fd(fd) => CgroupSockoptLinkIdInner::Fd(fd.id()), | ||||||
|  |             CgroupSockoptLinkInner::ProgAttach(p) => CgroupSockoptLinkIdInner::ProgAttach(p.id()), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn detach(self) -> Result<(), ProgramError> { | ||||||
|  |         match self { | ||||||
|  |             CgroupSockoptLinkInner::Fd(fd) => fd.detach(), | ||||||
|  |             CgroupSockoptLinkInner::ProgAttach(p) => p.detach(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | define_link_wrapper!( | ||||||
|  |     /// The link used by [CgroupSockopt] programs.
 | ||||||
|  |     CgroupSockoptLink, | ||||||
|  |     /// The type returned by [CgroupSockopt::attach]. Can be passed to [CgroupSockopt::detach].
 | ||||||
|  |     CgroupSockoptLinkId, | ||||||
|  |     CgroupSockoptLinkInner, | ||||||
|  |     CgroupSockoptLinkIdInner | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | /// Defines where to attach a [`CgroupSockopt`] program.
 | ||||||
|  | #[derive(Copy, Clone, Debug)] | ||||||
|  | pub enum CgroupSockoptAttachType { | ||||||
|  |     /// Attach to GetSockopt.
 | ||||||
|  |     Get, | ||||||
|  |     /// Attach to SetSockopt.
 | ||||||
|  |     Set, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<CgroupSockoptAttachType> for bpf_attach_type { | ||||||
|  |     fn from(s: CgroupSockoptAttachType) -> bpf_attach_type { | ||||||
|  |         match s { | ||||||
|  |             CgroupSockoptAttachType::Get => bpf_attach_type::BPF_CGROUP_GETSOCKOPT, | ||||||
|  |             CgroupSockoptAttachType::Set => bpf_attach_type::BPF_CGROUP_SETSOCKOPT, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Error)] | ||||||
|  | #[error("{0} is not a valid attach type for a CGROUP_SOCKOPT program")] | ||||||
|  | pub(crate) struct InvalidAttachType(String); | ||||||
|  | 
 | ||||||
|  | impl CgroupSockoptAttachType { | ||||||
|  |     pub(crate) fn try_from(value: &str) -> Result<CgroupSockoptAttachType, InvalidAttachType> { | ||||||
|  |         match value { | ||||||
|  |             "getsockopt" => Ok(CgroupSockoptAttachType::Get), | ||||||
|  |             "setsockopt" => Ok(CgroupSockoptAttachType::Set), | ||||||
|  |             _ => Err(InvalidAttachType(value.to_owned())), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,19 @@ | |||||||
|  | use core::ffi::c_void; | ||||||
|  | 
 | ||||||
|  | use crate::{bindings::bpf_sockopt, BpfContext}; | ||||||
|  | 
 | ||||||
|  | pub struct SockoptContext { | ||||||
|  |     pub sockopt: *mut bpf_sockopt, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl SockoptContext { | ||||||
|  |     pub fn new(sockopt: *mut bpf_sockopt) -> SockoptContext { | ||||||
|  |         SockoptContext { sockopt } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl BpfContext for SockoptContext { | ||||||
|  |     fn as_ptr(&self) -> *mut c_void { | ||||||
|  |         self.sockopt as *mut _ | ||||||
|  |     } | ||||||
|  | } | ||||||
					Loading…
					
					
				
		Reference in New Issue