|
|
@ -63,7 +63,7 @@ pub enum TcAttachType {
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// let prog: &mut SchedClassifier = bpf.program_mut("redirect_ingress").unwrap().try_into()?;
|
|
|
|
/// let prog: &mut SchedClassifier = bpf.program_mut("redirect_ingress").unwrap().try_into()?;
|
|
|
|
/// prog.load()?;
|
|
|
|
/// prog.load()?;
|
|
|
|
/// prog.attach("eth0", TcAttachType::Ingress, 0)?;
|
|
|
|
/// prog.attach("eth0", TcAttachType::Ingress)?;
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Ok::<(), Error>(())
|
|
|
|
/// # Ok::<(), Error>(())
|
|
|
|
/// ```
|
|
|
|
/// ```
|
|
|
@ -99,17 +99,24 @@ impl TcAttachType {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Options for SchedClassifier attach
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
|
|
|
|
pub struct TcOptions {
|
|
|
|
|
|
|
|
/// Priority assigned to tc program with lower number = higher priority.
|
|
|
|
|
|
|
|
/// If set to default (0), the system chooses the next highest priority or 49152 if no filters exist yet
|
|
|
|
|
|
|
|
pub priority: u16,
|
|
|
|
|
|
|
|
/// Handle used to uniquely identify a program at a given priority level.
|
|
|
|
|
|
|
|
/// If set to default (0), the system chooses a handle.
|
|
|
|
|
|
|
|
pub handle: u32,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl SchedClassifier {
|
|
|
|
impl SchedClassifier {
|
|
|
|
/// Loads the program inside the kernel.
|
|
|
|
/// Loads the program inside the kernel.
|
|
|
|
pub fn load(&mut self) -> Result<(), ProgramError> {
|
|
|
|
pub fn load(&mut self) -> Result<(), ProgramError> {
|
|
|
|
load_program(BPF_PROG_TYPE_SCHED_CLS, &mut self.data)
|
|
|
|
load_program(BPF_PROG_TYPE_SCHED_CLS, &mut self.data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Attaches the program to the given `interface`.
|
|
|
|
/// Attaches the program to the given `interface` using the default options.
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Valid priority values range from 0 - 65535 with lower number = higher priority.
|
|
|
|
|
|
|
|
/// 0 means let the system choose the next highest priority, or 49152 if no filters exist yet.
|
|
|
|
|
|
|
|
/// All other values in the range are taken as an explicit priority setting (aka "preference").
|
|
|
|
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// The returned value can be used to detach, see [SchedClassifier::detach].
|
|
|
|
/// The returned value can be used to detach, see [SchedClassifier::detach].
|
|
|
|
///
|
|
|
|
///
|
|
|
@ -123,13 +130,38 @@ impl SchedClassifier {
|
|
|
|
&mut self,
|
|
|
|
&mut self,
|
|
|
|
interface: &str,
|
|
|
|
interface: &str,
|
|
|
|
attach_type: TcAttachType,
|
|
|
|
attach_type: TcAttachType,
|
|
|
|
priority: u16,
|
|
|
|
) -> Result<SchedClassifierLinkId, ProgramError> {
|
|
|
|
|
|
|
|
self.attach_with_options(interface, attach_type, TcOptions::default())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Attaches the program to the given `interface` with options defined in [`TcOptions`].
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// The returned value can be used to detach, see [SchedClassifier::detach].
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// [`TcError::NetlinkError`] is returned if attaching fails. A common cause
|
|
|
|
|
|
|
|
/// of failure is not having added the `clsact` qdisc to the given
|
|
|
|
|
|
|
|
/// interface, see [`qdisc_add_clsact`]
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
pub fn attach_with_options(
|
|
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
|
|
interface: &str,
|
|
|
|
|
|
|
|
attach_type: TcAttachType,
|
|
|
|
|
|
|
|
options: TcOptions,
|
|
|
|
) -> Result<SchedClassifierLinkId, ProgramError> {
|
|
|
|
) -> Result<SchedClassifierLinkId, ProgramError> {
|
|
|
|
let prog_fd = self.data.fd_or_err()?;
|
|
|
|
let prog_fd = self.data.fd_or_err()?;
|
|
|
|
let if_index = ifindex_from_ifname(interface)
|
|
|
|
let if_index = ifindex_from_ifname(interface)
|
|
|
|
.map_err(|io_error| TcError::NetlinkError { io_error })?;
|
|
|
|
.map_err(|io_error| TcError::NetlinkError { io_error })?;
|
|
|
|
let priority = unsafe {
|
|
|
|
let (priority, handle) = unsafe {
|
|
|
|
netlink_qdisc_attach(if_index as i32, &attach_type, prog_fd, &self.name, priority)
|
|
|
|
netlink_qdisc_attach(
|
|
|
|
|
|
|
|
if_index as i32,
|
|
|
|
|
|
|
|
&attach_type,
|
|
|
|
|
|
|
|
prog_fd,
|
|
|
|
|
|
|
|
&self.name,
|
|
|
|
|
|
|
|
options.priority,
|
|
|
|
|
|
|
|
options.handle,
|
|
|
|
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.map_err(|io_error| TcError::NetlinkError { io_error })?;
|
|
|
|
.map_err(|io_error| TcError::NetlinkError { io_error })?;
|
|
|
|
|
|
|
|
|
|
|
@ -137,6 +169,7 @@ impl SchedClassifier {
|
|
|
|
if_index: if_index as i32,
|
|
|
|
if_index: if_index as i32,
|
|
|
|
attach_type,
|
|
|
|
attach_type,
|
|
|
|
priority,
|
|
|
|
priority,
|
|
|
|
|
|
|
|
handle,
|
|
|
|
}))
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -160,25 +193,28 @@ impl SchedClassifier {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Hash, Eq, PartialEq)]
|
|
|
|
#[derive(Debug, Hash, Eq, PartialEq)]
|
|
|
|
pub(crate) struct TcLinkId(i32, TcAttachType, u16);
|
|
|
|
pub(crate) struct TcLinkId(i32, TcAttachType, u16, u32);
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct TcLink {
|
|
|
|
struct TcLink {
|
|
|
|
if_index: i32,
|
|
|
|
if_index: i32,
|
|
|
|
attach_type: TcAttachType,
|
|
|
|
attach_type: TcAttachType,
|
|
|
|
priority: u16,
|
|
|
|
priority: u16,
|
|
|
|
|
|
|
|
handle: u32,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Link for TcLink {
|
|
|
|
impl Link for TcLink {
|
|
|
|
type Id = TcLinkId;
|
|
|
|
type Id = TcLinkId;
|
|
|
|
|
|
|
|
|
|
|
|
fn id(&self) -> Self::Id {
|
|
|
|
fn id(&self) -> Self::Id {
|
|
|
|
TcLinkId(self.if_index, self.attach_type, self.priority)
|
|
|
|
TcLinkId(self.if_index, self.attach_type, self.priority, self.handle)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn detach(self) -> Result<(), ProgramError> {
|
|
|
|
fn detach(self) -> Result<(), ProgramError> {
|
|
|
|
unsafe { netlink_qdisc_detach(self.if_index, &self.attach_type, self.priority) }
|
|
|
|
unsafe {
|
|
|
|
.map_err(|io_error| TcError::NetlinkError { io_error })?;
|
|
|
|
netlink_qdisc_detach(self.if_index, &self.attach_type, self.priority, self.handle)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.map_err(|io_error| TcError::NetlinkError { io_error })?;
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -233,16 +269,16 @@ fn qdisc_detach_program_fast(
|
|
|
|
) -> Result<(), io::Error> {
|
|
|
|
) -> Result<(), io::Error> {
|
|
|
|
let if_index = ifindex_from_ifname(if_name)? as i32;
|
|
|
|
let if_index = ifindex_from_ifname(if_name)? as i32;
|
|
|
|
|
|
|
|
|
|
|
|
let prios = unsafe { netlink_find_filter_with_name(if_index, attach_type, name)? };
|
|
|
|
let filter_info = unsafe { netlink_find_filter_with_name(if_index, attach_type, name)? };
|
|
|
|
if prios.is_empty() {
|
|
|
|
if filter_info.is_empty() {
|
|
|
|
return Err(io::Error::new(
|
|
|
|
return Err(io::Error::new(
|
|
|
|
io::ErrorKind::NotFound,
|
|
|
|
io::ErrorKind::NotFound,
|
|
|
|
name.to_string_lossy(),
|
|
|
|
name.to_string_lossy(),
|
|
|
|
));
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for prio in prios {
|
|
|
|
for (prio, handle) in filter_info {
|
|
|
|
unsafe { netlink_qdisc_detach(if_index, &attach_type, prio)? };
|
|
|
|
unsafe { netlink_qdisc_detach(if_index, &attach_type, prio, handle)? };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|