Use proper error handling instead of lurking panics everywhere

This commit is contained in:
Nils Andreas Svee committed 2022-10-04 16:20:24 +02:00
1 parent 999987d157
commit 214ffef6f3
11 files changed
+349 -392

No files matched your search

+80 -39
View File
@@ -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;