use std::os::fd::AsFd;
use aya_obj::generated::{
bpf_attach_type::BPF_FLOW_DISSECTOR, bpf_prog_type::BPF_PROG_TYPE_FLOW_DISSECTOR,
};
use crate::{
programs::{
CgroupAttachMode, FdLink, Link, ProgAttachLink, ProgramData, ProgramError, ProgramType,
define_link_wrapper, id_as_key, impl_try_into_fdlink, load_program,
},
sys::{LinkTarget, SyscallError, bpf_link_create},
util::KernelVersion,
};
#[derive(Debug)]
#[doc(alias = "BPF_PROG_TYPE_FLOW_DISSECTOR")]
pub struct FlowDissector {
pub(crate) data: ProgramData<FlowDissectorLink>,
}
impl FlowDissector {
pub const PROGRAM_TYPE: ProgramType = ProgramType::FlowDissector;
pub fn load(&mut self) -> Result<(), ProgramError> {
self.data.expected_attach_type = Some(BPF_FLOW_DISSECTOR);
load_program(BPF_PROG_TYPE_FLOW_DISSECTOR, &mut self.data)
}
pub fn attach<T: AsFd>(&mut self, netns: T) -> Result<FlowDissectorLinkId, ProgramError> {
let prog_fd = self.fd()?;
let prog_fd = prog_fd.as_fd();
let netns_fd = netns.as_fd();
if KernelVersion::at_least(5, 7, 0) {
let link_fd = bpf_link_create(
prog_fd,
LinkTarget::Fd(netns_fd),
BPF_FLOW_DISSECTOR,
0,
None,
)
.map_err(|io_error| SyscallError {
call: "bpf_link_create",
io_error,
})?;
self.data
.links
.insert(FlowDissectorLink::new(FlowDissectorLinkInner::Fd(
FdLink::new(link_fd),
)))
} else {
let link = ProgAttachLink::attach(
prog_fd,
netns_fd,
BPF_FLOW_DISSECTOR,
CgroupAttachMode::default(),
)?;
self.data
.links
.insert(FlowDissectorLink::new(FlowDissectorLinkInner::ProgAttach(
link,
)))
}
}
}
#[derive(Debug, Hash, Eq, PartialEq)]
enum FlowDissectorLinkIdInner {
Fd(<FdLink as Link>::Id),
ProgAttach(<ProgAttachLink as Link>::Id),
}
#[derive(Debug)]
enum FlowDissectorLinkInner {
Fd(FdLink),
ProgAttach(ProgAttachLink),
}
impl Link for FlowDissectorLinkInner {
type Id = FlowDissectorLinkIdInner;
fn id(&self) -> Self::Id {
match self {
Self::Fd(fd) => FlowDissectorLinkIdInner::Fd(fd.id()),
Self::ProgAttach(p) => FlowDissectorLinkIdInner::ProgAttach(p.id()),
}
}
fn detach(self) -> Result<(), ProgramError> {
match self {
Self::Fd(fd) => fd.detach(),
Self::ProgAttach(p) => p.detach(),
}
}
}
id_as_key!(FlowDissectorLinkInner, FlowDissectorLinkIdInner);
define_link_wrapper!(
FlowDissectorLink,
FlowDissectorLinkId,
FlowDissectorLinkInner,
FlowDissectorLinkIdInner,
FlowDissector,
);
impl_try_into_fdlink!(FlowDissectorLink, FlowDissectorLinkInner);