Use proper error handling instead of lurking panics everywhere
This commit is contained in:
1 parent
999987d157
commit
214ffef6f3
11 files changed
+349
-392
No files matched your search
+80
-39
@@ -1,19 +1,49 @@
|
||||
use crate::cake::TcaCake;
|
||||
use crate::error::NoQdiscFoundError;
|
||||
|
||||
use neli::consts::nl::{NlmF, NlmFFlags};
|
||||
use neli::consts::rtnl::{Arphrd, IffFlags, Ifla, RtAddrFamily, Rtm, Tca};
|
||||
use neli::consts::socket::NlFamily;
|
||||
use neli::err::NlError;
|
||||
use neli::err::{NlError, SerError};
|
||||
use neli::nl::{NlPayload, Nlmsghdr};
|
||||
use neli::rtnl::{Ifinfomsg, Rtattr, Tcmsg};
|
||||
use neli::socket::NlSocketHandle;
|
||||
use neli::types::{Buffer, RtBuffer};
|
||||
use serde::Deserialize;
|
||||
use std::error::Error;
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
|
||||
use bincode::deserialize;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NetlinkError {
|
||||
#[error("Couldn't deserialize to struct")]
|
||||
Deserialization(#[from] Box<bincode::ErrorKind>),
|
||||
|
||||
#[error("Couldn't find intreface `{0}`")]
|
||||
InterfaceNotFound(String),
|
||||
|
||||
#[error("Netlink interface error")]
|
||||
NlInterfaceError(#[from] NlError<Rtm, Ifinfomsg>),
|
||||
|
||||
#[error("Netlink interface error")]
|
||||
NlQdiscError(#[from] NlError<Rtm, Tcmsg>),
|
||||
|
||||
#[error("Couldn't find CAKE qdisc on interface `{0}`")]
|
||||
NoQdiscFound(String),
|
||||
|
||||
#[error("Couldn't find interface statistics: `{0}`")]
|
||||
NoInterfaceStatsFound(String),
|
||||
|
||||
#[error("Couldn't open Netlink socket")]
|
||||
OpenSocket(#[from] io::Error),
|
||||
|
||||
#[error("Serialization error")]
|
||||
Serialization(#[from] SerError),
|
||||
|
||||
#[error("Invalid Rtm type (expected {expected:?}, found {found:?})")]
|
||||
WrongType { expected: Rtm, found: Rtm },
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Copy, Clone, Default, Debug)]
|
||||
pub struct RtnlLinkStats64 {
|
||||
pub rx_packets: u64,
|
||||
@@ -43,7 +73,7 @@ pub struct RtnlLinkStats64 {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Qdisc {
|
||||
ifindex: i32,
|
||||
handle: u32,
|
||||
@@ -55,13 +85,13 @@ pub struct Qdisc {
|
||||
pub struct Netlink {}
|
||||
|
||||
impl Netlink {
|
||||
fn nl_interface_get(socket: &mut NlSocketHandle, ifname: &str) -> Result<(), Box<dyn Error>> {
|
||||
fn nl_interface_get(socket: &mut NlSocketHandle, ifname: &str) -> Result<(), NetlinkError> {
|
||||
let mut attrs = RtBuffer::new();
|
||||
|
||||
const RTEXT_FILTER_VF: i32 = 1 << 0;
|
||||
|
||||
let attr_ifname = Rtattr::new(None, Ifla::Ifname, ifname).unwrap();
|
||||
let attr_ext_mask = Rtattr::new(None, Ifla::ExtMask, RTEXT_FILTER_VF).unwrap();
|
||||
let attr_ifname = Rtattr::new(None, Ifla::Ifname, ifname)?;
|
||||
let attr_ext_mask = Rtattr::new(None, Ifla::ExtMask, RTEXT_FILTER_VF)?;
|
||||
attrs.push(attr_ifname);
|
||||
attrs.push(attr_ext_mask);
|
||||
|
||||
@@ -88,28 +118,7 @@ impl Netlink {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn find_interface(ifname: &str) -> Result<i32, Box<dyn Error>> {
|
||||
let mut socket = NlSocketHandle::connect(NlFamily::Route, None, &[]).unwrap();
|
||||
|
||||
Self::nl_interface_get(&mut socket, ifname).expect("Wrong when sending intf");
|
||||
|
||||
for response in socket.iter(false) {
|
||||
let header: Nlmsghdr<Rtm, Ifinfomsg> = response?;
|
||||
|
||||
if header.nl_type != Rtm::Newlink {
|
||||
return Err(Box::new(NlError::msg("Netlink error retrieving link")));
|
||||
}
|
||||
|
||||
if let NlPayload::Payload(p) = header.nl_payload {
|
||||
return Ok(p.ifi_index);
|
||||
}
|
||||
}
|
||||
|
||||
// we shouldn't reach here
|
||||
Err(Box::new(NlError::msg("Netlink error retrieving link")))
|
||||
}
|
||||
|
||||
pub fn get_interface_stats(ifname: &str) -> Result<RtnlLinkStats64, Box<dyn Error>> {
|
||||
pub fn find_interface(ifname: &str) -> Result<i32, NetlinkError> {
|
||||
let mut socket = NlSocketHandle::connect(NlFamily::Route, None, &[]).unwrap();
|
||||
|
||||
Self::nl_interface_get(&mut socket, ifname)?;
|
||||
@@ -118,7 +127,34 @@ impl Netlink {
|
||||
let header: Nlmsghdr<Rtm, Ifinfomsg> = response?;
|
||||
|
||||
if header.nl_type != Rtm::Newlink {
|
||||
return Err(Box::new(NlError::msg("Netlink error retrieving link")));
|
||||
return Err(NetlinkError::WrongType {
|
||||
expected: Rtm::Newlink,
|
||||
found: header.nl_type,
|
||||
});
|
||||
}
|
||||
|
||||
if let NlPayload::Payload(p) = header.nl_payload {
|
||||
return Ok(p.ifi_index);
|
||||
}
|
||||
}
|
||||
|
||||
// we shouldn't reach here
|
||||
Err(NetlinkError::InterfaceNotFound(ifname.to_string()))
|
||||
}
|
||||
|
||||
pub fn get_interface_stats(ifname: &str) -> Result<RtnlLinkStats64, NetlinkError> {
|
||||
let mut socket = NlSocketHandle::connect(NlFamily::Route, None, &[])?;
|
||||
|
||||
Self::nl_interface_get(&mut socket, ifname)?;
|
||||
|
||||
for response in socket.iter(false) {
|
||||
let header: Nlmsghdr<Rtm, Ifinfomsg> = response?;
|
||||
|
||||
if header.nl_type != Rtm::Newlink {
|
||||
return Err(NetlinkError::WrongType {
|
||||
expected: Rtm::Newlink,
|
||||
found: header.nl_type,
|
||||
});
|
||||
}
|
||||
|
||||
if let NlPayload::Payload(p) = header.nl_payload {
|
||||
@@ -126,7 +162,7 @@ impl Netlink {
|
||||
if attr.rta_type == Ifla::Stats64 {
|
||||
let buf = attr.rta_payload.as_ref();
|
||||
|
||||
let stats: RtnlLinkStats64 = deserialize(buf).unwrap();
|
||||
let stats: RtnlLinkStats64 = deserialize(buf)?;
|
||||
|
||||
return Ok(stats);
|
||||
}
|
||||
@@ -134,11 +170,11 @@ impl Netlink {
|
||||
}
|
||||
}
|
||||
|
||||
Err(Box::new(NlError::msg("Error getting stats")))
|
||||
Err(NetlinkError::NoInterfaceStatsFound(ifname.to_string()))
|
||||
}
|
||||
|
||||
pub fn qdisc_from_ifindex(ifindex: i32) -> Result<Qdisc, Box<dyn Error>> {
|
||||
let mut socket = NlSocketHandle::connect(NlFamily::Route, None, &[]).unwrap();
|
||||
pub fn qdisc_from_ifindex(ifindex: i32) -> Result<Qdisc, NetlinkError> {
|
||||
let mut socket = NlSocketHandle::connect(NlFamily::Route, None, &[])?;
|
||||
let tc_msg = Tcmsg::new(
|
||||
u8::from(RtAddrFamily::Unspecified),
|
||||
0,
|
||||
@@ -157,14 +193,19 @@ impl Netlink {
|
||||
NlPayload::Payload(tc_msg),
|
||||
);
|
||||
|
||||
socket.send(nlhdr)?;
|
||||
if let Err(e) = socket.send(nlhdr) {
|
||||
return Err(NetlinkError::Serialization(e));
|
||||
}
|
||||
|
||||
for response in socket.iter(false) {
|
||||
let header: Nlmsghdr<Rtm, Tcmsg> = response?;
|
||||
|
||||
if let NlPayload::Payload(p) = header.nl_payload {
|
||||
if header.nl_type != Rtm::Newqdisc {
|
||||
return Err(Box::new(NlError::msg("Netlink error retrieving qdisc")));
|
||||
return Err(NetlinkError::WrongType {
|
||||
expected: Rtm::Newqdisc,
|
||||
found: header.nl_type,
|
||||
});
|
||||
}
|
||||
|
||||
if p.tcm_ifindex == ifindex {
|
||||
@@ -196,15 +237,15 @@ impl Netlink {
|
||||
}
|
||||
}
|
||||
|
||||
return Err(Box::new(NoQdiscFoundError));
|
||||
return Err(NetlinkError::NoQdiscFound(ifindex.to_string()));
|
||||
}
|
||||
|
||||
pub fn qdisc_from_ifname(ifname: &str) -> Result<Qdisc, Box<dyn Error>> {
|
||||
pub fn qdisc_from_ifname(ifname: &str) -> Result<Qdisc, NetlinkError> {
|
||||
let ifindex = Netlink::find_interface(ifname)?;
|
||||
Netlink::qdisc_from_ifindex(ifindex)
|
||||
}
|
||||
|
||||
pub fn set_qdisc_rate(qdisc: Qdisc, bandwidth_kbit: u64) -> Result<(), Box<dyn Error>> {
|
||||
pub fn set_qdisc_rate(qdisc: Qdisc, bandwidth_kbit: u64) -> Result<(), NetlinkError> {
|
||||
let mut socket = NlSocketHandle::connect(NlFamily::Route, None, &[])?;
|
||||
let bandwidth = bandwidth_kbit * 1000 / 8;
|
||||
|
||||
|
||||
Reference in new issue
Block a user