mirror of https://github.com/aya-rs/aya
programs: add support for attaching and detaching TC programs
This change adds support for attaching TC programs directly from aya, without having to use iproute2/tc.pull/1/head
parent
d085bdb89f
commit
6974d349e8
@ -1,42 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
generated::bpf_prog_type::{BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_SCHED_CLS},
|
|
||||||
programs::{load_program, ProgramData, ProgramError},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SchedClassifier {
|
|
||||||
pub(crate) data: ProgramData,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SchedClassifier {
|
|
||||||
/// Loads the program inside the kernel.
|
|
||||||
///
|
|
||||||
/// See also [`Program::load`](crate::programs::Program::load).
|
|
||||||
pub fn load(&mut self) -> Result<(), ProgramError> {
|
|
||||||
load_program(BPF_PROG_TYPE_SCHED_CLS, &mut self.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the name of the program.
|
|
||||||
pub fn name(&self) -> String {
|
|
||||||
self.data.name.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SchedAction {
|
|
||||||
pub(crate) data: ProgramData,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SchedAction {
|
|
||||||
/// Loads the program inside the kernel.
|
|
||||||
///
|
|
||||||
/// See also [`Program::load`](crate::programs::Program::load).
|
|
||||||
pub fn load(&mut self) -> Result<(), ProgramError> {
|
|
||||||
load_program(BPF_PROG_TYPE_SCHED_ACT, &mut self.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the name of the program.
|
|
||||||
pub fn name(&self) -> String {
|
|
||||||
self.data.name.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,118 @@
|
|||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use std::{io, os::unix::io::RawFd};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
generated::{
|
||||||
|
TC_H_CLSACT, TC_H_MIN_INGRESS, TC_H_MIN_EGRESS,
|
||||||
|
bpf_prog_type::BPF_PROG_TYPE_SCHED_CLS,
|
||||||
|
},
|
||||||
|
programs::{Link, LinkRef, load_program, ProgramData, ProgramError},
|
||||||
|
sys::{netlink_qdisc_add_clsact, netlink_qdisc_attach, netlink_qdisc_detach},
|
||||||
|
util::{ifindex_from_ifname, tc_handler_make},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum TcAttachPoint {
|
||||||
|
Ingress = TC_H_MIN_INGRESS,
|
||||||
|
Egress = TC_H_MIN_EGRESS,
|
||||||
|
Custom,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SchedClassifier {
|
||||||
|
pub(crate) data: ProgramData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum TcError {
|
||||||
|
#[error("netlink error while attaching ebpf program to tc")]
|
||||||
|
NetlinkError {
|
||||||
|
#[source]
|
||||||
|
io_error: io::Error,
|
||||||
|
},
|
||||||
|
#[error("the clsact qdisc is already attached")]
|
||||||
|
AlreadyAttached,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TcLink {
|
||||||
|
if_index: i32,
|
||||||
|
attach_point: TcAttachPoint,
|
||||||
|
prog_fd: Option<RawFd>,
|
||||||
|
priority: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TcAttachPoint {
|
||||||
|
pub fn tcm_parent(&self, parent: u32) -> Result<u32, io::Error> {
|
||||||
|
match *self {
|
||||||
|
TcAttachPoint::Custom => {
|
||||||
|
if parent == 0 {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "Parent must be non-zero for Custom attach points"));
|
||||||
|
}
|
||||||
|
Ok(parent)
|
||||||
|
}
|
||||||
|
_ => Ok(tc_handler_make(TC_H_CLSACT, (*self).clone() as u32))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SchedClassifier {
|
||||||
|
/// Loads the program inside the kernel.
|
||||||
|
///
|
||||||
|
/// See also [`Program::load`](crate::programs::Program::load).
|
||||||
|
pub fn load(&mut self) -> Result<(), ProgramError> {
|
||||||
|
load_program(BPF_PROG_TYPE_SCHED_CLS, &mut self.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the name of the program.
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
self.data.name.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attaches the program to the given `interface` and `attach-point`
|
||||||
|
pub fn attach(&mut self, interface: &str, attach_point: TcAttachPoint) -> Result<LinkRef, ProgramError> {
|
||||||
|
let prog_fd = self.data.fd_or_err()?;
|
||||||
|
let if_index = unsafe { ifindex_from_ifname(interface) }
|
||||||
|
.map_err(|io_error| TcError::NetlinkError { io_error })?;
|
||||||
|
let prog_name = self.name();
|
||||||
|
let priority = unsafe { netlink_qdisc_attach(if_index as i32, &attach_point, prog_fd, &prog_name[..]) }
|
||||||
|
.map_err(|io_error| TcError::NetlinkError { io_error })?;
|
||||||
|
Ok(self.data.link(TcLink {
|
||||||
|
if_index: if_index as i32,
|
||||||
|
attach_point,
|
||||||
|
prog_fd: Some(prog_fd),
|
||||||
|
priority,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add "clasct" qdisc to an interface
|
||||||
|
pub fn qdisc_add_clsact_to_interface(if_name: &str) -> Result<(), ProgramError> {
|
||||||
|
// unsafe wrapper
|
||||||
|
let if_index = unsafe { ifindex_from_ifname(if_name) }
|
||||||
|
.map_err(|_| ProgramError::UnknownInterface {name: if_name.to_string()})?;
|
||||||
|
unsafe { netlink_qdisc_add_clsact(if_index as i32) }
|
||||||
|
.map_err(|io_error| TcError::NetlinkError { io_error })?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TcLink {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Link for TcLink {
|
||||||
|
fn detach(&mut self) -> Result<(), ProgramError> {
|
||||||
|
if let Some(_) = self.prog_fd.take() {
|
||||||
|
unsafe { netlink_qdisc_detach(self.if_index, &self.attach_point, self.priority) }
|
||||||
|
.map_err(|io_error| TcError::NetlinkError { io_error })?;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ProgramError::AlreadyDetached)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue