From 4ef43b7c5b7b5554946d931cdd9d1e63d50a8805 Mon Sep 17 00:00:00 2001 From: Miguel Flores Ruiz de Eguino <1889916+miguelfrde@users.noreply.github.com> Date: Fri, 19 Apr 2024 17:57:34 -0700 Subject: [PATCH 1/3] Introduce typed errors instead of raw anyhow errors This enables downstream clients to be able to match on specific errors and handle specific error conditions in different ways without having to compare strings meant for humans reading. --- Cargo.toml | 3 +- src/address/attribute.rs | 2 + src/address/cache_info.rs | 2 + src/address/message.rs | 3 + src/link/af_spec/bridge.rs | 2 + src/link/af_spec/inet.rs | 3 + src/link/af_spec/inet6.rs | 2 + src/link/af_spec/inet6_cache.rs | 1 + src/link/af_spec/inet6_devconf.rs | 1 + src/link/af_spec/inet6_icmp.rs | 1 + src/link/af_spec/inet6_stats.rs | 1 + src/link/af_spec/unspec.rs | 1 + src/link/attribute.rs | 3 +- src/link/down_reason.rs | 1 + src/link/event.rs | 1 + src/link/header.rs | 1 + src/link/link_info/bond.rs | 2 + src/link/link_info/bond_port.rs | 1 + src/link/link_info/bridge.rs | 3 + src/link/link_info/bridge_port.rs | 1 + src/link/link_info/gre.rs | 1 + src/link/link_info/gre6.rs | 1 + src/link/link_info/gre_tap.rs | 1 + src/link/link_info/gre_tap6.rs | 2 + src/link/link_info/gtp.rs | 1 + src/link/link_info/hsr.rs | 1 + src/link/link_info/info_port.rs | 1 + src/link/link_info/infos.rs | 2 + src/link/link_info/ipoib.rs | 1 + src/link/link_info/ipvlan.rs | 2 + src/link/link_info/mac_vlan.rs | 2 + src/link/link_info/macsec.rs | 1 + src/link/link_info/sit.rs | 1 + src/link/link_info/tun.rs | 1 + src/link/link_info/veth.rs | 1 + src/link/link_info/vlan.rs | 2 + src/link/link_info/vrf.rs | 1 + src/link/link_info/vti.rs | 1 + src/link/link_info/vxlan.rs | 1 + src/link/link_info/xfrm.rs | 1 + src/link/link_info/xstats.rs | 1 + src/link/map.rs | 1 + src/link/message.rs | 2 + src/link/phys_id.rs | 1 + src/link/prop_list.rs | 1 + src/link/proto_info/bridge.rs | 2 + src/link/proto_info/inet6.rs | 2 + src/link/sriov/broadcast.rs | 1 + src/link/sriov/guid.rs | 1 + src/link/sriov/link_state.rs | 1 + src/link/sriov/mac.rs | 1 + src/link/sriov/rate.rs | 1 + src/link/sriov/rss_query.rs | 1 + src/link/sriov/spoofchk.rs | 1 + src/link/sriov/stats.rs | 1 + src/link/sriov/trust.rs | 1 + src/link/sriov/tx_rate.rs | 1 + src/link/sriov/vf_list.rs | 3 + src/link/sriov/vf_port.rs | 3 + src/link/sriov/vf_vlan.rs | 2 + src/link/sriov/vlan.rs | 1 + src/link/stats.rs | 1 + src/link/stats64.rs | 1 + src/link/wireless.rs | 1 + src/link/xdp.rs | 2 + src/message.rs | 152 ++++++++++++++++++------------ src/neighbour/attribute.rs | 1 + src/neighbour/cache_info.rs | 1 + src/neighbour/header.rs | 1 + src/neighbour/message.rs | 2 + src/neighbour_table/attribute.rs | 1 + src/neighbour_table/config.rs | 1 + src/neighbour_table/header.rs | 1 + src/neighbour_table/message.rs | 2 + src/neighbour_table/param.rs | 2 + src/neighbour_table/stats.rs | 1 + src/nsid/attribute.rs | 1 + src/nsid/header.rs | 1 + src/nsid/message.rs | 2 + src/prefix/attribute.rs | 1 + src/prefix/cache_info.rs | 1 + src/prefix/message.rs | 3 + src/route/attribute.rs | 1 + src/route/cache_info.rs | 1 + src/route/header.rs | 2 + src/route/lwtunnel.rs | 2 + src/route/message.rs | 2 + src/route/metrics.rs | 2 + src/route/mfc_stats.rs | 1 + src/route/mpls.rs | 1 + src/route/next_hops.rs | 2 + src/route/via.rs | 1 + src/rule/attribute.rs | 1 + src/rule/header.rs | 1 + src/rule/message.rs | 2 + src/tc/actions/action.rs | 3 + src/tc/actions/mirror.rs | 2 + src/tc/actions/nat.rs | 2 + src/tc/attribute.rs | 1 + src/tc/filters/cls_u32.rs | 3 + src/tc/filters/matchall.rs | 1 + src/tc/header.rs | 1 + src/tc/message.rs | 2 + src/tc/options.rs | 2 + src/tc/qdiscs/fq_codel.rs | 4 + src/tc/qdiscs/ingress.rs | 1 + src/tc/stats/basic.rs | 1 + src/tc/stats/compat.rs | 1 + src/tc/stats/queue.rs | 1 + src/tc/stats/stats2.rs | 1 + src/tc/stats/xstats.rs | 1 + 111 files changed, 251 insertions(+), 63 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a25aa39e..ea6cce15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,8 @@ byteorder = "1.3.2" libc = "0.2.66" log = { version = "0.4.20", features = ["std"] } netlink-packet-core = { version = "0.7.0" } -netlink-packet-utils = { version = "0.5.2" } +netlink-packet-utils = { path = "../netlink-packet-utils" } +thiserror = "1.0.58" [[example]] name = "dump_packet_links" diff --git a/src/address/attribute.rs b/src/address/attribute.rs index 3c72062d..2972b925 100644 --- a/src/address/attribute.rs +++ b/src/address/attribute.rs @@ -110,6 +110,8 @@ impl Nla for AddressAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for AddressAttribute { + type Error = DecodeError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/address/cache_info.rs b/src/address/cache_info.rs index b23edde1..4c94082e 100644 --- a/src/address/cache_info.rs +++ b/src/address/cache_info.rs @@ -24,6 +24,8 @@ buffer!(CacheInfoBuffer(ADDRESSS_CACHE_INFO_LEN) { }); impl> Parseable> for CacheInfo { + type Error = DecodeError; + fn parse(buf: &CacheInfoBuffer) -> Result { Ok(CacheInfo { ifa_preferred: buf.ifa_preferred(), diff --git a/src/address/message.rs b/src/address/message.rs index d8d9bd0e..dc57ccf1 100644 --- a/src/address/message.rs +++ b/src/address/message.rs @@ -76,6 +76,7 @@ impl Emitable for AddressMessage { } impl> Parseable> for AddressHeader { + type Error = DecodeError; fn parse(buf: &AddressMessageBuffer) -> Result { Ok(Self { family: buf.family().into(), @@ -90,6 +91,7 @@ impl> Parseable> for AddressHeader { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for AddressMessage { + type Error = DecodeError; fn parse(buf: &AddressMessageBuffer<&'a T>) -> Result { Ok(AddressMessage { header: AddressHeader::parse(buf) @@ -103,6 +105,7 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { + type Error = DecodeError; fn parse(buf: &AddressMessageBuffer<&'a T>) -> Result { let mut attributes = vec![]; for nla_buf in buf.attributes() { diff --git a/src/link/af_spec/bridge.rs b/src/link/af_spec/bridge.rs index 6a5352dd..66907420 100644 --- a/src/link/af_spec/bridge.rs +++ b/src/link/af_spec/bridge.rs @@ -52,6 +52,7 @@ impl nla::Nla for AfSpecBridge { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for AfSpecBridge { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::AfSpecBridge::*; @@ -80,6 +81,7 @@ pub(crate) struct VecAfSpecBridge(pub(crate) Vec); impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecAfSpecBridge { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; let err = "Invalid AF_INET NLA for IFLA_AF_SPEC(AF_BRIDGE)"; diff --git a/src/link/af_spec/inet.rs b/src/link/af_spec/inet.rs index 27a5a0da..b07b4f2c 100644 --- a/src/link/af_spec/inet.rs +++ b/src/link/af_spec/inet.rs @@ -27,6 +27,7 @@ pub(crate) struct VecAfSpecInet(pub(crate) Vec); impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecAfSpecInet { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; let err = "Invalid AF_INET NLA for IFLA_AF_SPEC(AF_UNSPEC)"; @@ -65,6 +66,7 @@ impl nla::Nla for AfSpecInet { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for AfSpecInet { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::AfSpecInet::*; @@ -162,6 +164,7 @@ pub struct InetDevConf { } impl> Parseable> for InetDevConf { + type Error = DecodeError; fn parse(buf: &InetDevConfBuffer) -> Result { Ok(Self { forwarding: buf.forwarding(), diff --git a/src/link/af_spec/inet6.rs b/src/link/af_spec/inet6.rs index b4034888..4e053d91 100644 --- a/src/link/af_spec/inet6.rs +++ b/src/link/af_spec/inet6.rs @@ -53,6 +53,7 @@ pub(crate) struct VecAfSpecInet6(pub(crate) Vec); impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecAfSpecInet6 { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; let err = "Invalid AF_INET6 NLA for IFLA_AF_SPEC(AF_UNSPEC)"; @@ -111,6 +112,7 @@ impl Nla for AfSpecInet6 { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for AfSpecInet6 { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::AfSpecInet6::*; diff --git a/src/link/af_spec/inet6_cache.rs b/src/link/af_spec/inet6_cache.rs index 8d28710d..9fc761d3 100644 --- a/src/link/af_spec/inet6_cache.rs +++ b/src/link/af_spec/inet6_cache.rs @@ -24,6 +24,7 @@ buffer!(Inet6CacheInfoBuffer(LINK_INET6_CACHE_INFO_LEN) { }); impl> Parseable> for Inet6CacheInfo { + type Error = DecodeError; fn parse(buf: &Inet6CacheInfoBuffer) -> Result { Ok(Self { max_reasm_len: buf.max_reasm_len(), diff --git a/src/link/af_spec/inet6_devconf.rs b/src/link/af_spec/inet6_devconf.rs index 740ce3da..38ad7622 100644 --- a/src/link/af_spec/inet6_devconf.rs +++ b/src/link/af_spec/inet6_devconf.rs @@ -72,6 +72,7 @@ buffer!(Inet6DevConfBuffer(LINK_INET6_DEV_CONF_LEN) { }); impl> Parseable> for Inet6DevConf { + type Error = DecodeError; fn parse(buf: &Inet6DevConfBuffer) -> Result { Ok(Self { forwarding: buf.forwarding(), diff --git a/src/link/af_spec/inet6_icmp.rs b/src/link/af_spec/inet6_icmp.rs index 238e3245..eb6a71ac 100644 --- a/src/link/af_spec/inet6_icmp.rs +++ b/src/link/af_spec/inet6_icmp.rs @@ -28,6 +28,7 @@ buffer!(Icmp6StatsBuffer(ICMP6_STATS_LEN) { }); impl> Parseable> for Icmp6Stats { + type Error = DecodeError; fn parse(buf: &Icmp6StatsBuffer) -> Result { Ok(Self { num: buf.num(), diff --git a/src/link/af_spec/inet6_stats.rs b/src/link/af_spec/inet6_stats.rs index 685d9693..8377a73a 100644 --- a/src/link/af_spec/inet6_stats.rs +++ b/src/link/af_spec/inet6_stats.rs @@ -88,6 +88,7 @@ pub struct Inet6Stats { } impl> Parseable> for Inet6Stats { + type Error = DecodeError; fn parse(buf: &Inet6StatsBuffer) -> Result { Ok(Self { num: buf.num(), diff --git a/src/link/af_spec/unspec.rs b/src/link/af_spec/unspec.rs index 439d3626..306874a0 100644 --- a/src/link/af_spec/unspec.rs +++ b/src/link/af_spec/unspec.rs @@ -48,6 +48,7 @@ pub(crate) struct VecAfSpecUnspec(pub(crate) Vec); impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecAfSpecUnspec { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; let err = "Invalid NLA for IFLA_AF_SPEC(AF_UNSPEC)"; diff --git a/src/link/attribute.rs b/src/link/attribute.rs index 1a7665a3..06bc9be0 100644 --- a/src/link/attribute.rs +++ b/src/link/attribute.rs @@ -14,7 +14,7 @@ use netlink_packet_utils::{ #[cfg(any(target_os = "linux", target_os = "fuchsia",))] use super::af_spec::VecAfSpecBridge; #[cfg(any(target_os = "linux", target_os = "fuchsia",))] -use super::proto_info::VecLinkProtoInfoBridge; +use super::proto_info::VecanhowLinkProtoInfoBridge; use super::{ af_spec::VecAfSpecUnspec, buffer_tool::expand_buffer_if_small, @@ -367,6 +367,7 @@ impl Nla for LinkAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized, AddressFamily> for LinkAttribute { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, interface_family: AddressFamily, diff --git a/src/link/down_reason.rs b/src/link/down_reason.rs index a542e8fb..d64f8655 100644 --- a/src/link/down_reason.rs +++ b/src/link/down_reason.rs @@ -22,6 +22,7 @@ pub enum LinkProtocolDownReason { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for LinkProtocolDownReason { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/link/event.rs b/src/link/event.rs index 634ff91e..5c9754f1 100644 --- a/src/link/event.rs +++ b/src/link/event.rs @@ -59,6 +59,7 @@ impl From for u32 { } impl + ?Sized> Parseable for LinkEvent { + type Error = DecodeError; fn parse(buf: &T) -> Result { Ok(LinkEvent::from( parse_u32(buf.as_ref()).context("invalid IFLA_EVENT value")?, diff --git a/src/link/header.rs b/src/link/header.rs index d92a642f..52f4721d 100644 --- a/src/link/header.rs +++ b/src/link/header.rs @@ -86,6 +86,7 @@ impl Emitable for LinkHeader { } impl> Parseable> for LinkHeader { + type Error = DecodeError; fn parse(buf: &LinkMessageBuffer) -> Result { Ok(Self { interface_family: buf.interface_family().into(), diff --git a/src/link/link_info/bond.rs b/src/link/link_info/bond.rs index dd9e1d5e..14b4c188 100644 --- a/src/link/link_info/bond.rs +++ b/src/link/link_info/bond.rs @@ -107,6 +107,7 @@ impl Nla for BondAdInfo { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for BondAdInfo { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { @@ -426,6 +427,7 @@ impl Nla for InfoBond { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoBond { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/link/link_info/bond_port.rs b/src/link/link_info/bond_port.rs index 62206818..4b849401 100644 --- a/src/link/link_info/bond_port.rs +++ b/src/link/link_info/bond_port.rs @@ -158,6 +158,7 @@ impl Nla for InfoBondPort { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoBondPort { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoBondPort::*; let payload = buf.value(); diff --git a/src/link/link_info/bridge.rs b/src/link/link_info/bridge.rs index 13d2a894..ed1a83bc 100644 --- a/src/link/link_info/bridge.rs +++ b/src/link/link_info/bridge.rs @@ -305,6 +305,7 @@ impl Nla for InfoBridge { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoBridge { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { @@ -530,6 +531,7 @@ buffer!(BridgeIdBuffer(BRIDGE_ID_LEN) { }); impl + ?Sized> Parseable> for BridgeId { + type Error = DecodeError; fn parse(buf: &BridgeIdBuffer<&T>) -> Result { // Priority is encoded in big endian. From kernel's // net/bridge/br_netlink.c br_fill_info(): @@ -616,6 +618,7 @@ impl Nla for BridgeQuerierState { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for BridgeQuerierState { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::BridgeQuerierState::*; let payload = buf.value(); diff --git a/src/link/link_info/bridge_port.rs b/src/link/link_info/bridge_port.rs index 35c818cf..76ca4d8a 100644 --- a/src/link/link_info/bridge_port.rs +++ b/src/link/link_info/bridge_port.rs @@ -274,6 +274,7 @@ impl Nla for InfoBridgePort { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoBridgePort { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); diff --git a/src/link/link_info/gre.rs b/src/link/link_info/gre.rs index d1ff4a1a..a1299759 100644 --- a/src/link/link_info/gre.rs +++ b/src/link/link_info/gre.rs @@ -33,6 +33,7 @@ impl Nla for InfoGreTun { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoGreTun { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { #[allow(clippy::match_single_binding)] Ok(match buf.kind() { diff --git a/src/link/link_info/gre6.rs b/src/link/link_info/gre6.rs index ceef4161..e3813b7b 100644 --- a/src/link/link_info/gre6.rs +++ b/src/link/link_info/gre6.rs @@ -33,6 +33,7 @@ impl Nla for InfoGreTun6 { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoGreTun6 { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { #[allow(clippy::match_single_binding)] Ok(match buf.kind() { diff --git a/src/link/link_info/gre_tap.rs b/src/link/link_info/gre_tap.rs index 16293dd2..87198849 100644 --- a/src/link/link_info/gre_tap.rs +++ b/src/link/link_info/gre_tap.rs @@ -33,6 +33,7 @@ impl Nla for InfoGreTap { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoGreTap { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { #[allow(clippy::match_single_binding)] Ok(match buf.kind() { diff --git a/src/link/link_info/gre_tap6.rs b/src/link/link_info/gre_tap6.rs index 491e9f2b..9fe4617f 100644 --- a/src/link/link_info/gre_tap6.rs +++ b/src/link/link_info/gre_tap6.rs @@ -33,6 +33,8 @@ impl Nla for InfoGreTap6 { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoGreTap6 { + type Error = DecodeError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { #[allow(clippy::match_single_binding)] Ok(match buf.kind() { diff --git a/src/link/link_info/gtp.rs b/src/link/link_info/gtp.rs index 4a87d314..804a78b3 100644 --- a/src/link/link_info/gtp.rs +++ b/src/link/link_info/gtp.rs @@ -33,6 +33,7 @@ impl Nla for InfoGtp { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoGtp { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { #[allow(clippy::match_single_binding)] Ok(match buf.kind() { diff --git a/src/link/link_info/hsr.rs b/src/link/link_info/hsr.rs index 52884ac5..ceb903c1 100644 --- a/src/link/link_info/hsr.rs +++ b/src/link/link_info/hsr.rs @@ -74,6 +74,7 @@ impl Nla for InfoHsr { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoHsr { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoHsr::*; let payload = buf.value(); diff --git a/src/link/link_info/info_port.rs b/src/link/link_info/info_port.rs index 67f3f966..d2bc54d5 100644 --- a/src/link/link_info/info_port.rs +++ b/src/link/link_info/info_port.rs @@ -63,6 +63,7 @@ impl Nla for InfoPortKind { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoPortKind { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { if buf.kind() != IFLA_INFO_PORT_KIND { return Err(format!( diff --git a/src/link/link_info/infos.rs b/src/link/link_info/infos.rs index 87c0afd2..8f78398c 100644 --- a/src/link/link_info/infos.rs +++ b/src/link/link_info/infos.rs @@ -103,6 +103,7 @@ pub(crate) struct VecLinkInfo(pub(crate) Vec); // The downside is that this impl will not be exposed. impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecLinkInfo { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = Vec::new(); let mut link_info_kind: Option = None; @@ -290,6 +291,7 @@ impl Nla for InfoKind { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoKind { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { if buf.kind() != IFLA_INFO_KIND { return Err(format!( diff --git a/src/link/link_info/ipoib.rs b/src/link/link_info/ipoib.rs index e68c57b6..0800f002 100644 --- a/src/link/link_info/ipoib.rs +++ b/src/link/link_info/ipoib.rs @@ -53,6 +53,7 @@ impl Nla for InfoIpoib { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoIpoib { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoIpoib::*; let payload = buf.value(); diff --git a/src/link/link_info/ipvlan.rs b/src/link/link_info/ipvlan.rs index a08cc2f2..125ecb32 100644 --- a/src/link/link_info/ipvlan.rs +++ b/src/link/link_info/ipvlan.rs @@ -49,6 +49,7 @@ impl Nla for InfoIpVlan { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoIpVlan { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoIpVlan::*; let payload = buf.value(); @@ -106,6 +107,7 @@ impl Nla for InfoIpVtap { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoIpVtap { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoIpVtap::*; let payload = buf.value(); diff --git a/src/link/link_info/mac_vlan.rs b/src/link/link_info/mac_vlan.rs index 88d454a1..ad6d7a0f 100644 --- a/src/link/link_info/mac_vlan.rs +++ b/src/link/link_info/mac_vlan.rs @@ -90,6 +90,7 @@ impl Nla for InfoMacVlan { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoMacVlan { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoMacVlan::*; let payload = buf.value(); @@ -210,6 +211,7 @@ impl Nla for InfoMacVtap { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoMacVtap { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoMacVtap::*; let payload = buf.value(); diff --git a/src/link/link_info/macsec.rs b/src/link/link_info/macsec.rs index c8d24111..b16b437e 100644 --- a/src/link/link_info/macsec.rs +++ b/src/link/link_info/macsec.rs @@ -213,6 +213,7 @@ impl Nla for InfoMacSec { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoMacSec { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoMacSec::*; let payload = buf.value(); diff --git a/src/link/link_info/sit.rs b/src/link/link_info/sit.rs index f4977f63..18c16ee2 100644 --- a/src/link/link_info/sit.rs +++ b/src/link/link_info/sit.rs @@ -33,6 +33,7 @@ impl Nla for InfoSitTun { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoSitTun { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { #[allow(clippy::match_single_binding)] Ok(match buf.kind() { diff --git a/src/link/link_info/tun.rs b/src/link/link_info/tun.rs index e7326c21..2960c4a2 100644 --- a/src/link/link_info/tun.rs +++ b/src/link/link_info/tun.rs @@ -33,6 +33,7 @@ impl Nla for InfoTun { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoTun { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { #[allow(clippy::match_single_binding)] Ok(match buf.kind() { diff --git a/src/link/link_info/veth.rs b/src/link/link_info/veth.rs index e36f698d..1f2b1622 100644 --- a/src/link/link_info/veth.rs +++ b/src/link/link_info/veth.rs @@ -48,6 +48,7 @@ impl Nla for InfoVeth { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoVeth { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoVeth::*; let payload = buf.value(); diff --git a/src/link/link_info/vlan.rs b/src/link/link_info/vlan.rs index d4c1ab4a..5638e03c 100644 --- a/src/link/link_info/vlan.rs +++ b/src/link/link_info/vlan.rs @@ -109,6 +109,7 @@ impl Nla for VlanQosMapping { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VlanQosMapping { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use VlanQosMapping::*; let payload = buf.value(); @@ -142,6 +143,7 @@ fn parse_mappings(payload: &[u8]) -> Result, DecodeError> { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoVlan { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoVlan::*; let payload = buf.value(); diff --git a/src/link/link_info/vrf.rs b/src/link/link_info/vrf.rs index a8524e12..bb911f52 100644 --- a/src/link/link_info/vrf.rs +++ b/src/link/link_info/vrf.rs @@ -45,6 +45,7 @@ impl Nla for InfoVrf { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoVrf { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoVrf::*; let payload = buf.value(); diff --git a/src/link/link_info/vti.rs b/src/link/link_info/vti.rs index bfe52608..2adadb94 100644 --- a/src/link/link_info/vti.rs +++ b/src/link/link_info/vti.rs @@ -33,6 +33,7 @@ impl Nla for InfoVti { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoVti { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { #[allow(clippy::match_single_binding)] Ok(match buf.kind() { diff --git a/src/link/link_info/vxlan.rs b/src/link/link_info/vxlan.rs index 03861717..6bfe598b 100644 --- a/src/link/link_info/vxlan.rs +++ b/src/link/link_info/vxlan.rs @@ -193,6 +193,7 @@ impl Nla for InfoVxlan { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoVxlan { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/link/link_info/xfrm.rs b/src/link/link_info/xfrm.rs index d76ffc42..2dca8c66 100644 --- a/src/link/link_info/xfrm.rs +++ b/src/link/link_info/xfrm.rs @@ -50,6 +50,7 @@ impl Nla for InfoXfrm { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoXfrm { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { use self::InfoXfrm::*; let payload = buf.value(); diff --git a/src/link/link_info/xstats.rs b/src/link/link_info/xstats.rs index 9e5f5f1a..49b3a80f 100644 --- a/src/link/link_info/xstats.rs +++ b/src/link/link_info/xstats.rs @@ -31,6 +31,7 @@ impl Emitable for LinkXstats { impl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized, &InfoKind> for LinkXstats { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, _kind: &InfoKind, diff --git a/src/link/map.rs b/src/link/map.rs index 425243ae..7b43970d 100644 --- a/src/link/map.rs +++ b/src/link/map.rs @@ -28,6 +28,7 @@ pub struct Map { } impl> Parseable> for Map { + type Error = DecodeError; fn parse(buf: &MapBuffer) -> Result { Ok(Self { memory_start: buf.memory_start(), diff --git a/src/link/message.rs b/src/link/message.rs index b6922a01..4296c9f0 100644 --- a/src/link/message.rs +++ b/src/link/message.rs @@ -32,6 +32,7 @@ impl Emitable for LinkMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for LinkMessage { + type Error = DecodeError; fn parse(buf: &LinkMessageBuffer<&'a T>) -> Result { let header = LinkHeader::parse(buf) .context("failed to parse link message header")?; @@ -47,6 +48,7 @@ impl<'a, T: AsRef<[u8]> + 'a> ParseableParametrized, AddressFamily> for Vec { + type Error = DecodeError; fn parse_with_param( buf: &LinkMessageBuffer<&'a T>, family: AddressFamily, diff --git a/src/link/phys_id.rs b/src/link/phys_id.rs index 19d8fac2..a9f64716 100644 --- a/src/link/phys_id.rs +++ b/src/link/phys_id.rs @@ -15,6 +15,7 @@ pub struct LinkPhysId { } impl Parseable<[u8]> for LinkPhysId { + type Error = DecodeError; fn parse(buf: &[u8]) -> Result { let len = buf.len() % MAX_PHYS_ITEM_ID_LEN; let mut id = [0; MAX_PHYS_ITEM_ID_LEN]; diff --git a/src/link/prop_list.rs b/src/link/prop_list.rs index 7ba4061b..a9bc64db 100644 --- a/src/link/prop_list.rs +++ b/src/link/prop_list.rs @@ -49,6 +49,7 @@ impl Nla for Prop { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for Prop { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/link/proto_info/bridge.rs b/src/link/proto_info/bridge.rs index 8645cc15..02cafcde 100644 --- a/src/link/proto_info/bridge.rs +++ b/src/link/proto_info/bridge.rs @@ -18,6 +18,7 @@ pub(crate) struct VecLinkProtoInfoBridge(pub(crate) Vec); impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecLinkProtoInfoBridge { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; for nla in NlasIterator::new(buf.into_inner()) { @@ -54,6 +55,7 @@ impl Nla for LinkProtoInfoBridge { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for LinkProtoInfoBridge { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { Ok(Self::Other(DefaultNla::parse(buf).context(format!( "invalid bridge IFLA_PROTINFO {:?}", diff --git a/src/link/proto_info/inet6.rs b/src/link/proto_info/inet6.rs index e7cad4d0..bbb5c019 100644 --- a/src/link/proto_info/inet6.rs +++ b/src/link/proto_info/inet6.rs @@ -18,6 +18,7 @@ pub(crate) struct VecLinkProtoInfoInet6(pub(crate) Vec); impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecLinkProtoInfoInet6 { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; for nla in NlasIterator::new(buf.into_inner()) { @@ -54,6 +55,7 @@ impl Nla for LinkProtoInfoInet6 { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for LinkProtoInfoInet6 { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { Ok(Self::Other(DefaultNla::parse(buf).context(format!( "invalid inet6 IFLA_PROTINFO {:?}", diff --git a/src/link/sriov/broadcast.rs b/src/link/sriov/broadcast.rs index e23a1234..9b09245f 100644 --- a/src/link/sriov/broadcast.rs +++ b/src/link/sriov/broadcast.rs @@ -29,6 +29,7 @@ buffer!(VfInfoBroadcastBuffer(VF_INFO_BROADCAST_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfInfoBroadcast { + type Error = DecodeError; fn parse(buf: &VfInfoBroadcastBuffer<&T>) -> Result { Ok(Self::new(buf.addr())) } diff --git a/src/link/sriov/guid.rs b/src/link/sriov/guid.rs index a57af829..07623599 100644 --- a/src/link/sriov/guid.rs +++ b/src/link/sriov/guid.rs @@ -25,6 +25,7 @@ buffer!(VfInfoGuidBuffer(VF_INFO_GUID_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfInfoGuid { + type Error = DecodeError; fn parse(buf: &VfInfoGuidBuffer<&T>) -> Result { Ok(Self::new(buf.vf_id(), buf.guid())) } diff --git a/src/link/sriov/link_state.rs b/src/link/sriov/link_state.rs index baf3144d..0c0839e5 100644 --- a/src/link/sriov/link_state.rs +++ b/src/link/sriov/link_state.rs @@ -25,6 +25,7 @@ buffer!(VfInfoLinkStateBuffer(VF_INFO_LINK_STATE_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfInfoLinkState { + type Error = DecodeError; fn parse(buf: &VfInfoLinkStateBuffer<&T>) -> Result { Ok(Self::new(buf.vf_id(), buf.state().into())) } diff --git a/src/link/sriov/mac.rs b/src/link/sriov/mac.rs index 5be6dbce..285f6059 100644 --- a/src/link/sriov/mac.rs +++ b/src/link/sriov/mac.rs @@ -36,6 +36,7 @@ buffer!(VfInfoMacBuffer(VF_INFO_MAC_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfInfoMac { + type Error = DecodeError; fn parse(buf: &VfInfoMacBuffer<&T>) -> Result { Ok(Self::new(buf.vf_id(), buf.mac())) } diff --git a/src/link/sriov/rate.rs b/src/link/sriov/rate.rs index 111e482a..8db89223 100644 --- a/src/link/sriov/rate.rs +++ b/src/link/sriov/rate.rs @@ -31,6 +31,7 @@ buffer!(VfInfoRateBuffer(VF_INFO_RATE_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfInfoRate { + type Error = DecodeError; fn parse(buf: &VfInfoRateBuffer<&T>) -> Result { Ok(Self { vf_id: buf.vf_id(), diff --git a/src/link/sriov/rss_query.rs b/src/link/sriov/rss_query.rs index d595487c..acfa2ed5 100644 --- a/src/link/sriov/rss_query.rs +++ b/src/link/sriov/rss_query.rs @@ -25,6 +25,7 @@ buffer!(VfInfoRssQueryEnBuffer(VF_INFO_RSS_QUERY_EN_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfInfoRssQueryEn { + type Error = DecodeError; fn parse(buf: &VfInfoRssQueryEnBuffer<&T>) -> Result { Ok(Self::new( buf.vf_id(), diff --git a/src/link/sriov/spoofchk.rs b/src/link/sriov/spoofchk.rs index d45ae38f..c4fe7417 100644 --- a/src/link/sriov/spoofchk.rs +++ b/src/link/sriov/spoofchk.rs @@ -25,6 +25,7 @@ buffer!(VfInfoSpoofCheckBuffer(VF_INFO_SPOOFCHK_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfInfoSpoofCheck { + type Error = DecodeError; fn parse(buf: &VfInfoSpoofCheckBuffer<&T>) -> Result { Ok(Self::new( buf.vf_id(), diff --git a/src/link/sriov/stats.rs b/src/link/sriov/stats.rs index 30a14dac..9608b1a1 100644 --- a/src/link/sriov/stats.rs +++ b/src/link/sriov/stats.rs @@ -70,6 +70,7 @@ impl Nla for VfStats { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfStats { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/link/sriov/trust.rs b/src/link/sriov/trust.rs index 57478d44..299a7890 100644 --- a/src/link/sriov/trust.rs +++ b/src/link/sriov/trust.rs @@ -25,6 +25,7 @@ buffer!(VfInfoTrustBuffer(VF_INFO_TRUST_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfInfoTrust { + type Error = DecodeError; fn parse(buf: &VfInfoTrustBuffer<&T>) -> Result { Ok(Self::new( buf.vf_id(), diff --git a/src/link/sriov/tx_rate.rs b/src/link/sriov/tx_rate.rs index 302f4851..6fb319dd 100644 --- a/src/link/sriov/tx_rate.rs +++ b/src/link/sriov/tx_rate.rs @@ -25,6 +25,7 @@ buffer!(VfInfoTxRateBuffer(VF_INFO_TX_RATE_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfInfoTxRate { + type Error = DecodeError; fn parse(buf: &VfInfoTxRateBuffer<&T>) -> Result { Ok(Self { vf_id: buf.vf_id(), diff --git a/src/link/sriov/vf_list.rs b/src/link/sriov/vf_list.rs index cd5c631e..24a85223 100644 --- a/src/link/sriov/vf_list.rs +++ b/src/link/sriov/vf_list.rs @@ -23,6 +23,7 @@ pub(crate) struct VecLinkVfInfo(pub(crate) Vec); impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecLinkVfInfo { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; for nla in NlasIterator::new(buf.into_inner()) { @@ -62,6 +63,7 @@ impl Nla for LinkVfInfo { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for LinkVfInfo { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; for nla in NlasIterator::new(buf.into_inner()) { @@ -168,6 +170,7 @@ impl Nla for VfInfo { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfInfo { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/link/sriov/vf_port.rs b/src/link/sriov/vf_port.rs index ac759e2f..5b63d50b 100644 --- a/src/link/sriov/vf_port.rs +++ b/src/link/sriov/vf_port.rs @@ -12,6 +12,7 @@ pub(crate) struct VecLinkVfPort(pub(crate) Vec); impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecLinkVfPort { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; for nla in NlasIterator::new(buf.into_inner()) { @@ -53,6 +54,7 @@ impl Nla for LinkVfPort { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for LinkVfPort { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; for nla in NlasIterator::new(buf.into_inner()) { @@ -111,6 +113,7 @@ impl Nla for VfPort { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfPort { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); #[allow(clippy::match_single_binding)] diff --git a/src/link/sriov/vf_vlan.rs b/src/link/sriov/vf_vlan.rs index 62b3954b..54f84211 100644 --- a/src/link/sriov/vf_vlan.rs +++ b/src/link/sriov/vf_vlan.rs @@ -41,6 +41,7 @@ impl Nla for VfVlan { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfVlan { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { @@ -93,6 +94,7 @@ buffer!(VfVlanInfoBuffer(VF_VLAN_INFO_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfVlanInfo { + type Error = DecodeError; fn parse(buf: &VfVlanInfoBuffer<&T>) -> Result { Ok(Self { vf_id: buf.vf_id(), diff --git a/src/link/sriov/vlan.rs b/src/link/sriov/vlan.rs index e2f87d5a..284033e7 100644 --- a/src/link/sriov/vlan.rs +++ b/src/link/sriov/vlan.rs @@ -31,6 +31,7 @@ buffer!(VfInfoVlanBuffer(VF_INFO_VLAN_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VfInfoVlan { + type Error = DecodeError; fn parse(buf: &VfInfoVlanBuffer<&T>) -> Result { Ok(Self { vf_id: buf.vf_id(), diff --git a/src/link/stats.rs b/src/link/stats.rs index 7ab476d2..687f6d29 100644 --- a/src/link/stats.rs +++ b/src/link/stats.rs @@ -86,6 +86,7 @@ buffer!(StatsBuffer(LINK_STATS_LEN) { }); impl> Parseable> for Stats { + type Error = DecodeError; fn parse(buf: &StatsBuffer) -> Result { Ok(Self { rx_packets: buf.rx_packets(), diff --git a/src/link/stats64.rs b/src/link/stats64.rs index 5bece142..b9aae4c4 100644 --- a/src/link/stats64.rs +++ b/src/link/stats64.rs @@ -89,6 +89,7 @@ pub struct Stats64 { } impl> Parseable> for Stats64 { + type Error = DecodeError; fn parse(buf: &Stats64Buffer) -> Result { Ok(Self { rx_packets: buf.rx_packets(), diff --git a/src/link/wireless.rs b/src/link/wireless.rs index 65fa628c..8045f01c 100644 --- a/src/link/wireless.rs +++ b/src/link/wireless.rs @@ -8,6 +8,7 @@ use netlink_packet_utils::{DecodeError, Emitable, Parseable}; pub struct LinkWirelessEvent(Vec); impl + ?Sized> Parseable for LinkWirelessEvent { + type Error = DecodeError; fn parse(buf: &T) -> Result { Ok(LinkWirelessEvent(buf.as_ref().to_vec())) } diff --git a/src/link/xdp.rs b/src/link/xdp.rs index 99182a2d..ea717445 100644 --- a/src/link/xdp.rs +++ b/src/link/xdp.rs @@ -92,6 +92,7 @@ impl Nla for LinkXdp { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for LinkXdp { + type Error = DecodeError; fn parse(nla: &NlaBuffer<&'a T>) -> Result { let payload = nla.value(); Ok(match nla.kind() as u32 { @@ -138,6 +139,7 @@ pub(crate) struct VecLinkXdp(pub(crate) Vec); // nla->data[0].type <- nla.kind() // nla->data[0].len impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecLinkXdp { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut res = Vec::new(); let nlas = NlasIterator::new(buf.into_inner()); diff --git a/src/message.rs b/src/message.rs index 3529f07a..a3bf10cf 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,14 +1,5 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; -use netlink_packet_utils::{ - DecodeError, Emitable, Parseable, ParseableParametrized, -}; - -use netlink_packet_core::{ - NetlinkDeserializable, NetlinkHeader, NetlinkPayload, NetlinkSerializable, -}; - use crate::{ address::{AddressHeader, AddressMessage, AddressMessageBuffer}, link::{LinkMessage, LinkMessageBuffer}, @@ -20,6 +11,13 @@ use crate::{ rule::{RuleMessage, RuleMessageBuffer}, tc::{TcMessage, TcMessageBuffer}, }; +use netlink_packet_core::{ + NetlinkDeserializable, NetlinkHeader, NetlinkPayload, NetlinkSerializable, +}; +use netlink_packet_utils::{ + DecodeError, Emitable, Parseable, ParseableParametrized, +}; +use thiserror::Error; const RTM_NEWLINK: u16 = 16; const RTM_DELLINK: u16 = 17; @@ -81,20 +79,56 @@ const RTM_DELLINKPROP: u16 = 109; buffer!(RouteNetlinkMessageBuffer); +#[derive(Debug, Error)] +pub enum RouteNetlinkMessageParseError { + #[error("Invalid link message")] + InvalidLinkMessage(#[source] DecodeError), + + #[error("Invalid route message")] + InvalidRouteMessage(#[source] DecodeError), + + #[error("Invalid addr message")] + InvalidAddrMessage(#[source] DecodeError), + + #[error("Invalid prefix message")] + InvalidPrefixMessage(#[source] DecodeError), + + #[error("Invalid fib rule message")] + InvalidFibRuleMessage(#[source] DecodeError), + + #[error("Invalid tc message")] + InvalidTcMessage(#[source] DecodeError), + + #[error("invalid nsid message")] + InvalidNsidMessage(#[source] DecodeError), + + #[error("Invalid neighbour message")] + InvalidNeighbourMessage(#[source] DecodeError), + + #[error("Invalid neighbour table message")] + InvalidNeighbourTableMessage(#[source] DecodeError), + + #[error("Unknown message type: {0}")] + UnknownMessageType(u16), +} + impl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized, u16> for RouteNetlinkMessage { + type Error = RouteNetlinkMessageParseError; + fn parse_with_param( buf: &RouteNetlinkMessageBuffer<&'a T>, message_type: u16, - ) -> Result { + ) -> Result { let message = match message_type { // Link messages RTM_NEWLINK | RTM_GETLINK | RTM_DELLINK | RTM_SETLINK => { let msg = match LinkMessageBuffer::new_checked(&buf.inner()) { - Ok(buf) => LinkMessage::parse(&buf) - .context("invalid link message")?, + Ok(buf) => LinkMessage::parse(&buf).map_err( + RouteNetlinkMessageParseError::InvalidLinkMessage, + )?, // HACK: iproute2 sends invalid RTM_GETLINK message, where // the header is limited to the // interface family (1 byte) and 3 bytes of padding. @@ -105,7 +139,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> msg.header.interface_family = buf.inner()[0].into(); msg } else { - return Err(e); + return Err(RouteNetlinkMessageParseError::InvalidLinkMessage(e)); } } }; @@ -122,8 +156,9 @@ impl<'a, T: AsRef<[u8]> + ?Sized> RTM_NEWADDR | RTM_GETADDR | RTM_DELADDR => { let msg = match AddressMessageBuffer::new_checked(&buf.inner()) { - Ok(buf) => AddressMessage::parse(&buf) - .context("invalid link message")?, + Ok(buf) => AddressMessage::parse(&buf).map_err( + RouteNetlinkMessageParseError::InvalidAddrMessage, + )?, // HACK: iproute2 sends invalid RTM_GETADDR message, where // the header is limited to the // interface family (1 byte) and 3 bytes of padding. @@ -137,7 +172,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> msg.header.family = buf.inner()[0].into(); msg } else { - return Err(e); + return Err(RouteNetlinkMessageParseError::InvalidAddrMessage(e)); } } }; @@ -151,12 +186,11 @@ impl<'a, T: AsRef<[u8]> + ?Sized> // Neighbour messages RTM_NEWNEIGH | RTM_GETNEIGH | RTM_DELNEIGH => { - let err = "invalid neighbour message"; - let msg = NeighbourMessage::parse( - &NeighbourMessageBuffer::new_checked(&buf.inner()) - .context(err)?, - ) - .context(err)?; + let msg = NeighbourMessageBuffer::new_checked(&buf.inner()) + .and_then(|buffer| NeighbourMessage::parse(&buffer)) + .map_err( + RouteNetlinkMessageParseError::InvalidNeighbourMessage, + )?; match message_type { RTM_GETNEIGH => RouteNetlinkMessage::GetNeighbour(msg), RTM_NEWNEIGH => RouteNetlinkMessage::NewNeighbour(msg), @@ -167,12 +201,13 @@ impl<'a, T: AsRef<[u8]> + ?Sized> // Neighbour table messages RTM_NEWNEIGHTBL | RTM_GETNEIGHTBL | RTM_SETNEIGHTBL => { - let err = "invalid neighbour table message"; - let msg = NeighbourTableMessage::parse( - &NeighbourTableMessageBuffer::new_checked(&buf.inner()) - .context(err)?, + let msg = NeighbourTableMessageBuffer::new_checked( + &buf.inner(), ) - .context(err)?; + .and_then(|buffer| NeighbourTableMessage::parse(&buffer)) + .map_err( + RouteNetlinkMessageParseError::InvalidNeighbourTableMessage, + )?; match message_type { RTM_GETNEIGHTBL => { RouteNetlinkMessage::GetNeighbourTable(msg) @@ -190,8 +225,9 @@ impl<'a, T: AsRef<[u8]> + ?Sized> // Route messages RTM_NEWROUTE | RTM_GETROUTE | RTM_DELROUTE => { let msg = match RouteMessageBuffer::new_checked(&buf.inner()) { - Ok(buf) => RouteMessage::parse(&buf) - .context("invalid route message")?, + Ok(buf) => RouteMessage::parse(&buf).map_err( + RouteNetlinkMessageParseError::InvalidRouteMessage, + )?, // HACK: iproute2 sends invalid RTM_GETROUTE message, where // the header is limited to the // interface family (1 byte) and 3 bytes of padding. @@ -214,7 +250,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> msg.header.address_family = buf.inner()[0].into(); msg } else { - return Err(e); + return Err(RouteNetlinkMessageParseError::InvalidRouteMessage(e)); } } }; @@ -227,24 +263,20 @@ impl<'a, T: AsRef<[u8]> + ?Sized> } // Prefix messages - RTM_NEWPREFIX => { - let err = "invalid prefix message"; - RouteNetlinkMessage::NewPrefix( - PrefixMessage::parse( - &PrefixMessageBuffer::new_checked(&buf.inner()) - .context(err)?, - ) - .context(err)?, - ) - } + RTM_NEWPREFIX => RouteNetlinkMessage::NewPrefix( + PrefixMessageBuffer::new_checked(&buf.inner()) + .and_then(|buffer| PrefixMessage::parse(&buffer)) + .map_err( + RouteNetlinkMessageParseError::InvalidPrefixMessage, + )?, + ), RTM_NEWRULE | RTM_GETRULE | RTM_DELRULE => { - let err = "invalid fib rule message"; - let msg = RuleMessage::parse( - &RuleMessageBuffer::new_checked(&buf.inner()) - .context(err)?, - ) - .context(err)?; + let msg = RuleMessageBuffer::new_checked(&buf.inner()) + .and_then(|buffer| RuleMessage::parse(&buffer)) + .map_err( + RouteNetlinkMessageParseError::InvalidFibRuleMessage, + )?; match message_type { RTM_NEWRULE => RouteNetlinkMessage::NewRule(msg), RTM_DELRULE => RouteNetlinkMessage::DelRule(msg), @@ -257,11 +289,9 @@ impl<'a, T: AsRef<[u8]> + ?Sized> | RTM_DELTCLASS | RTM_GETTCLASS | RTM_NEWTFILTER | RTM_DELTFILTER | RTM_GETTFILTER | RTM_NEWCHAIN | RTM_DELCHAIN | RTM_GETCHAIN => { - let err = "invalid tc message"; - let msg = TcMessage::parse( - &TcMessageBuffer::new_checked(&buf.inner()).context(err)?, - ) - .context(err)?; + let msg = TcMessageBuffer::new_checked(&buf.inner()) + .and_then(|buffer| TcMessage::parse(&buffer)) + .map_err(RouteNetlinkMessageParseError::InvalidTcMessage)?; match message_type { RTM_NEWQDISC => { RouteNetlinkMessage::NewQueueDiscipline(msg) @@ -293,12 +323,11 @@ impl<'a, T: AsRef<[u8]> + ?Sized> // ND ID Messages RTM_NEWNSID | RTM_GETNSID | RTM_DELNSID => { - let err = "invalid nsid message"; - let msg = NsidMessage::parse( - &NsidMessageBuffer::new_checked(&buf.inner()) - .context(err)?, - ) - .context(err)?; + let msg = NsidMessageBuffer::new_checked(&buf.inner()) + .and_then(|buffer| NsidMessage::parse(&buffer)) + .map_err( + RouteNetlinkMessageParseError::InvalidNsidMessage, + )?; match message_type { RTM_NEWNSID => RouteNetlinkMessage::NewNsId(msg), RTM_DELNSID => RouteNetlinkMessage::DelNsId(msg), @@ -308,9 +337,9 @@ impl<'a, T: AsRef<[u8]> + ?Sized> } _ => { - return Err( - format!("Unknown message type: {message_type}").into() - ) + return Err(RouteNetlinkMessageParseError::UnknownMessageType( + message_type, + )) } }; Ok(message) @@ -678,7 +707,8 @@ impl NetlinkSerializable for RouteNetlinkMessage { } impl NetlinkDeserializable for RouteNetlinkMessage { - type Error = DecodeError; + type Error = RouteNetlinkMessageParseError; + fn deserialize( header: &NetlinkHeader, payload: &[u8], diff --git a/src/neighbour/attribute.rs b/src/neighbour/attribute.rs index ec871eda..5f5c718f 100644 --- a/src/neighbour/attribute.rs +++ b/src/neighbour/attribute.rs @@ -106,6 +106,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized, AddressFamily> for NeighbourAttribute { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, address_family: AddressFamily, diff --git a/src/neighbour/cache_info.rs b/src/neighbour/cache_info.rs index 86c61865..75066c41 100644 --- a/src/neighbour/cache_info.rs +++ b/src/neighbour/cache_info.rs @@ -26,6 +26,7 @@ buffer!(NeighbourCacheInfoBuffer(NEIGHBOUR_CACHE_INFO_LEN) { impl> Parseable> for NeighbourCacheInfo { + type Error = DecodeError; fn parse(buf: &NeighbourCacheInfoBuffer) -> Result { Ok(Self { confirmed: buf.confirmed(), diff --git a/src/neighbour/header.rs b/src/neighbour/header.rs index f12fab69..967c57e4 100644 --- a/src/neighbour/header.rs +++ b/src/neighbour/header.rs @@ -58,6 +58,7 @@ pub struct NeighbourHeader { } impl> Parseable> for NeighbourHeader { + type Error = DecodeError; fn parse(buf: &NeighbourMessageBuffer) -> Result { Ok(Self { family: buf.family().into(), diff --git a/src/neighbour/message.rs b/src/neighbour/message.rs index f5908584..9381c2ad 100644 --- a/src/neighbour/message.rs +++ b/src/neighbour/message.rs @@ -34,6 +34,7 @@ impl Emitable for NeighbourMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for NeighbourMessage { + type Error = DecodeError; fn parse(buf: &NeighbourMessageBuffer<&'a T>) -> Result { let header = NeighbourHeader::parse(buf) .context("failed to parse neighbour message header")?; @@ -53,6 +54,7 @@ impl<'a, T: AsRef<[u8]> + 'a> ParseableParametrized, AddressFamily> for Vec { + type Error = DecodeError; fn parse_with_param( buf: &NeighbourMessageBuffer<&'a T>, address_family: AddressFamily, diff --git a/src/neighbour_table/attribute.rs b/src/neighbour_table/attribute.rs index 45326e26..11affd6d 100644 --- a/src/neighbour_table/attribute.rs +++ b/src/neighbour_table/attribute.rs @@ -90,6 +90,7 @@ impl Nla for NeighbourTableAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for NeighbourTableAttribute { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/neighbour_table/config.rs b/src/neighbour_table/config.rs index 6e625333..6e137e63 100644 --- a/src/neighbour_table/config.rs +++ b/src/neighbour_table/config.rs @@ -36,6 +36,7 @@ buffer!(NeighbourTableConfigBuffer(CONFIG_LEN) { impl> Parseable> for NeighbourTableConfig { + type Error = DecodeError; fn parse(buf: &NeighbourTableConfigBuffer) -> Result { Ok(Self { key_len: buf.key_len(), diff --git a/src/neighbour_table/header.rs b/src/neighbour_table/header.rs index 1f41d838..1ed81ceb 100644 --- a/src/neighbour_table/header.rs +++ b/src/neighbour_table/header.rs @@ -32,6 +32,7 @@ pub struct NeighbourTableHeader { impl> Parseable> for NeighbourTableHeader { + type Error = DecodeError; fn parse( buf: &NeighbourTableMessageBuffer, ) -> Result { diff --git a/src/neighbour_table/message.rs b/src/neighbour_table/message.rs index 9dbdb11d..87f0b1c2 100644 --- a/src/neighbour_table/message.rs +++ b/src/neighbour_table/message.rs @@ -33,6 +33,7 @@ impl Emitable for NeighbourTableMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for NeighbourTableMessage { + type Error = DecodeError; fn parse( buf: &NeighbourTableMessageBuffer<&'a T>, ) -> Result { @@ -48,6 +49,7 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { + type Error = DecodeError; fn parse( buf: &NeighbourTableMessageBuffer<&'a T>, ) -> Result { diff --git a/src/neighbour_table/param.rs b/src/neighbour_table/param.rs index 91cd791c..32d0ed8b 100644 --- a/src/neighbour_table/param.rs +++ b/src/neighbour_table/param.rs @@ -135,6 +135,7 @@ impl Nla for NeighbourTableParameter { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for NeighbourTableParameter { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { @@ -233,6 +234,7 @@ pub(crate) struct VecNeighbourTableParameter( impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecNeighbourTableParameter { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; let err = "invalid NDTA_PARMS attribute"; diff --git a/src/neighbour_table/stats.rs b/src/neighbour_table/stats.rs index a99bf6ff..ab08d96b 100644 --- a/src/neighbour_table/stats.rs +++ b/src/neighbour_table/stats.rs @@ -39,6 +39,7 @@ buffer!(NeighbourTableStatsBuffer(STATS_LEN) { impl> Parseable> for NeighbourTableStats { + type Error = DecodeError; fn parse(buf: &NeighbourTableStatsBuffer) -> Result { Ok(Self { allocs: buf.allocs(), diff --git a/src/nsid/attribute.rs b/src/nsid/attribute.rs index 487e6f3e..0546d213 100644 --- a/src/nsid/attribute.rs +++ b/src/nsid/attribute.rs @@ -65,6 +65,7 @@ impl Nla for NsidAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for NsidAttribute { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/nsid/header.rs b/src/nsid/header.rs index 7b43b736..ff2c9f98 100644 --- a/src/nsid/header.rs +++ b/src/nsid/header.rs @@ -39,6 +39,7 @@ impl Emitable for NsidHeader { } impl> Parseable> for NsidHeader { + type Error = DecodeError; fn parse(buf: &NsidMessageBuffer) -> Result { Ok(NsidHeader { family: buf.family().into(), diff --git a/src/nsid/message.rs b/src/nsid/message.rs index e6269f76..e05f8d6f 100644 --- a/src/nsid/message.rs +++ b/src/nsid/message.rs @@ -18,6 +18,7 @@ pub struct NsidMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for NsidMessage { + type Error = DecodeError; fn parse(buf: &NsidMessageBuffer<&'a T>) -> Result { Ok(Self { header: NsidHeader::parse(buf) @@ -31,6 +32,7 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { + type Error = DecodeError; fn parse(buf: &NsidMessageBuffer<&'a T>) -> Result { let mut attributes = vec![]; for nla_buf in buf.attributes() { diff --git a/src/prefix/attribute.rs b/src/prefix/attribute.rs index 1c129ca4..3cd1515a 100644 --- a/src/prefix/attribute.rs +++ b/src/prefix/attribute.rs @@ -50,6 +50,7 @@ impl nla::Nla for PrefixAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for PrefixAttribute { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); match buf.kind() { diff --git a/src/prefix/cache_info.rs b/src/prefix/cache_info.rs index b2dc2bb9..4e090909 100644 --- a/src/prefix/cache_info.rs +++ b/src/prefix/cache_info.rs @@ -17,6 +17,7 @@ buffer!(CacheInfoBuffer(CACHE_INFO_LEN) { }); impl> Parseable> for CacheInfo { + type Error = DecodeError; fn parse(buf: &CacheInfoBuffer) -> Result { Ok(CacheInfo { preferred_time: buf.preferred_time(), diff --git a/src/prefix/message.rs b/src/prefix/message.rs index fc4e9bcf..d27ce1f4 100644 --- a/src/prefix/message.rs +++ b/src/prefix/message.rs @@ -32,6 +32,7 @@ impl Emitable for PrefixMessage { } impl> Parseable> for PrefixHeader { + type Error = DecodeError; fn parse(buf: &PrefixMessageBuffer) -> Result { Ok(Self { prefix_family: buf.prefix_family(), @@ -46,6 +47,7 @@ impl> Parseable> for PrefixHeader { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for PrefixMessage { + type Error = DecodeError; fn parse(buf: &PrefixMessageBuffer<&'a T>) -> Result { Ok(Self { header: PrefixHeader::parse(buf) @@ -59,6 +61,7 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { + type Error = DecodeError; fn parse(buf: &PrefixMessageBuffer<&'a T>) -> Result { let mut nlas = vec![]; for nla_buf in buf.nlas() { diff --git a/src/route/attribute.rs b/src/route/attribute.rs index 344fc745..17b40b94 100644 --- a/src/route/attribute.rs +++ b/src/route/attribute.rs @@ -194,6 +194,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> (AddressFamily, RouteType, RouteLwEnCapType), > for RouteAttribute { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, (address_family, route_type, encap_type): ( diff --git a/src/route/cache_info.rs b/src/route/cache_info.rs index 42484c24..e725779b 100644 --- a/src/route/cache_info.rs +++ b/src/route/cache_info.rs @@ -32,6 +32,7 @@ buffer!(RouteCacheInfoBuffer(CACHE_INFO_LEN) { }); impl> Parseable> for RouteCacheInfo { + type Error = DecodeError; fn parse(buf: &RouteCacheInfoBuffer) -> Result { Ok(Self { clntref: buf.clntref(), diff --git a/src/route/header.rs b/src/route/header.rs index c33af0f6..e9ee4c94 100644 --- a/src/route/header.rs +++ b/src/route/header.rs @@ -64,6 +64,7 @@ impl RouteHeader { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RouteHeader { + type Error = DecodeError; fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result { Ok(RouteHeader { address_family: buf.address_family().into(), @@ -246,6 +247,7 @@ impl Default for RouteProtocol { } impl Parseable<[u8]> for RouteProtocol { + type Error = DecodeError; fn parse(buf: &[u8]) -> Result { if buf.len() == 1 { Ok(Self::from(buf[0])) diff --git a/src/route/lwtunnel.rs b/src/route/lwtunnel.rs index 8e1619f1..282ee0c0 100644 --- a/src/route/lwtunnel.rs +++ b/src/route/lwtunnel.rs @@ -141,6 +141,7 @@ impl<'a, T> ParseableParametrized, RouteLwEnCapType> where T: AsRef<[u8]> + ?Sized, { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: RouteLwEnCapType, @@ -163,6 +164,7 @@ impl<'a, T> ParseableParametrized, RouteLwEnCapType> where T: AsRef<[u8]> + ?Sized, { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: RouteLwEnCapType, diff --git a/src/route/message.rs b/src/route/message.rs index 072776cc..e662c6ef 100644 --- a/src/route/message.rs +++ b/src/route/message.rs @@ -34,6 +34,7 @@ impl Emitable for RouteMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for RouteMessage { + type Error = DecodeError; fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result { let header = RouteHeader::parse(buf) .context("failed to parse route message header")?; @@ -54,6 +55,7 @@ impl<'a, T: AsRef<[u8]> + 'a> ParseableParametrized, (AddressFamily, RouteType)> for Vec { + type Error = DecodeError; fn parse_with_param( buf: &RouteMessageBuffer<&'a T>, (address_family, route_type): (AddressFamily, RouteType), diff --git a/src/route/metrics.rs b/src/route/metrics.rs index 6bb24ea5..5a9f5266 100644 --- a/src/route/metrics.rs +++ b/src/route/metrics.rs @@ -127,6 +127,7 @@ impl Nla for RouteMetric { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RouteMetric { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { @@ -193,6 +194,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RouteMetric { pub(crate) struct VecRouteMetric(pub(crate) Vec); impl + ?Sized> Parseable for VecRouteMetric { + type Error = DecodeError; fn parse(payload: &T) -> Result { let mut nlas = vec![]; for nla in NlasIterator::new(payload) { diff --git a/src/route/mfc_stats.rs b/src/route/mfc_stats.rs index a9f14455..b9391298 100644 --- a/src/route/mfc_stats.rs +++ b/src/route/mfc_stats.rs @@ -22,6 +22,7 @@ buffer!(RouteMfcStatsBuffer(MFC_STATS_LEN) { }); impl> Parseable> for RouteMfcStats { + type Error = DecodeError; fn parse( buf: &RouteMfcStatsBuffer, ) -> Result { diff --git a/src/route/mpls.rs b/src/route/mpls.rs index 5c4b4ece..0fc1a476 100644 --- a/src/route/mpls.rs +++ b/src/route/mpls.rs @@ -50,6 +50,7 @@ impl Nla for RouteMplsIpTunnel { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RouteMplsIpTunnel { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/route/next_hops.rs b/src/route/next_hops.rs index 724c1c01..65499f49 100644 --- a/src/route/next_hops.rs +++ b/src/route/next_hops.rs @@ -100,6 +100,7 @@ impl<'a, T: AsRef<[u8]>> (AddressFamily, RouteType, RouteLwEnCapType), > for RouteNextHop { + type Error = DecodeError; fn parse_with_param( buf: &RouteNextHopBuffer<&T>, (address_family, route_type, encap_type): ( @@ -129,6 +130,7 @@ impl<'a, T: AsRef<[u8]> + 'a> (AddressFamily, RouteType, RouteLwEnCapType), > for Vec { + type Error = DecodeError; fn parse_with_param( buf: &RouteNextHopBuffer<&'a T>, (address_family, route_type, encap_type): ( diff --git a/src/route/via.rs b/src/route/via.rs index e7da6924..53320e77 100644 --- a/src/route/via.rs +++ b/src/route/via.rs @@ -36,6 +36,7 @@ buffer!(RouteViaBuffer(RTVIA_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RouteVia { + type Error = DecodeError; fn parse(buf: &RouteViaBuffer<&'a T>) -> Result { let address_family: AddressFamily = (buf.address_family() as u8).into(); Ok(match address_family { diff --git a/src/rule/attribute.rs b/src/rule/attribute.rs index e56e554d..1cc60983 100644 --- a/src/rule/attribute.rs +++ b/src/rule/attribute.rs @@ -152,6 +152,7 @@ impl Nla for RuleAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RuleAttribute { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); diff --git a/src/rule/header.rs b/src/rule/header.rs index 8451ec47..fc710cbe 100644 --- a/src/rule/header.rs +++ b/src/rule/header.rs @@ -63,6 +63,7 @@ impl Emitable for RuleHeader { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RuleHeader { + type Error = DecodeError; fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result { Ok(RuleHeader { family: buf.family().into(), diff --git a/src/rule/message.rs b/src/rule/message.rs index fa96cf01..85934425 100644 --- a/src/rule/message.rs +++ b/src/rule/message.rs @@ -31,6 +31,7 @@ impl Emitable for RuleMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for RuleMessage { + type Error = DecodeError; fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result { let header = RuleHeader::parse(buf) .context("failed to parse link message header")?; @@ -43,6 +44,7 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { + type Error = DecodeError; fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result { let mut attributes = vec![]; for nla_buf in buf.attributes() { diff --git a/src/tc/actions/action.rs b/src/tc/actions/action.rs index 153a0e62..df6f4c99 100644 --- a/src/tc/actions/action.rs +++ b/src/tc/actions/action.rs @@ -48,6 +48,7 @@ impl Nla for TcAction { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcAction { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut attributes = vec![]; let mut kind = String::new(); @@ -214,6 +215,7 @@ where T: AsRef<[u8]> + ?Sized, S: AsRef, { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: S, @@ -274,6 +276,7 @@ impl Emitable for TcActionGeneric { } impl> Parseable> for TcActionGeneric { + type Error = DecodeError; fn parse(buf: &TcActionGenericBuffer) -> Result { Ok(Self { index: buf.index(), diff --git a/src/tc/actions/mirror.rs b/src/tc/actions/mirror.rs index c818da94..e72ca484 100644 --- a/src/tc/actions/mirror.rs +++ b/src/tc/actions/mirror.rs @@ -60,6 +60,7 @@ impl Nla for TcActionMirrorOption { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcActionMirrorOption { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { @@ -105,6 +106,7 @@ impl Emitable for TcMirror { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcMirror { + type Error = DecodeError; fn parse(buf: &TcMirrorBuffer<&T>) -> Result { Ok(Self { generic: TcActionGeneric::parse(&TcActionGenericBuffer::new( diff --git a/src/tc/actions/nat.rs b/src/tc/actions/nat.rs index a1d6a350..2218bed5 100644 --- a/src/tc/actions/nat.rs +++ b/src/tc/actions/nat.rs @@ -60,6 +60,7 @@ impl Nla for TcActionNatOption { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcActionNatOption { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { @@ -124,6 +125,7 @@ impl Emitable for TcNat { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcNat { + type Error = DecodeError; fn parse(buf: &TcNatBuffer<&T>) -> Result { Ok(Self { generic: TcActionGeneric::parse(&TcActionGenericBuffer::new( diff --git a/src/tc/attribute.rs b/src/tc/attribute.rs index 992ec880..9d8051b3 100644 --- a/src/tc/attribute.rs +++ b/src/tc/attribute.rs @@ -109,6 +109,7 @@ impl Nla for TcAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized, &str> for TcAttribute { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: &str, diff --git a/src/tc/filters/cls_u32.rs b/src/tc/filters/cls_u32.rs index 06327f5b..3b08de3a 100644 --- a/src/tc/filters/cls_u32.rs +++ b/src/tc/filters/cls_u32.rs @@ -115,6 +115,7 @@ impl Nla for TcFilterU32Option { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcFilterU32Option { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { @@ -219,6 +220,7 @@ impl Emitable for TcU32Selector { impl + ?Sized> Parseable> for TcU32Selector { + type Error = DecodeError; fn parse(buf: &TcU32SelectorBuffer<&T>) -> Result { let nkeys = buf.nkeys(); let mut keys = Vec::::with_capacity(nkeys.into()); @@ -279,6 +281,7 @@ impl Emitable for TcU32Key { } impl> Parseable> for TcU32Key { + type Error = DecodeError; fn parse(buf: &TcU32KeyBuffer) -> Result { Ok(Self { mask: buf.mask(), diff --git a/src/tc/filters/matchall.rs b/src/tc/filters/matchall.rs index 280f8a24..fef22e00 100644 --- a/src/tc/filters/matchall.rs +++ b/src/tc/filters/matchall.rs @@ -71,6 +71,7 @@ impl Nla for TcFilterMatchAllOption { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcFilterMatchAllOption { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/tc/header.rs b/src/tc/header.rs index 1b4dc824..019c964b 100644 --- a/src/tc/header.rs +++ b/src/tc/header.rs @@ -61,6 +61,7 @@ impl Emitable for TcHeader { } impl> Parseable> for TcHeader { + type Error = DecodeError; fn parse(buf: &TcMessageBuffer) -> Result { Ok(Self { family: buf.family().into(), diff --git a/src/tc/message.rs b/src/tc/message.rs index 00a6d7bf..a6e75196 100644 --- a/src/tc/message.rs +++ b/src/tc/message.rs @@ -37,6 +37,7 @@ impl TcMessage { } impl<'a, T: AsRef<[u8]> + 'a> Parseable> for TcMessage { + type Error = DecodeError; fn parse(buf: &TcMessageBuffer<&'a T>) -> Result { Ok(Self { header: TcHeader::parse(buf) @@ -50,6 +51,7 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> for TcMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { + type Error = DecodeError; fn parse(buf: &TcMessageBuffer<&'a T>) -> Result { let mut attributes = vec![]; let mut kind = String::new(); diff --git a/src/tc/options.rs b/src/tc/options.rs index 1b180f4c..80a69719 100644 --- a/src/tc/options.rs +++ b/src/tc/options.rs @@ -62,6 +62,7 @@ impl<'a, T> ParseableParametrized, &str> for TcOption where T: AsRef<[u8]> + ?Sized, { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: &str, @@ -97,6 +98,7 @@ impl<'a, T> ParseableParametrized, &str> for VecTcOption where T: AsRef<[u8]> + ?Sized, { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: &str, diff --git a/src/tc/qdiscs/fq_codel.rs b/src/tc/qdiscs/fq_codel.rs index a19484b4..fe330545 100644 --- a/src/tc/qdiscs/fq_codel.rs +++ b/src/tc/qdiscs/fq_codel.rs @@ -32,6 +32,7 @@ pub enum TcFqCodelXstats { } impl + ?Sized> Parseable for TcFqCodelXstats { + type Error = DecodeError; fn parse(buf: &T) -> Result { if buf.as_ref().len() < 4 { return Err(DecodeError::from(format!( @@ -117,6 +118,7 @@ buffer!(TcFqCodelQdStatsBuffer(TC_FQ_CODEL_QD_STATS_LEN) { }); impl> Parseable> for TcFqCodelQdStats { + type Error = DecodeError; fn parse(buf: &TcFqCodelQdStatsBuffer) -> Result { Ok(Self { maxpacket: buf.maxpacket(), @@ -172,6 +174,7 @@ buffer!(TcFqCodelClStatsBuffer(TC_FQ_CODEL_CL_STATS_LEN) { }); impl> Parseable> for TcFqCodelClStats { + type Error = DecodeError; fn parse(buf: &TcFqCodelClStatsBuffer) -> Result { Ok(Self { deficit: buf.deficit(), @@ -285,6 +288,7 @@ impl Nla for TcQdiscFqCodelOption { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcQdiscFqCodelOption { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { diff --git a/src/tc/qdiscs/ingress.rs b/src/tc/qdiscs/ingress.rs index c87a29e0..4479ca53 100644 --- a/src/tc/qdiscs/ingress.rs +++ b/src/tc/qdiscs/ingress.rs @@ -46,6 +46,7 @@ impl Nla for TcQdiscIngressOption { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcQdiscIngressOption { + type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { Ok(Self::Other( DefaultNla::parse(buf).context("failed to parse ingress nla")?, diff --git a/src/tc/stats/basic.rs b/src/tc/stats/basic.rs index 786fee9c..acfb717e 100644 --- a/src/tc/stats/basic.rs +++ b/src/tc/stats/basic.rs @@ -24,6 +24,7 @@ buffer!(TcStatsBasicBuffer(STATS_BASIC_LEN) { }); impl> Parseable> for TcStatsBasic { + type Error = DecodeError; fn parse(buf: &TcStatsBasicBuffer) -> Result { Ok(TcStatsBasic { bytes: buf.bytes(), diff --git a/src/tc/stats/compat.rs b/src/tc/stats/compat.rs index 5d8cd397..f193fc28 100644 --- a/src/tc/stats/compat.rs +++ b/src/tc/stats/compat.rs @@ -41,6 +41,7 @@ buffer!(TcStatsBuffer(STATS_LEN) { }); impl> Parseable> for TcStats { + type Error = DecodeError; fn parse(buf: &TcStatsBuffer) -> Result { Ok(Self { bytes: buf.bytes(), diff --git a/src/tc/stats/queue.rs b/src/tc/stats/queue.rs index 9909e819..893d2a7e 100644 --- a/src/tc/stats/queue.rs +++ b/src/tc/stats/queue.rs @@ -32,6 +32,7 @@ buffer!(TcStatsQueueBuffer( STATS_QUEUE_LEN) { }); impl> Parseable> for TcStatsQueue { + type Error = DecodeError; fn parse(buf: &TcStatsQueueBuffer) -> Result { Ok(Self { qlen: buf.qlen(), diff --git a/src/tc/stats/stats2.rs b/src/tc/stats/stats2.rs index 9cab4f1e..931497fa 100644 --- a/src/tc/stats/stats2.rs +++ b/src/tc/stats/stats2.rs @@ -65,6 +65,7 @@ impl<'a, T> ParseableParametrized, &str> for TcStats2 where T: AsRef<[u8]> + ?Sized, { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: &str, diff --git a/src/tc/stats/xstats.rs b/src/tc/stats/xstats.rs index 38522e2a..876d064f 100644 --- a/src/tc/stats/xstats.rs +++ b/src/tc/stats/xstats.rs @@ -35,6 +35,7 @@ impl<'a, T> ParseableParametrized, &str> for TcXstats where T: AsRef<[u8]> + ?Sized, { + type Error = DecodeError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: &str, From 7ea8af922f9d45b66aff74124ce5b0a2c28fcc73 Mon Sep 17 00:00:00 2001 From: Miguel Flores Ruiz de Eguino <1889916+miguelfrde@users.noreply.github.com> Date: Fri, 19 Apr 2024 18:52:59 -0700 Subject: [PATCH 2/3] A few more typed errors --- src/address/attribute.rs | 93 ++++++------ src/address/error.rs | 30 ++++ src/address/message.rs | 35 +++-- src/address/mod.rs | 2 + src/link/header.rs | 4 +- src/link/link_info/info_port.rs | 10 +- src/message.rs | 114 +++++++-------- src/neighbour/attribute.rs | 122 ++++++++++------ src/neighbour/error.rs | 23 +++ src/neighbour/header.rs | 8 +- src/neighbour/message.rs | 28 ++-- src/neighbour/mod.rs | 2 + src/neighbour_table/attribute.rs | 114 ++++++++++----- src/neighbour_table/error.rs | 25 ++++ src/neighbour_table/header.rs | 10 +- src/neighbour_table/message.rs | 25 ++-- src/neighbour_table/mod.rs | 2 + src/neighbour_table/param.rs | 206 +++++++++++++++++--------- src/nsid/attribute.rs | 55 ++++--- src/nsid/error.rs | 19 +++ src/nsid/header.rs | 8 +- src/nsid/message.rs | 24 ++-- src/nsid/mod.rs | 2 + src/prefix/attribute.rs | 29 ++-- src/prefix/error.rs | 21 +++ src/prefix/header.rs | 4 +- src/prefix/message.rs | 28 ++-- src/prefix/mod.rs | 2 + src/route/attribute.rs | 239 ++++++++++++++++++++----------- src/route/error.rs | 48 +++++++ src/route/header.rs | 20 ++- src/route/lwtunnel.rs | 21 ++- src/route/message.rs | 29 ++-- src/route/metrics.rs | 203 +++++++++++++++++--------- src/route/mod.rs | 2 + src/route/mpls.rs | 37 ++--- src/route/next_hops.rs | 45 +++--- src/route/realm.rs | 14 +- src/rule/attribute.rs | 194 +++++++++++++++---------- src/rule/error.rs | 29 ++++ src/rule/header.rs | 8 +- src/rule/message.rs | 24 ++-- src/rule/mod.rs | 2 + src/rule/port_range.rs | 14 +- src/rule/uid_range.rs | 14 +- src/tc/header.rs | 4 +- 46 files changed, 1257 insertions(+), 735 deletions(-) create mode 100644 src/address/error.rs create mode 100644 src/neighbour/error.rs create mode 100644 src/neighbour_table/error.rs create mode 100644 src/nsid/error.rs create mode 100644 src/prefix/error.rs create mode 100644 src/route/error.rs create mode 100644 src/rule/error.rs diff --git a/src/address/attribute.rs b/src/address/attribute.rs index 2972b925..03075597 100644 --- a/src/address/attribute.rs +++ b/src/address/attribute.rs @@ -1,17 +1,14 @@ // SPDX-License-Identifier: MIT -use std::mem::size_of; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; - -use anyhow::Context; +use crate::address::{AddressError, AddressFlags, CacheInfo, CacheInfoBuffer}; use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer}, parsers::{parse_string, parse_u32}, - DecodeError, Emitable, Parseable, + Emitable, Parseable, }; - -use crate::address::{AddressFlags, CacheInfo, CacheInfoBuffer}; +use std::mem::size_of; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; const IFA_ADDRESS: u16 = 1; const IFA_LOCAL: u16 = 2; @@ -110,9 +107,9 @@ impl Nla for AddressAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for AddressAttribute { - type Error = DecodeError; + type Error = AddressError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { IFA_ADDRESS => { @@ -125,11 +122,10 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> data.copy_from_slice(&payload[0..IPV6_ADDR_LEN]); Self::Address(IpAddr::from(data)) } else { - return Err(DecodeError::from(format!( - "Invalid IFA_LOCAL, got unexpected length \ - of payload {:?}", - payload - ))); + return Err(AddressError::ParseAttributeInvalidPayload { + kind: "IFA_ADDRESS", + payload_length: payload.len(), + }); } } IFA_LOCAL => { @@ -142,27 +138,28 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> data.copy_from_slice(&payload[0..IPV6_ADDR_LEN]); Self::Local(IpAddr::from(data)) } else { - return Err(DecodeError::from(format!( - "Invalid IFA_LOCAL, got unexpected length \ - of payload {:?}", - payload - ))); + return Err(AddressError::ParseAttributeInvalidPayload { + kind: "IFA_LOCAL", + payload_length: payload.len(), + }); } } - IFA_LABEL => Self::Label( - parse_string(payload).context("invalid IFA_LABEL value")?, - ), + IFA_LABEL => Self::Label(parse_string(payload).map_err(|err| { + AddressError::ParseAttribute { + kind: "IFA_LABEL", + err, + } + })?), IFA_BROADCAST => { if payload.len() == IPV4_ADDR_LEN { let mut data = [0u8; IPV4_ADDR_LEN]; data.copy_from_slice(&payload[0..IPV4_ADDR_LEN]); Self::Broadcast(Ipv4Addr::from(data)) } else { - return Err(DecodeError::from(format!( - "Invalid IFA_BROADCAST, got unexpected length \ - of IPv4 address payload {:?}", - payload - ))); + return Err(AddressError::ParseAttributeInvalidPayload { + kind: "IFA_BROADCAST", + payload_length: payload.len(), + }); } } IFA_ANYCAST => { @@ -171,16 +168,19 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> data.copy_from_slice(&payload[0..IPV6_ADDR_LEN]); Self::Anycast(Ipv6Addr::from(data)) } else { - return Err(DecodeError::from(format!( - "Invalid IFA_ANYCAST, got unexpected length \ - of IPv6 address payload {:?}", - payload - ))); + return Err(AddressError::ParseAttributeInvalidPayload { + kind: "IFA_ANYCAST", + payload_length: payload.len(), + }); } } IFA_CACHEINFO => Self::CacheInfo( - CacheInfo::parse(&CacheInfoBuffer::new(payload)) - .context(format!("Invalid IFA_CACHEINFO {:?}", payload))?, + CacheInfo::parse(&CacheInfoBuffer::new(payload)).map_err( + |err| AddressError::ParseAttribute { + kind: "IFA_CACHEINFO", + err, + }, + )?, ), IFA_MULTICAST => { if payload.len() == IPV6_ADDR_LEN { @@ -188,20 +188,25 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> data.copy_from_slice(&payload[0..IPV6_ADDR_LEN]); Self::Multicast(Ipv6Addr::from(data)) } else { - return Err(DecodeError::from(format!( - "Invalid IFA_MULTICAST, got unexpected length \ - of IPv6 address payload {:?}", - payload - ))); + return Err(AddressError::ParseAttributeInvalidPayload { + kind: "IFA_MULTICAST", + payload_length: payload.len(), + }); } } IFA_FLAGS => Self::Flags(AddressFlags::from_bits_retain( - parse_u32(payload).context("invalid IFA_FLAGS value")?, + parse_u32(payload).map_err(|err| { + AddressError::ParseAttribute { + kind: "IFA_FLAGS", + err, + } + })?, )), - kind => Self::Other( - DefaultNla::parse(buf) - .context(format!("unknown NLA type {kind}"))?, - ), + kind => { + Self::Other(DefaultNla::parse(buf).map_err(|err| { + AddressError::ParseUnknownNLA { kind, err } + })?) + } }) } } diff --git a/src/address/error.rs b/src/address/error.rs new file mode 100644 index 00000000..211f14e9 --- /dev/null +++ b/src/address/error.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT + +use netlink_packet_utils::{nla::NlaError, DecodeError}; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum AddressError { + #[error( + "Invalid {kind}, got unexpected length of payload: {payload_length}" + )] + ParseAttributeInvalidPayload { + kind: &'static str, + payload_length: usize, + }, + + #[error("Invalid {kind} value")] + ParseAttribute { + kind: &'static str, + err: DecodeError, + }, + + #[error("unknown NLA {kind}")] + ParseUnknownNLA { kind: u16, err: DecodeError }, + + #[error(transparent)] + NlaAttribute(#[from] NlaError), + + #[error("Faield to parse address buffer: {0:?}")] + FailedBufferInit(DecodeError), +} diff --git a/src/address/message.rs b/src/address/message.rs index dc57ccf1..78864889 100644 --- a/src/address/message.rs +++ b/src/address/message.rs @@ -1,17 +1,17 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use crate::{ + address::{ + AddressAttribute, AddressError, AddressHeaderFlags, AddressScope, + }, + AddressFamily, +}; use netlink_packet_utils::{ - nla::{NlaBuffer, NlasIterator}, + nla::{NlaBuffer, NlaError, NlasIterator}, traits::{Emitable, Parseable}, DecodeError, }; -use crate::{ - address::{AddressAttribute, AddressHeaderFlags, AddressScope}, - AddressFamily, -}; - const ADDRESS_HEADER_LEN: usize = 8; buffer!(AddressMessageBuffer(ADDRESS_HEADER_LEN) { @@ -26,7 +26,7 @@ buffer!(AddressMessageBuffer(ADDRESS_HEADER_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> AddressMessageBuffer<&'a T> { pub fn attributes( &self, - ) -> impl Iterator, DecodeError>> { + ) -> impl Iterator, NlaError>> { NlasIterator::new(self.payload()) } } @@ -76,8 +76,8 @@ impl Emitable for AddressMessage { } impl> Parseable> for AddressHeader { - type Error = DecodeError; - fn parse(buf: &AddressMessageBuffer) -> Result { + type Error = (); + fn parse(buf: &AddressMessageBuffer) -> Result { Ok(Self { family: buf.family().into(), prefix_len: buf.prefix_len(), @@ -91,13 +91,12 @@ impl> Parseable> for AddressHeader { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for AddressMessage { - type Error = DecodeError; - fn parse(buf: &AddressMessageBuffer<&'a T>) -> Result { + type Error = AddressError; + fn parse(buf: &AddressMessageBuffer<&'a T>) -> Result { Ok(AddressMessage { - header: AddressHeader::parse(buf) - .context("failed to parse address message header")?, - attributes: Vec::::parse(buf) - .context("failed to parse address message NLAs")?, + // ok to unwrap, we never fail parsing the header. + header: AddressHeader::parse(buf).unwrap(), + attributes: Vec::::parse(buf)?, }) } } @@ -105,8 +104,8 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { - type Error = DecodeError; - fn parse(buf: &AddressMessageBuffer<&'a T>) -> Result { + type Error = AddressError; + fn parse(buf: &AddressMessageBuffer<&'a T>) -> Result { let mut attributes = vec![]; for nla_buf in buf.attributes() { attributes.push(AddressAttribute::parse(&nla_buf?)?); diff --git a/src/address/mod.rs b/src/address/mod.rs index 5c9119f0..3ea23d3e 100644 --- a/src/address/mod.rs +++ b/src/address/mod.rs @@ -4,6 +4,7 @@ mod addr_flags; mod addr_scope; mod attribute; mod cache_info; +mod error; mod message; #[cfg(test)] @@ -13,4 +14,5 @@ pub use self::addr_flags::{AddressFlags, AddressHeaderFlags}; pub use self::addr_scope::AddressScope; pub use self::attribute::AddressAttribute; pub use self::cache_info::{CacheInfo, CacheInfoBuffer}; +pub use self::error::AddressError; pub use self::message::{AddressHeader, AddressMessage, AddressMessageBuffer}; diff --git a/src/link/header.rs b/src/link/header.rs index 52f4721d..87ea5b93 100644 --- a/src/link/header.rs +++ b/src/link/header.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT use netlink_packet_utils::{ - nla::{NlaBuffer, NlasIterator}, + nla::{NlaBuffer, NlaError, NlasIterator}, traits::{Emitable, Parseable}, DecodeError, }; @@ -25,7 +25,7 @@ buffer!(LinkMessageBuffer(LINK_HEADER_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> LinkMessageBuffer<&'a T> { pub fn attributes( &self, - ) -> impl Iterator, DecodeError>> { + ) -> impl Iterator, NlaError>> { NlasIterator::new(self.payload()) } } diff --git a/src/link/link_info/info_port.rs b/src/link/link_info/info_port.rs index d2bc54d5..870fc58b 100644 --- a/src/link/link_info/info_port.rs +++ b/src/link/link_info/info_port.rs @@ -119,11 +119,17 @@ impl InfoPortData { ) -> Result { let port_data = match kind { InfoPortKind::Bond => NlasIterator::new(payload) - .map(|nla| nla.and_then(|nla| InfoBondPort::parse(&nla))) + .map(|nla| { + let nla = nla?; + InfoBondPort::parse(&nla) + }) .collect::, _>>() .map(InfoPortData::BondPort), InfoPortKind::Bridge => NlasIterator::new(payload) - .map(|nla| nla.and_then(|nla| InfoBridgePort::parse(&nla))) + .map(|nla| { + let nla = nla?; + InfoBridgePort::parse(&nla) + }) .collect::, _>>() .map(InfoPortData::BridgePort), InfoPortKind::Other(_) => Ok(InfoPortData::Other(payload.to_vec())), diff --git a/src/message.rs b/src/message.rs index a3bf10cf..3485128b 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,14 +1,18 @@ // SPDX-License-Identifier: MIT use crate::{ - address::{AddressHeader, AddressMessage, AddressMessageBuffer}, + address::{ + AddressError, AddressHeader, AddressMessage, AddressMessageBuffer, + }, link::{LinkMessage, LinkMessageBuffer}, - neighbour::{NeighbourMessage, NeighbourMessageBuffer}, - neighbour_table::{NeighbourTableMessage, NeighbourTableMessageBuffer}, - nsid::{NsidMessage, NsidMessageBuffer}, - prefix::{PrefixMessage, PrefixMessageBuffer}, - route::{RouteHeader, RouteMessage, RouteMessageBuffer}, - rule::{RuleMessage, RuleMessageBuffer}, + neighbour::{NeighbourError, NeighbourMessage, NeighbourMessageBuffer}, + neighbour_table::{ + NeighbourTableError, NeighbourTableMessage, NeighbourTableMessageBuffer, + }, + nsid::{NsidError, NsidMessage, NsidMessageBuffer}, + prefix::{PrefixError, PrefixMessage, PrefixMessageBuffer}, + route::{RouteError, RouteHeader, RouteMessage, RouteMessageBuffer}, + rule::{RuleError, RuleMessage, RuleMessageBuffer}, tc::{TcMessage, TcMessageBuffer}, }; use netlink_packet_core::{ @@ -84,32 +88,35 @@ pub enum RouteNetlinkMessageParseError { #[error("Invalid link message")] InvalidLinkMessage(#[source] DecodeError), - #[error("Invalid route message")] - InvalidRouteMessage(#[source] DecodeError), + #[error(transparent)] + InvalidRouteMessage(#[from] RouteError), - #[error("Invalid addr message")] - InvalidAddrMessage(#[source] DecodeError), + #[error(transparent)] + InvalidAddrMessage(#[from] AddressError), - #[error("Invalid prefix message")] - InvalidPrefixMessage(#[source] DecodeError), + #[error(transparent)] + InvalidPrefixMessage(#[from] PrefixError), - #[error("Invalid fib rule message")] - InvalidFibRuleMessage(#[source] DecodeError), + #[error(transparent)] + InvalidFibRuleMessage(#[from] RuleError), #[error("Invalid tc message")] InvalidTcMessage(#[source] DecodeError), - #[error("invalid nsid message")] - InvalidNsidMessage(#[source] DecodeError), + #[error(transparent)] + InvalidNsidMessage(#[from] NsidError), - #[error("Invalid neighbour message")] - InvalidNeighbourMessage(#[source] DecodeError), + #[error(transparent)] + InvalidNeighbourMessage(#[from] NeighbourError), - #[error("Invalid neighbour table message")] - InvalidNeighbourTableMessage(#[source] DecodeError), + #[error(transparent)] + InvalidNeighbourTableMessage(#[from] NeighbourTableError), #[error("Unknown message type: {0}")] UnknownMessageType(u16), + + #[error("Parse buffer: {0}")] + ParseBuffer(#[source] DecodeError), } impl<'a, T: AsRef<[u8]> + ?Sized> @@ -156,9 +163,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> RTM_NEWADDR | RTM_GETADDR | RTM_DELADDR => { let msg = match AddressMessageBuffer::new_checked(&buf.inner()) { - Ok(buf) => AddressMessage::parse(&buf).map_err( - RouteNetlinkMessageParseError::InvalidAddrMessage, - )?, + Ok(buf) => AddressMessage::parse(&buf)?, // HACK: iproute2 sends invalid RTM_GETADDR message, where // the header is limited to the // interface family (1 byte) and 3 bytes of padding. @@ -172,7 +177,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> msg.header.family = buf.inner()[0].into(); msg } else { - return Err(RouteNetlinkMessageParseError::InvalidAddrMessage(e)); + return Err(RouteNetlinkMessageParseError::InvalidAddrMessage(AddressError::FailedBufferInit(e))); } } }; @@ -186,11 +191,10 @@ impl<'a, T: AsRef<[u8]> + ?Sized> // Neighbour messages RTM_NEWNEIGH | RTM_GETNEIGH | RTM_DELNEIGH => { - let msg = NeighbourMessageBuffer::new_checked(&buf.inner()) - .and_then(|buffer| NeighbourMessage::parse(&buffer)) - .map_err( - RouteNetlinkMessageParseError::InvalidNeighbourMessage, - )?; + let buf_inner = buf.inner(); + let buffer = NeighbourMessageBuffer::new_checked(&buf_inner) + .map_err(RouteNetlinkMessageParseError::ParseBuffer)?; + let msg = NeighbourMessage::parse(&buffer)?; match message_type { RTM_GETNEIGH => RouteNetlinkMessage::GetNeighbour(msg), RTM_NEWNEIGH => RouteNetlinkMessage::NewNeighbour(msg), @@ -201,11 +205,11 @@ impl<'a, T: AsRef<[u8]> + ?Sized> // Neighbour table messages RTM_NEWNEIGHTBL | RTM_GETNEIGHTBL | RTM_SETNEIGHTBL => { - let msg = NeighbourTableMessageBuffer::new_checked( - &buf.inner(), - ) - .and_then(|buffer| NeighbourTableMessage::parse(&buffer)) - .map_err( + let buf_inner = buf.inner(); + let buffer = + NeighbourTableMessageBuffer::new_checked(&buf_inner) + .map_err(RouteNetlinkMessageParseError::ParseBuffer)?; + let msg = NeighbourTableMessage::parse(&buffer).map_err( RouteNetlinkMessageParseError::InvalidNeighbourTableMessage, )?; match message_type { @@ -225,9 +229,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> // Route messages RTM_NEWROUTE | RTM_GETROUTE | RTM_DELROUTE => { let msg = match RouteMessageBuffer::new_checked(&buf.inner()) { - Ok(buf) => RouteMessage::parse(&buf).map_err( - RouteNetlinkMessageParseError::InvalidRouteMessage, - )?, + Ok(buf) => RouteMessage::parse(&buf)?, // HACK: iproute2 sends invalid RTM_GETROUTE message, where // the header is limited to the // interface family (1 byte) and 3 bytes of padding. @@ -250,7 +252,9 @@ impl<'a, T: AsRef<[u8]> + ?Sized> msg.header.address_family = buf.inner()[0].into(); msg } else { - return Err(RouteNetlinkMessageParseError::InvalidRouteMessage(e)); + return Err( + RouteNetlinkMessageParseError::ParseBuffer(e), + ); } } }; @@ -263,20 +267,17 @@ impl<'a, T: AsRef<[u8]> + ?Sized> } // Prefix messages - RTM_NEWPREFIX => RouteNetlinkMessage::NewPrefix( - PrefixMessageBuffer::new_checked(&buf.inner()) - .and_then(|buffer| PrefixMessage::parse(&buffer)) - .map_err( - RouteNetlinkMessageParseError::InvalidPrefixMessage, - )?, - ), - + RTM_NEWPREFIX => { + let buf_inner = buf.inner(); + let buffer = PrefixMessageBuffer::new_checked(&buf_inner) + .map_err(RouteNetlinkMessageParseError::ParseBuffer)?; + RouteNetlinkMessage::NewPrefix(PrefixMessage::parse(&buffer)?) + } RTM_NEWRULE | RTM_GETRULE | RTM_DELRULE => { - let msg = RuleMessageBuffer::new_checked(&buf.inner()) - .and_then(|buffer| RuleMessage::parse(&buffer)) - .map_err( - RouteNetlinkMessageParseError::InvalidFibRuleMessage, - )?; + let buf_inner = buf.inner(); + let buffer = RuleMessageBuffer::new_checked(&buf_inner) + .map_err(RouteNetlinkMessageParseError::ParseBuffer)?; + let msg = RuleMessage::parse(&buffer)?; match message_type { RTM_NEWRULE => RouteNetlinkMessage::NewRule(msg), RTM_DELRULE => RouteNetlinkMessage::DelRule(msg), @@ -323,11 +324,10 @@ impl<'a, T: AsRef<[u8]> + ?Sized> // ND ID Messages RTM_NEWNSID | RTM_GETNSID | RTM_DELNSID => { - let msg = NsidMessageBuffer::new_checked(&buf.inner()) - .and_then(|buffer| NsidMessage::parse(&buffer)) - .map_err( - RouteNetlinkMessageParseError::InvalidNsidMessage, - )?; + let buf_inner = buf.inner(); + let buffer = NsidMessageBuffer::new_checked(&buf_inner) + .map_err(RouteNetlinkMessageParseError::ParseBuffer)?; + let msg = NsidMessage::parse(&buffer)?; match message_type { RTM_NEWNSID => RouteNetlinkMessage::NewNsId(msg), RTM_DELNSID => RouteNetlinkMessage::DelNsId(msg), diff --git a/src/neighbour/attribute.rs b/src/neighbour/attribute.rs index 5f5c718f..48d7f50c 100644 --- a/src/neighbour/attribute.rs +++ b/src/neighbour/attribute.rs @@ -1,16 +1,17 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::{ + NeighbourAddress, NeighbourCacheInfo, NeighbourCacheInfoBuffer, + NeighbourError, +}; +use crate::{route::RouteProtocol, AddressFamily}; use byteorder::{BigEndian, ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer}, parsers::{parse_u16, parse_u16_be, parse_u32}, - DecodeError, Emitable, Parseable, ParseableParametrized, + Emitable, Parseable, ParseableParametrized, }; -use super::{NeighbourAddress, NeighbourCacheInfo, NeighbourCacheInfoBuffer}; -use crate::{route::RouteProtocol, AddressFamily}; - const NDA_DST: u16 = 1; const NDA_LLADDR: u16 = 2; const NDA_CACHEINFO: u16 = 3; @@ -106,58 +107,93 @@ impl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized, AddressFamily> for NeighbourAttribute { - type Error = DecodeError; + type Error = NeighbourError; fn parse_with_param( buf: &NlaBuffer<&'a T>, address_family: AddressFamily, - ) -> Result { + ) -> Result { let payload = buf.value(); Ok(match buf.kind() { NDA_DST => Self::Destination( NeighbourAddress::parse_with_param(address_family, payload) - .context(format!("invalid NDA_DST value {:?}", payload))?, + .map_err(|error| NeighbourError::InvalidValue { + kind: "NDA_DST", + error, + })?, ), NDA_LLADDR => Self::LinkLocalAddress(payload.to_vec()), NDA_CACHEINFO => Self::CacheInfo( - NeighbourCacheInfo::parse( - &NeighbourCacheInfoBuffer::new_checked(payload).context( - format!("invalid NDA_CACHEINFO value {:?}", payload), - )?, - ) - .context(format!( - "invalid NDA_CACHEINFO value {:?}", - payload - ))?, + NeighbourCacheInfoBuffer::new_checked(payload) + .and_then(|buffer| NeighbourCacheInfo::parse(&buffer)) + .map_err(|error| NeighbourError::InvalidValue { + kind: "NDA_CACHEINFO", + error, + })?, ), NDA_PROBES => { - Self::Probes(parse_u32(payload).context(format!( - "invalid NDA_PROBES value {:?}", - payload - ))?) + Self::Probes(parse_u32(payload).map_err(|error| { + NeighbourError::InvalidValue { + kind: "NDA_PROBES", + error, + } + })?) } - NDA_VLAN => Self::Vlan(parse_u16(payload)?), - NDA_PORT => Self::Port( - parse_u16_be(payload) - .context(format!("invalid NDA_PORT value {payload:?}"))?, - ), - NDA_VNI => Self::Vni(parse_u32(payload)?), - NDA_IFINDEX => Self::IfIndex(parse_u32(payload)?), - NDA_CONTROLLER => Self::Controller(parse_u32(payload).context( - format!("invalid NDA_CONTROLLER value {payload:?}"), - )?), - NDA_LINK_NETNSID => Self::LinkNetNsId(parse_u32(payload).context( - format!("invalid NDA_LINK_NETNSID value {payload:?}"), - )?), - NDA_SRC_VNI => Self::SourceVni(parse_u32(payload)?), - NDA_PROTOCOL => { - Self::Protocol(RouteProtocol::parse(payload).context( - format!("invalid NDA_PROTOCOL value {:?}", payload), - )?) + NDA_VLAN => Self::Vlan(parse_u16(payload).map_err(|error| { + NeighbourError::InvalidValue { + kind: "NDA_VLAN", + error, + } + })?), + NDA_PORT => Self::Port(parse_u16_be(payload).map_err(|error| { + NeighbourError::InvalidValue { + kind: "NDA_PORT", + error, + } + })?), + NDA_VNI => Self::Vni(parse_u32(payload).map_err(|error| { + NeighbourError::InvalidValue { + kind: "NDA_VNI", + error, + } + })?), + NDA_IFINDEX => { + Self::IfIndex(parse_u32(payload).map_err(|error| { + NeighbourError::InvalidValue { + kind: "NDA_IFINDEX", + error, + } + })?) + } + NDA_CONTROLLER => { + Self::Controller(parse_u32(payload).map_err(|error| { + NeighbourError::InvalidValue { + kind: "NDA_CONTROLLER", + error, + } + })?) + } + NDA_LINK_NETNSID => { + Self::LinkNetNsId(parse_u32(payload).map_err(|error| { + NeighbourError::InvalidValue { + kind: "NDA_LINK_NETNSID", + error, + } + })?) + } + NDA_SRC_VNI => { + Self::SourceVni(parse_u32(payload).map_err(|error| { + NeighbourError::InvalidValue { + kind: "NDA_SRC_VNI", + error, + } + })?) + } + NDA_PROTOCOL => Self::Protocol(RouteProtocol::parse(payload)?), + kind => { + Self::Other(DefaultNla::parse(buf).map_err(|error| { + NeighbourError::UnknownNLA { kind, error } + })?) } - _ => Self::Other( - DefaultNla::parse(buf) - .context("invalid link NLA value (unknown type)")?, - ), }) } } diff --git a/src/neighbour/error.rs b/src/neighbour/error.rs new file mode 100644 index 00000000..3decd82c --- /dev/null +++ b/src/neighbour/error.rs @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +use crate::route::RouteError; +use netlink_packet_utils::{nla::NlaError, DecodeError}; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum NeighbourError { + #[error("Invalid {kind}")] + InvalidValue { + kind: &'static str, + error: DecodeError, + }, + + #[error("Unknown NLA type: {kind}")] + UnknownNLA { kind: u16, error: DecodeError }, + + #[error(transparent)] + ParseNdaProtocol(#[from] RouteError), + + #[error(transparent)] + ParseNla(#[from] NlaError), +} diff --git a/src/neighbour/header.rs b/src/neighbour/header.rs index 967c57e4..c915143a 100644 --- a/src/neighbour/header.rs +++ b/src/neighbour/header.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT use netlink_packet_utils::{ - nla::{NlaBuffer, NlasIterator}, + nla::{NlaBuffer, NlaError, NlasIterator}, traits::{Emitable, Parseable}, DecodeError, }; @@ -23,7 +23,7 @@ buffer!(NeighbourMessageBuffer(NEIGHBOUR_HEADER_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> NeighbourMessageBuffer<&'a T> { pub fn attributes( &self, - ) -> impl Iterator, DecodeError>> { + ) -> impl Iterator, NlaError>> { NlasIterator::new(self.payload()) } } @@ -58,8 +58,8 @@ pub struct NeighbourHeader { } impl> Parseable> for NeighbourHeader { - type Error = DecodeError; - fn parse(buf: &NeighbourMessageBuffer) -> Result { + type Error = (); + fn parse(buf: &NeighbourMessageBuffer) -> Result { Ok(Self { family: buf.family().into(), ifindex: buf.ifindex(), diff --git a/src/neighbour/message.rs b/src/neighbour/message.rs index 9381c2ad..617a723d 100644 --- a/src/neighbour/message.rs +++ b/src/neighbour/message.rs @@ -1,15 +1,12 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; -use netlink_packet_utils::{ - traits::{Emitable, Parseable, ParseableParametrized}, - DecodeError, -}; - use super::{ - super::AddressFamily, NeighbourAttribute, NeighbourHeader, + super::AddressFamily, NeighbourAttribute, NeighbourError, NeighbourHeader, NeighbourMessageBuffer, }; +use netlink_packet_utils::traits::{ + Emitable, Parseable, ParseableParametrized, +}; #[derive(Debug, PartialEq, Eq, Clone, Default)] #[non_exhaustive] @@ -34,18 +31,19 @@ impl Emitable for NeighbourMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for NeighbourMessage { - type Error = DecodeError; - fn parse(buf: &NeighbourMessageBuffer<&'a T>) -> Result { - let header = NeighbourHeader::parse(buf) - .context("failed to parse neighbour message header")?; + type Error = NeighbourError; + fn parse( + buf: &NeighbourMessageBuffer<&'a T>, + ) -> Result { + // unwrap: parsing the header is always ok. + let header = NeighbourHeader::parse(buf).unwrap(); let address_family = header.family; Ok(NeighbourMessage { header, attributes: Vec::::parse_with_param( buf, address_family, - ) - .context("failed to parse neighbour message NLAs")?, + )?, }) } } @@ -54,11 +52,11 @@ impl<'a, T: AsRef<[u8]> + 'a> ParseableParametrized, AddressFamily> for Vec { - type Error = DecodeError; + type Error = NeighbourError; fn parse_with_param( buf: &NeighbourMessageBuffer<&'a T>, address_family: AddressFamily, - ) -> Result { + ) -> Result { let mut attributes = vec![]; for nla_buf in buf.attributes() { attributes.push(NeighbourAttribute::parse_with_param( diff --git a/src/neighbour/mod.rs b/src/neighbour/mod.rs index 9b8c105e..88366970 100644 --- a/src/neighbour/mod.rs +++ b/src/neighbour/mod.rs @@ -3,6 +3,7 @@ mod address; mod attribute; mod cache_info; +mod error; mod flags; mod header; mod message; @@ -14,6 +15,7 @@ mod tests; pub use self::address::NeighbourAddress; pub use self::attribute::NeighbourAttribute; pub use self::cache_info::{NeighbourCacheInfo, NeighbourCacheInfoBuffer}; +pub use self::error::NeighbourError; pub use self::flags::NeighbourFlags; pub use self::header::{NeighbourHeader, NeighbourMessageBuffer}; pub use self::message::NeighbourMessage; diff --git a/src/neighbour_table/attribute.rs b/src/neighbour_table/attribute.rs index 11affd6d..1b9ce6ae 100644 --- a/src/neighbour_table/attribute.rs +++ b/src/neighbour_table/attribute.rs @@ -1,17 +1,15 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::{ + param::VecNeighbourTableParameter, NeighbourTableConfig, + NeighbourTableConfigBuffer, NeighbourTableError, NeighbourTableParameter, + NeighbourTableStats, NeighbourTableStatsBuffer, +}; use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer}, parsers::{parse_string, parse_u32, parse_u64}, - DecodeError, Emitable, Parseable, -}; - -use super::{ - param::VecNeighbourTableParameter, NeighbourTableConfig, - NeighbourTableConfigBuffer, NeighbourTableParameter, NeighbourTableStats, - NeighbourTableStatsBuffer, + Emitable, Parseable, }; const NDTA_NAME: u16 = 1; @@ -90,48 +88,88 @@ impl Nla for NeighbourTableAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for NeighbourTableAttribute { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = NeighbourTableError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { - NDTA_NAME => Self::Name( - parse_string(payload).context("invalid NDTA_NAME value")?, - ), + NDTA_NAME => { + Self::Name(parse_string(payload).map_err(|error| { + NeighbourTableError::InvalidValue { + kind: "NDTA_NAME", + error, + } + })?) + } NDTA_CONFIG => Self::Config( NeighbourTableConfig::parse( - &NeighbourTableConfigBuffer::new_checked(payload) - .context(format!("invalid NDTA_CONFIG {payload:?}"))?, + &NeighbourTableConfigBuffer::new_checked(payload).map_err( + |error| NeighbourTableError::InvalidValue { + kind: "NDTA_CONFIG", + error, + }, + )?, ) - .context(format!("invalid NDTA_CONFIG {payload:?}"))?, + .map_err(|error| { + NeighbourTableError::InvalidValue { + kind: "NDTA_CONFIG", + error, + } + })?, ), NDTA_STATS => Self::Stats( NeighbourTableStats::parse( - &NeighbourTableStatsBuffer::new_checked(payload) - .context(format!("invalid NDTA_STATS {payload:?}"))?, + &NeighbourTableStatsBuffer::new_checked(payload).map_err( + |error| NeighbourTableError::InvalidValue { + kind: "NDTA_STATS", + error, + }, + )?, ) - .context(format!("invalid NDTA_STATS {payload:?}"))?, + .map_err(|error| { + NeighbourTableError::InvalidValue { + kind: "NDTA_STATS", + error, + } + })?, ), NDTA_PARMS => Self::Parms( - VecNeighbourTableParameter::parse(&NlaBuffer::new(payload)) - .context(format!("invalid NDTA_PARMS {payload:?}"))? - .0, - ), - NDTA_GC_INTERVAL => Self::GcInterval( - parse_u64(payload).context("invalid NDTA_GC_INTERVAL value")?, - ), - NDTA_THRESH1 => Self::Threshold1( - parse_u32(payload).context("invalid NDTA_THRESH1 value")?, - ), - NDTA_THRESH2 => Self::Threshold2( - parse_u32(payload).context("invalid NDTA_THRESH2 value")?, - ), - NDTA_THRESH3 => Self::Threshold3( - parse_u32(payload).context("invalid NDTA_THRESH3 value")?, - ), - kind => Self::Other( - DefaultNla::parse(buf) - .context(format!("unknown NLA type {kind}"))?, + VecNeighbourTableParameter::parse(&NlaBuffer::new(payload))?.0, ), + NDTA_GC_INTERVAL => { + Self::GcInterval(parse_u64(payload).map_err(|error| { + NeighbourTableError::InvalidValue { + kind: "NDTA_GC_INTERVAL", + error, + } + })?) + } + NDTA_THRESH1 => { + Self::Threshold1(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidValue { + kind: "NDTA_THRESH1", + error, + } + })?) + } + NDTA_THRESH2 => { + Self::Threshold2(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidValue { + kind: "NDTA_THRESH2", + error, + } + })?) + } + NDTA_THRESH3 => { + Self::Threshold3(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidValue { + kind: "NDTA_THRESH3", + error, + } + })?) + } + kind => Self::Other(DefaultNla::parse(buf).map_err(|error| { + NeighbourTableError::UnknownNla { kind, error } + })?), }) } } diff --git a/src/neighbour_table/error.rs b/src/neighbour_table/error.rs new file mode 100644 index 00000000..3b0b3843 --- /dev/null +++ b/src/neighbour_table/error.rs @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +use netlink_packet_utils::{nla::NlaError, DecodeError}; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum NeighbourTableError { + #[error("Invalid {kind}")] + InvalidValue { + kind: &'static str, + error: DecodeError, + }, + + #[error("Invalid {kind} value")] + InvalidParameter { + kind: &'static str, + error: DecodeError, + }, + + #[error("Unknown NLA type: {kind}")] + UnknownNla { kind: u16, error: DecodeError }, + + #[error(transparent)] + ParseNla(#[from] NlaError), +} diff --git a/src/neighbour_table/header.rs b/src/neighbour_table/header.rs index 1ed81ceb..1387ca27 100644 --- a/src/neighbour_table/header.rs +++ b/src/neighbour_table/header.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT use netlink_packet_utils::{ - nla::{NlaBuffer, NlasIterator}, + nla::{NlaBuffer, NlaError, NlasIterator}, traits::{Emitable, Parseable}, DecodeError, }; @@ -18,7 +18,7 @@ buffer!(NeighbourTableMessageBuffer(NEIGHBOUR_TABLE_HEADER_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> NeighbourTableMessageBuffer<&'a T> { pub fn attributes( &self, - ) -> impl Iterator, DecodeError>> { + ) -> impl Iterator, NlaError>> { NlasIterator::new(self.payload()) } } @@ -32,10 +32,8 @@ pub struct NeighbourTableHeader { impl> Parseable> for NeighbourTableHeader { - type Error = DecodeError; - fn parse( - buf: &NeighbourTableMessageBuffer, - ) -> Result { + type Error = (); + fn parse(buf: &NeighbourTableMessageBuffer) -> Result { Ok(Self { family: buf.family().into(), }) diff --git a/src/neighbour_table/message.rs b/src/neighbour_table/message.rs index 87f0b1c2..3796d6c3 100644 --- a/src/neighbour_table/message.rs +++ b/src/neighbour_table/message.rs @@ -1,14 +1,10 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; -use netlink_packet_utils::{ - traits::{Emitable, Parseable}, - DecodeError, -}; - use super::{ - NeighbourTableAttribute, NeighbourTableHeader, NeighbourTableMessageBuffer, + NeighbourTableAttribute, NeighbourTableError, NeighbourTableHeader, + NeighbourTableMessageBuffer, }; +use netlink_packet_utils::traits::{Emitable, Parseable}; #[derive(Debug, PartialEq, Eq, Clone, Default)] #[non_exhaustive] @@ -33,15 +29,14 @@ impl Emitable for NeighbourTableMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for NeighbourTableMessage { - type Error = DecodeError; + type Error = NeighbourTableError; fn parse( buf: &NeighbourTableMessageBuffer<&'a T>, - ) -> Result { + ) -> Result { Ok(NeighbourTableMessage { - header: NeighbourTableHeader::parse(buf) - .context("failed to parse neighbour table message header")?, - attributes: Vec::::parse(buf) - .context("failed to parse neighbour table message NLAs")?, + // unwrap: we always succeed at parsing the header + header: NeighbourTableHeader::parse(buf).unwrap(), + attributes: Vec::::parse(buf)?, }) } } @@ -49,10 +44,10 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { - type Error = DecodeError; + type Error = NeighbourTableError; fn parse( buf: &NeighbourTableMessageBuffer<&'a T>, - ) -> Result { + ) -> Result { let mut attributes = vec![]; for nla_buf in buf.attributes() { attributes.push(NeighbourTableAttribute::parse(&nla_buf?)?); diff --git a/src/neighbour_table/mod.rs b/src/neighbour_table/mod.rs index 51f6f8c2..26bfb6a6 100644 --- a/src/neighbour_table/mod.rs +++ b/src/neighbour_table/mod.rs @@ -2,6 +2,7 @@ mod attribute; mod config; +mod error; mod header; mod message; pub(crate) mod param; @@ -11,6 +12,7 @@ mod tests; pub use self::attribute::NeighbourTableAttribute; pub use self::config::{NeighbourTableConfig, NeighbourTableConfigBuffer}; +pub use self::error::NeighbourTableError; pub use self::header::{NeighbourTableHeader, NeighbourTableMessageBuffer}; pub use self::message::NeighbourTableMessage; pub use self::param::NeighbourTableParameter; diff --git a/src/neighbour_table/param.rs b/src/neighbour_table/param.rs index 32d0ed8b..c2588fb8 100644 --- a/src/neighbour_table/param.rs +++ b/src/neighbour_table/param.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::NeighbourTableError; use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, @@ -135,93 +135,160 @@ impl Nla for NeighbourTableParameter { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for NeighbourTableParameter { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = NeighbourTableError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { NDTPA_IFINDEX => { - Self::Ifindex(parse_u32(payload).context(format!( - "invalid NDTPA_IFINDEX value {payload:?}" - ))?) + Self::Ifindex(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_IFINDEX", + error, + } + })?) } NDTPA_REFCNT => { - Self::ReferenceCount(parse_u32(payload).context(format!( - "invalid NDTPA_REFCNT value {payload:?}" - ))?) + Self::ReferenceCount(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_REFCNT", + error, + } + })?) } NDTPA_REACHABLE_TIME => { - Self::ReachableTime(parse_u64(payload).context(format!( - "invalid NDTPA_REACHABLE_TIME value {payload:?}" - ))?) + Self::ReachableTime(parse_u64(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_REACHABLE_TIME", + error, + } + })?) } NDTPA_BASE_REACHABLE_TIME => { - Self::BaseReachableTime(parse_u64(payload).context(format!( - "invalid NDTPA_BASE_REACHABLE_TIME value {payload:?}" - ))?) + Self::BaseReachableTime(parse_u64(payload).map_err( + |error| NeighbourTableError::InvalidParameter { + kind: "NDTPA_BASE_REACHABLE_TIME", + error, + }, + )?) } NDTPA_RETRANS_TIME => { - Self::RetransTime(parse_u64(payload).context(format!( - "invalid NDTPA_RETRANS_TIME value {payload:?}" - ))?) + Self::RetransTime(parse_u64(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_RETRANS_TIME", + error, + } + })?) } NDTPA_GC_STALETIME => { - Self::GcStaletime(parse_u64(payload).context(format!( - "invalid NDTPA_GC_STALE_TIME value {payload:?}" - ))?) + Self::GcStaletime(parse_u64(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_GC_STALETIME", + error, + } + })?) } NDTPA_DELAY_PROBE_TIME => { - Self::DelayProbeTime(parse_u64(payload).context(format!( - "invalid NDTPA_DELAY_PROBE_TIME value {payload:?}" - ))?) - } - NDTPA_QUEUE_LEN => Self::QueueLen(parse_u32(payload).context( - format!("invalid NDTPA_QUEUE_LEN value {payload:?}"), - )?), - NDTPA_APP_PROBES => Self::AppProbes(parse_u32(payload).context( - format!("invalid NDTPA_APP_PROBES value {payload:?}"), - )?), + Self::DelayProbeTime(parse_u64(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_DELAY_PROBE_TIME", + error, + } + })?) + } + NDTPA_QUEUE_LEN => { + Self::QueueLen(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_QUEUE_LEN", + error, + } + })?) + } + NDTPA_APP_PROBES => { + Self::AppProbes(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_APP_PROBES", + error, + } + })?) + } NDTPA_UCAST_PROBES => { - Self::UcastProbes(parse_u32(payload).context(format!( - "invalid NDTPA_UCAST_PROBES value {payload:?}" - ))?) + Self::UcastProbes(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_UCAST_PROBES", + error, + } + })?) } NDTPA_MCAST_PROBES => { - Self::McastProbes(parse_u32(payload).context(format!( - "invalid NDTPA_MCAST_PROBES value {payload:?}" - ))?) + Self::McastProbes(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_MCAST_PROBES", + error, + } + })?) } NDTPA_ANYCAST_DELAY => { - Self::AnycastDelay(parse_u64(payload).context(format!( - "invalid NDTPA_ANYCAST_DELAY value {payload:?}" - ))?) - } - NDTPA_PROXY_DELAY => Self::ProxyDelay(parse_u64(payload).context( - format!("invalid NDTPA_PROXY_DELAY value {payload:?}"), - )?), - NDTPA_PROXY_QLEN => Self::ProxyQlen(parse_u32(payload).context( - format!("invalid NDTPA_PROXY_QLEN value {payload:?}"), - )?), - NDTPA_LOCKTIME => Self::Locktime(parse_u64(payload).context( - format!("invalid NDTPA_LOCKTIME value {payload:?}"), - )?), + Self::AnycastDelay(parse_u64(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_ANYCAST_DELAY", + error, + } + })?) + } + NDTPA_PROXY_DELAY => { + Self::ProxyDelay(parse_u64(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_PROXY_DELAY", + error, + } + })?) + } + NDTPA_PROXY_QLEN => { + Self::ProxyQlen(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_PROXY_QLEN", + error, + } + })?) + } + NDTPA_LOCKTIME => { + Self::Locktime(parse_u64(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_LOCKTIME", + error, + } + })?) + } NDTPA_QUEUE_LENBYTES => { - Self::QueueLenbytes(parse_u32(payload).context(format!( - "invalid NDTPA_QUEUE_LENBYTES value {payload:?}" - ))?) + Self::QueueLenbytes(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_QUEUE_LENBYTES", + error, + } + })?) } NDTPA_MCAST_REPROBES => { - Self::McastReprobes(parse_u32(payload).context(format!( - "invalid NDTPA_MCAST_PROBES value {payload:?}" - ))?) - } - NDTPA_INTERVAL_PROBE_TIME_MS => Self::IntervalProbeTimeMs( - parse_u64(payload).context(format!( - "invalid NDTPA_INTERVAL_PROBE_TIME_MS value {payload:?}" - ))?, - ), - _ => Self::Other(DefaultNla::parse(buf).context(format!( - "invalid NDTA_PARMS attribute {payload:?}" - ))?), + Self::McastReprobes(parse_u32(payload).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTPA_MCAST_REPROBES", + error, + } + })?) + } + NDTPA_INTERVAL_PROBE_TIME_MS => { + Self::IntervalProbeTimeMs(parse_u64(payload).map_err( + |error| NeighbourTableError::InvalidParameter { + kind: "NDTPA_INTERVAL_PROBE_TIME_MS", + error, + }, + )?) + } + _ => Self::Other(DefaultNla::parse(buf).map_err(|error| { + NeighbourTableError::InvalidParameter { + kind: "NDTA_PARMS", + error, + } + })?), }) } } @@ -234,13 +301,12 @@ pub(crate) struct VecNeighbourTableParameter( impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for VecNeighbourTableParameter { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = NeighbourTableError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut nlas = vec![]; - let err = "invalid NDTA_PARMS attribute"; for nla in NlasIterator::new(buf.into_inner()) { - let nla = nla.context(err)?; - nlas.push(NeighbourTableParameter::parse(&nla).context(err)?); + let nla = nla?; + nlas.push(NeighbourTableParameter::parse(&nla)?); } Ok(Self(nlas)) } diff --git a/src/nsid/attribute.rs b/src/nsid/attribute.rs index 0546d213..b04f88c2 100644 --- a/src/nsid/attribute.rs +++ b/src/nsid/attribute.rs @@ -1,13 +1,11 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::NsidError; use byteorder::{ByteOrder, NativeEndian}; - use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer}, parsers::{parse_i32, parse_u32}, traits::Parseable, - DecodeError, }; const NETNSA_NSID: u16 = 1; @@ -65,28 +63,47 @@ impl Nla for NsidAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for NsidAttribute { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = NsidError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { - NETNSA_NSID => { - Self::Id(parse_i32(payload).context("invalid NETNSA_NSID")?) - } - NETNSA_PID => { - Self::Pid(parse_u32(payload).context("invalid NETNSA_PID")?) + NETNSA_NSID => Self::Id(parse_i32(payload).map_err(|error| { + NsidError::InvalidValue { + kind: "NETNSA_NSID", + error, + } + })?), + NETNSA_PID => Self::Pid(parse_u32(payload).map_err(|error| { + NsidError::InvalidValue { + kind: "NETNSA_PID", + error, + } + })?), + NETNSA_FD => Self::Fd(parse_u32(payload).map_err(|error| { + NsidError::InvalidValue { + kind: "NETNSA_FD", + error, + } + })?), + NETNSA_TARGET_NSID => { + Self::TargetNsid(parse_i32(payload).map_err(|error| { + NsidError::InvalidValue { + kind: "NETNSA_TARGET_NSID", + error, + } + })?) } - NETNSA_FD => { - Self::Fd(parse_u32(payload).context("invalid NETNSA_FD")?) + NETNSA_CURRENT_NSID => { + Self::CurrentNsid(parse_i32(payload).map_err(|error| { + NsidError::InvalidValue { + kind: "NETNSA_CURRENT_NSID", + error, + } + })?) } - NETNSA_TARGET_NSID => Self::TargetNsid( - parse_i32(payload).context("invalid NETNSA_TARGET_NSID")?, - ), - NETNSA_CURRENT_NSID => Self::CurrentNsid( - parse_i32(payload).context("invalid NETNSA_CURRENT_NSID")?, - ), kind => Self::Other( DefaultNla::parse(buf) - .context(format!("unknown NLA type {kind}"))?, + .map_err(|error| NsidError::UnknownNLA { kind, error })?, ), }) } diff --git a/src/nsid/error.rs b/src/nsid/error.rs new file mode 100644 index 00000000..d6608b33 --- /dev/null +++ b/src/nsid/error.rs @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +use netlink_packet_utils::{nla::NlaError, DecodeError}; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum NsidError { + #[error("Invalid {kind}")] + InvalidValue { + kind: &'static str, + error: DecodeError, + }, + + #[error("Unknown NLA type: {kind}")] + UnknownNLA { kind: u16, error: DecodeError }, + + #[error(transparent)] + ParseNla(#[from] NlaError), +} diff --git a/src/nsid/header.rs b/src/nsid/header.rs index ff2c9f98..f8b6e923 100644 --- a/src/nsid/header.rs +++ b/src/nsid/header.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT use netlink_packet_utils::{ - nla::{NlaBuffer, NlasIterator}, + nla::{NlaBuffer, NlaError, NlasIterator}, DecodeError, Emitable, Parseable, }; @@ -17,7 +17,7 @@ buffer!(NsidMessageBuffer(NSID_HEADER_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> NsidMessageBuffer<&'a T> { pub fn attributes( &self, - ) -> impl Iterator, DecodeError>> { + ) -> impl Iterator, NlaError>> { NlasIterator::new(self.payload()) } } @@ -39,8 +39,8 @@ impl Emitable for NsidHeader { } impl> Parseable> for NsidHeader { - type Error = DecodeError; - fn parse(buf: &NsidMessageBuffer) -> Result { + type Error = (); + fn parse(buf: &NsidMessageBuffer) -> Result { Ok(NsidHeader { family: buf.family().into(), }) diff --git a/src/nsid/message.rs b/src/nsid/message.rs index e05f8d6f..855541b4 100644 --- a/src/nsid/message.rs +++ b/src/nsid/message.rs @@ -1,12 +1,7 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; -use netlink_packet_utils::{ - traits::{Emitable, Parseable}, - DecodeError, -}; - -use crate::nsid::{NsidAttribute, NsidHeader, NsidMessageBuffer}; +use crate::nsid::{NsidAttribute, NsidError, NsidHeader, NsidMessageBuffer}; +use netlink_packet_utils::traits::{Emitable, Parseable}; #[derive(Debug, PartialEq, Eq, Clone, Default)] #[non_exhaustive] @@ -18,13 +13,12 @@ pub struct NsidMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for NsidMessage { - type Error = DecodeError; - fn parse(buf: &NsidMessageBuffer<&'a T>) -> Result { + type Error = NsidError; + fn parse(buf: &NsidMessageBuffer<&'a T>) -> Result { Ok(Self { - header: NsidHeader::parse(buf) - .context("failed to parse nsid message header")?, - attributes: Vec::::parse(buf) - .context("failed to parse nsid message NLAs")?, + // unwrap: parsing the header can't fail + header: NsidHeader::parse(buf).unwrap(), + attributes: Vec::::parse(buf)?, }) } } @@ -32,8 +26,8 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { - type Error = DecodeError; - fn parse(buf: &NsidMessageBuffer<&'a T>) -> Result { + type Error = NsidError; + fn parse(buf: &NsidMessageBuffer<&'a T>) -> Result { let mut attributes = vec![]; for nla_buf in buf.attributes() { attributes.push(NsidAttribute::parse(&nla_buf?)?); diff --git a/src/nsid/mod.rs b/src/nsid/mod.rs index 1b7f7b8e..0c07d217 100644 --- a/src/nsid/mod.rs +++ b/src/nsid/mod.rs @@ -1,11 +1,13 @@ // SPDX-License-Identifier: MIT mod attribute; +mod error; mod header; mod message; #[cfg(test)] mod tests; pub use self::attribute::NsidAttribute; +pub use self::error::NsidError; pub use self::header::{NsidHeader, NsidMessageBuffer}; pub use self::message::NsidMessage; diff --git a/src/prefix/attribute.rs b/src/prefix/attribute.rs index 3cd1515a..dc3e2017 100644 --- a/src/prefix/attribute.rs +++ b/src/prefix/attribute.rs @@ -1,15 +1,15 @@ // SPDX-License-Identifier: MIT -use std::net::Ipv6Addr; - -use anyhow::Context; +use super::{ + cache_info::{CacheInfo, CacheInfoBuffer}, + error::PrefixError, +}; use netlink_packet_utils::{ nla::{self, DefaultNla, NlaBuffer}, traits::Parseable, - DecodeError, Emitable, + Emitable, }; - -use super::cache_info::{CacheInfo, CacheInfoBuffer}; +use std::net::Ipv6Addr; const PREFIX_ADDRESS: u16 = 1; const PREFIX_CACHEINFO: u16 = 2; @@ -50,23 +50,26 @@ impl nla::Nla for PrefixAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for PrefixAttribute { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = PrefixError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); match buf.kind() { PREFIX_ADDRESS => { if let Ok(payload) = TryInto::<[u8; 16]>::try_into(payload) { Ok(Self::Address(Ipv6Addr::from(payload))) } else { - Err(DecodeError::from(format!("Invalid PREFIX_ADDRESS, unexpected payload length: {:?}", payload))) + Err(PrefixError::InvalidPrefixAddress { + payload_length: payload.len(), + }) } } PREFIX_CACHEINFO => Ok(Self::CacheInfo( - CacheInfo::parse(&CacheInfoBuffer::new(payload)).context( - format!("Invalid PREFIX_CACHEINFO: {:?}", payload), - )?, + CacheInfo::parse(&CacheInfoBuffer::new(payload)) + .map_err(PrefixError::InvalidPrefixCacheInfo)?, + )), + _ => Ok(Self::Other( + DefaultNla::parse(buf).map_err(PrefixError::Other)?, )), - _ => Ok(Self::Other(DefaultNla::parse(buf)?)), } } } diff --git a/src/prefix/error.rs b/src/prefix/error.rs new file mode 100644 index 00000000..c3107338 --- /dev/null +++ b/src/prefix/error.rs @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT + +use netlink_packet_utils::{nla::NlaError, DecodeError}; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum PrefixError { + #[error( + "Invalid PREFIX_ADDRESS, unexpected payload length: {payload_length}" + )] + InvalidPrefixAddress { payload_length: usize }, + + #[error("Invalid PREFIX_CACHEINFO: {0:?}")] + InvalidPrefixCacheInfo(DecodeError), + + #[error(transparent)] + ParseNla(#[from] NlaError), + + #[error(transparent)] + Other(#[from] DecodeError), +} diff --git a/src/prefix/header.rs b/src/prefix/header.rs index aead250f..9faa4076 100644 --- a/src/prefix/header.rs +++ b/src/prefix/header.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT use netlink_packet_utils::{ - nla::{NlaBuffer, NlasIterator}, + nla::{NlaBuffer, NlaError, NlasIterator}, DecodeError, Emitable, }; @@ -22,7 +22,7 @@ buffer!(PrefixMessageBuffer(PREFIX_HEADER_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> PrefixMessageBuffer<&'a T> { pub fn nlas( &self, - ) -> impl Iterator, DecodeError>> { + ) -> impl Iterator, NlaError>> { NlasIterator::new(self.payload()) } } diff --git a/src/prefix/message.rs b/src/prefix/message.rs index d27ce1f4..05c3fa47 100644 --- a/src/prefix/message.rs +++ b/src/prefix/message.rs @@ -1,16 +1,11 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; - -use netlink_packet_utils::{ - traits::{Emitable, Parseable}, - DecodeError, -}; - use super::{ attribute::PrefixAttribute, + error::PrefixError, header::{PrefixHeader, PrefixMessageBuffer}, }; +use netlink_packet_utils::traits::{Emitable, Parseable}; #[derive(Debug, PartialEq, Eq, Clone, Default)] pub struct PrefixMessage { @@ -32,8 +27,8 @@ impl Emitable for PrefixMessage { } impl> Parseable> for PrefixHeader { - type Error = DecodeError; - fn parse(buf: &PrefixMessageBuffer) -> Result { + type Error = (); + fn parse(buf: &PrefixMessageBuffer) -> Result { Ok(Self { prefix_family: buf.prefix_family(), ifindex: buf.ifindex(), @@ -47,13 +42,12 @@ impl> Parseable> for PrefixHeader { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for PrefixMessage { - type Error = DecodeError; - fn parse(buf: &PrefixMessageBuffer<&'a T>) -> Result { + type Error = PrefixError; + fn parse(buf: &PrefixMessageBuffer<&'a T>) -> Result { Ok(Self { - header: PrefixHeader::parse(buf) - .context("failed to parse prefix message header")?, - attributes: Vec::::parse(buf) - .context("failed to parse prefix message attributes")?, + // Unwrap: ok, we never return an error above. + header: PrefixHeader::parse(buf).unwrap(), + attributes: Vec::::parse(buf)?, }) } } @@ -61,8 +55,8 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { - type Error = DecodeError; - fn parse(buf: &PrefixMessageBuffer<&'a T>) -> Result { + type Error = PrefixError; + fn parse(buf: &PrefixMessageBuffer<&'a T>) -> Result { let mut nlas = vec![]; for nla_buf in buf.nlas() { nlas.push(PrefixAttribute::parse(&nla_buf?)?); diff --git a/src/prefix/mod.rs b/src/prefix/mod.rs index be4fc1dd..c3c6e3b5 100644 --- a/src/prefix/mod.rs +++ b/src/prefix/mod.rs @@ -2,10 +2,12 @@ mod attribute; mod cache_info; +mod error; mod header; mod message; #[cfg(test)] mod tests; +pub use error::PrefixError; pub use header::PrefixMessageBuffer; pub use message::PrefixMessage; diff --git a/src/route/attribute.rs b/src/route/attribute.rs index 17b40b94..d4b09642 100644 --- a/src/route/attribute.rs +++ b/src/route/attribute.rs @@ -1,21 +1,18 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::{ + super::AddressFamily, lwtunnel::VecRouteLwTunnelEncap, + metrics::VecRouteMetric, mpls::VecMplsLabel, MplsLabel, RouteAddress, + RouteCacheInfo, RouteCacheInfoBuffer, RouteError, RouteLwEnCapType, + RouteLwTunnelEncap, RouteMetric, RouteMfcStats, RouteMfcStatsBuffer, + RouteMplsTtlPropagation, RouteNextHop, RouteNextHopBuffer, RoutePreference, + RouteRealm, RouteType, RouteVia, RouteViaBuffer, +}; use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer}, parsers::{parse_u16, parse_u32, parse_u64, parse_u8}, traits::{Emitable, Parseable, ParseableParametrized}, - DecodeError, -}; - -use super::{ - super::AddressFamily, lwtunnel::VecRouteLwTunnelEncap, - metrics::VecRouteMetric, mpls::VecMplsLabel, MplsLabel, RouteAddress, - RouteCacheInfo, RouteCacheInfoBuffer, RouteLwEnCapType, RouteLwTunnelEncap, - RouteMetric, RouteMfcStats, RouteMfcStatsBuffer, RouteMplsTtlPropagation, - RouteNextHop, RouteNextHopBuffer, RoutePreference, RouteRealm, RouteType, - RouteVia, RouteViaBuffer, }; const RTA_DST: u16 = 1; @@ -194,7 +191,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> (AddressFamily, RouteType, RouteLwEnCapType), > for RouteAttribute { - type Error = DecodeError; + type Error = RouteError; fn parse_with_param( buf: &NlaBuffer<&'a T>, (address_family, route_type, encap_type): ( @@ -202,117 +199,184 @@ impl<'a, T: AsRef<[u8]> + ?Sized> RouteType, RouteLwEnCapType, ), - ) -> Result { + ) -> Result { let payload = buf.value(); Ok(match buf.kind() { - RTA_DST => { - Self::Destination(RouteAddress::parse(address_family, payload)?) - } - RTA_SRC => { - Self::Source(RouteAddress::parse(address_family, payload)?) - } - RTA_GATEWAY => { - Self::Gateway(RouteAddress::parse(address_family, payload)?) - } - RTA_PREFSRC => { - Self::PrefSource(RouteAddress::parse(address_family, payload)?) - } + RTA_DST => Self::Destination( + RouteAddress::parse(address_family, payload).map_err( + |error| RouteError::InvalidValue { + kind: "RTA_DST", + error, + }, + )?, + ), + RTA_SRC => Self::Source( + RouteAddress::parse(address_family, payload).map_err( + |error| RouteError::InvalidValue { + kind: "RTA_SRC", + error, + }, + )?, + ), + RTA_GATEWAY => Self::Gateway( + RouteAddress::parse(address_family, payload).map_err( + |error| RouteError::InvalidValue { + kind: "RTA_GATEWAY", + error, + }, + )?, + ), + RTA_PREFSRC => Self::PrefSource( + RouteAddress::parse(address_family, payload).map_err( + |error| RouteError::InvalidValue { + kind: "RTA_PREFSRC", + error, + }, + )?, + ), RTA_VIA => Self::Via( RouteVia::parse( - &RouteViaBuffer::new_checked(payload).context(format!( - "Invalid RTA_VIA value {:?}", - payload - ))?, + &RouteViaBuffer::new_checked(payload).map_err(|error| { + RouteError::InvalidValue { + kind: "RTA_VIA", + error, + } + })?, ) - .context(format!("Invalid RTA_VIA value {:?}", payload))?, - ), - RTA_NEWDST => Self::NewDestination( - VecMplsLabel::parse(payload) - .context(format!("Invalid RTA_NEWDST value {:?}", payload))? - .0, + .map_err(|error| RouteError::InvalidValue { + kind: "RTA_VIA", + error, + })?, ), + RTA_NEWDST => Self::NewDestination(VecMplsLabel::parse(payload)?.0), - RTA_PREF => Self::Preference(parse_u8(payload)?.into()), + RTA_PREF => Self::Preference( + parse_u8(payload) + .map_err(|error| RouteError::InvalidValue { + kind: "RTA_PREF", + error, + })? + .into(), + ), RTA_ENCAP => Self::Encap( VecRouteLwTunnelEncap::parse_with_param(buf, encap_type)?.0, ), RTA_EXPIRES => { if route_type == RouteType::Multicast { - Self::MulticastExpires(parse_u64(payload).context( - format!( - "invalid RTA_EXPIRES (multicast) value {:?}", - payload - ), + Self::MulticastExpires(parse_u64(payload).map_err( + |error| RouteError::InvalidValue { + kind: "RTA_EXPIRES (multicast)", + error, + }, )?) } else { - Self::Expires(parse_u32(payload).context(format!( - "invalid RTA_EXPIRES value {:?}", - payload - ))?) + Self::Expires(parse_u32(payload).map_err(|error| { + RouteError::InvalidValue { + kind: "RTA_EXPIRES", + error, + } + })?) } } - RTA_UID => Self::Uid( - parse_u32(payload) - .context(format!("invalid RTA_UID value {:?}", payload))?, - ), + RTA_UID => Self::Uid(parse_u32(payload).map_err(|error| { + RouteError::InvalidValue { + kind: "RTA_UID", + error, + } + })?), RTA_TTL_PROPAGATE => Self::TtlPropagate( - RouteMplsTtlPropagation::from(parse_u8(payload).context( - format!("invalid RTA_TTL_PROPAGATE {:?}", payload), + RouteMplsTtlPropagation::from(parse_u8(payload).map_err( + |error| RouteError::InvalidValue { + kind: "RTA_TTL_PROPAGATE", + error, + }, )?), ), RTA_ENCAP_TYPE => Self::EncapType(RouteLwEnCapType::from( - parse_u16(payload).context("invalid RTA_ENCAP_TYPE value")?, + parse_u16(payload).map_err(|error| { + RouteError::InvalidValue { + kind: "RTA_ENCAP_TYPE", + error, + } + })?, )), - RTA_IIF => { - Self::Iif(parse_u32(payload).context("invalid RTA_IIF value")?) - } - RTA_OIF => { - Self::Oif(parse_u32(payload).context("invalid RTA_OIF value")?) + RTA_IIF => Self::Iif(parse_u32(payload).map_err(|error| { + RouteError::InvalidValue { + kind: "RTA_IIF", + error, + } + })?), + RTA_OIF => Self::Oif(parse_u32(payload).map_err(|error| { + RouteError::InvalidValue { + kind: "RTA_OIF", + error, + } + })?), + RTA_PRIORITY => { + Self::Priority(parse_u32(payload).map_err(|error| { + RouteError::InvalidValue { + kind: "RTA_PRIORITY", + error, + } + })?) } - RTA_PRIORITY => Self::Priority( - parse_u32(payload).context("invalid RTA_PRIORITY value")?, - ), - RTA_FLOW => Self::Realm( - RouteRealm::parse(payload).context("invalid RTA_FLOW value")?, - ), - RTA_TABLE => Self::Table( - parse_u32(payload).context("invalid RTA_TABLE value")?, - ), - RTA_MARK => Self::Mark( - parse_u32(payload).context("invalid RTA_MARK value")?, - ), + RTA_FLOW => Self::Realm(RouteRealm::parse(payload)?), + RTA_TABLE => Self::Table(parse_u32(payload).map_err(|error| { + RouteError::InvalidValue { + kind: "RTA_TABLE", + error, + } + })?), + RTA_MARK => Self::Mark(parse_u32(payload).map_err(|error| { + RouteError::InvalidValue { + kind: "RTA_MARK", + error, + } + })?), RTA_CACHEINFO => Self::CacheInfo( RouteCacheInfo::parse( - &RouteCacheInfoBuffer::new_checked(payload) - .context("invalid RTA_CACHEINFO value")?, + &RouteCacheInfoBuffer::new_checked(payload).map_err( + |error| RouteError::InvalidValue { + kind: "RTA_CACHEINFO", + error, + }, + )?, ) - .context("invalid RTA_CACHEINFO value")?, + .map_err(|error| RouteError::InvalidValue { + kind: "RTA_CACHEINFO", + error, + })?, ), RTA_MFC_STATS => Self::MfcStats( RouteMfcStats::parse( - &RouteMfcStatsBuffer::new_checked(payload) - .context("invalid RTA_MFC_STATS value")?, + &RouteMfcStatsBuffer::new_checked(payload).map_err( + |error| RouteError::InvalidValue { + kind: "RTA_MFC_STATS", + error, + }, + )?, ) - .context("invalid RTA_MFC_STATS value")?, - ), - RTA_METRICS => Self::Metrics( - VecRouteMetric::parse(payload) - .context("invalid RTA_METRICS value")? - .0, + .map_err(|error| RouteError::InvalidValue { + kind: "RTA_MFC_STATS", + error, + })?, ), + RTA_METRICS => Self::Metrics(VecRouteMetric::parse(payload)?.0), RTA_MULTIPATH => { let mut next_hops = vec![]; let mut buf = payload; loop { let nh_buf = RouteNextHopBuffer::new_checked(&buf) - .context("invalid RTA_MULTIPATH value")?; + .map_err(|error| RouteError::InvalidValue { + kind: "RTA_MULTIPATH", + error, + })?; let len = nh_buf.length() as usize; let nh = RouteNextHop::parse_with_param( &nh_buf, (address_family, route_type, encap_type), - ) - .context("invalid RTA_MULTIPATH value")?; + )?; next_hops.push(nh); if buf.len() == len { break; @@ -321,9 +385,12 @@ impl<'a, T: AsRef<[u8]> + ?Sized> } Self::MultiPath(next_hops) } - _ => Self::Other( - DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, - ), + _ => Self::Other(DefaultNla::parse(buf).map_err(|error| { + RouteError::InvalidValue { + kind: "NLA (uknown kind)", + error, + } + })?), }) } } diff --git a/src/route/error.rs b/src/route/error.rs new file mode 100644 index 00000000..0bdcf3a0 --- /dev/null +++ b/src/route/error.rs @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +use super::RouteLwEnCapType; +use netlink_packet_utils::{nla::NlaError, DecodeError}; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum RouteError { + #[error("Invalid {kind} value")] + InvalidValue { + kind: &'static str, + #[source] + error: DecodeError, + }, + + #[error("cannot parse route attributes in next-hop")] + ParseNextHopAttributes(#[source] DecodeError), + + #[error("Invalid RTA_ENCAP for kind: {kind}")] + InvalidRtaEncap { + kind: RouteLwEnCapType, + error: NlaError, + }, + + #[error("invalid MPLS_IPTUNNEL_DST value")] + InvalidMplsIpTunnelTtl(#[source] DecodeError), + + #[error("Invalid {kind} value")] + InvalidRouteMetric { + kind: &'static str, + #[source] + error: DecodeError, + }, + + #[error("Invalid array length. Expected={expected}, got={got}")] + ParseMplsLabel { expected: usize, got: usize }, + + #[error("Expected single u8 for route protocol")] + ParseRouteProtocol, + + #[error("Invalid rule port range data, expecting {expected} u8 array, but got {got}")] + InvalidRulePortRange { expected: usize, got: usize }, + + #[error(transparent)] + ParseNla(#[from] NlaError), + + #[error(transparent)] + Other(#[from] DecodeError), +} diff --git a/src/route/header.rs b/src/route/header.rs index e9ee4c94..ca419d92 100644 --- a/src/route/header.rs +++ b/src/route/header.rs @@ -1,13 +1,12 @@ // SPDX-License-Identifier: MIT +use super::{super::AddressFamily, flags::RouteFlags, RouteError}; use netlink_packet_utils::{ - nla::{NlaBuffer, NlasIterator}, + nla::{NlaBuffer, NlaError, NlasIterator}, traits::{Emitable, Parseable}, DecodeError, }; -use super::{super::AddressFamily, flags::RouteFlags}; - const ROUTE_HEADER_LEN: usize = 12; buffer!(RouteMessageBuffer(ROUTE_HEADER_LEN) { @@ -26,7 +25,7 @@ buffer!(RouteMessageBuffer(ROUTE_HEADER_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> RouteMessageBuffer<&'a T> { pub fn attributes( &self, - ) -> impl Iterator, DecodeError>> { + ) -> impl Iterator, NlaError>> { NlasIterator::new(self.payload()) } } @@ -64,8 +63,8 @@ impl RouteHeader { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RouteHeader { - type Error = DecodeError; - fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result { + type Error = (); + fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result { Ok(RouteHeader { address_family: buf.address_family().into(), destination_prefix_length: buf.destination_prefix_length(), @@ -247,15 +246,12 @@ impl Default for RouteProtocol { } impl Parseable<[u8]> for RouteProtocol { - type Error = DecodeError; - fn parse(buf: &[u8]) -> Result { + type Error = RouteError; + fn parse(buf: &[u8]) -> Result { if buf.len() == 1 { Ok(Self::from(buf[0])) } else { - Err(DecodeError::from(format!( - "Expecting single u8 for route protocol, but got {:?}", - buf - ))) + Err(RouteError::ParseRouteProtocol) } } } diff --git a/src/route/lwtunnel.rs b/src/route/lwtunnel.rs index 282ee0c0..93656380 100644 --- a/src/route/lwtunnel.rs +++ b/src/route/lwtunnel.rs @@ -1,14 +1,11 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::{RouteError, RouteMplsIpTunnel}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, traits::{Emitable, Parseable, ParseableParametrized}, - DecodeError, }; -use super::RouteMplsIpTunnel; - const LWTUNNEL_ENCAP_NONE: u16 = 0; const LWTUNNEL_ENCAP_MPLS: u16 = 1; const LWTUNNEL_ENCAP_IP: u16 = 2; @@ -141,11 +138,11 @@ impl<'a, T> ParseableParametrized, RouteLwEnCapType> where T: AsRef<[u8]> + ?Sized, { - type Error = DecodeError; + type Error = RouteError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: RouteLwEnCapType, - ) -> Result { + ) -> Result { Ok(match kind { RouteLwEnCapType::Mpls => { Self::Mpls(RouteMplsIpTunnel::parse(buf)?) @@ -164,18 +161,16 @@ impl<'a, T> ParseableParametrized, RouteLwEnCapType> where T: AsRef<[u8]> + ?Sized, { - type Error = DecodeError; + type Error = RouteError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: RouteLwEnCapType, - ) -> Result { + ) -> Result { let mut ret = Vec::new(); for nla in NlasIterator::new(buf.value()) { - let nla = - nla.context(format!("Invalid RTA_ENCAP for kind: {kind}"))?; - ret.push(RouteLwTunnelEncap::parse_with_param(&nla, kind).context( - format!("Failed to parse RTA_ENCAP for kind: {kind}",), - )?) + let nla = nla + .map_err(|error| RouteError::InvalidRtaEncap { error, kind })?; + ret.push(RouteLwTunnelEncap::parse_with_param(&nla, kind)?); } Ok(Self(ret)) } diff --git a/src/route/message.rs b/src/route/message.rs index e662c6ef..5687c99b 100644 --- a/src/route/message.rs +++ b/src/route/message.rs @@ -1,14 +1,12 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; -use netlink_packet_utils::{ - traits::{Emitable, Parseable, ParseableParametrized}, - DecodeError, -}; - use super::{ - super::AddressFamily, attribute::RTA_ENCAP_TYPE, RouteAttribute, - RouteHeader, RouteLwEnCapType, RouteMessageBuffer, RouteType, + super::AddressFamily, attribute::RTA_ENCAP_TYPE, error::RouteError, + RouteAttribute, RouteHeader, RouteLwEnCapType, RouteMessageBuffer, + RouteType, +}; +use netlink_packet_utils::traits::{ + Emitable, Parseable, ParseableParametrized, }; #[derive(Debug, PartialEq, Eq, Clone, Default)] @@ -34,10 +32,10 @@ impl Emitable for RouteMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for RouteMessage { - type Error = DecodeError; - fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result { - let header = RouteHeader::parse(buf) - .context("failed to parse route message header")?; + type Error = RouteError; + fn parse(buf: &RouteMessageBuffer<&'a T>) -> Result { + // unwrap: RouteHeader can't fail. + let header = RouteHeader::parse(buf).unwrap(); let address_family = header.address_family; let route_type = header.kind; Ok(RouteMessage { @@ -45,8 +43,7 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> attributes: Vec::::parse_with_param( buf, (address_family, route_type), - ) - .context("failed to parse route message NLAs")?, + )?, }) } } @@ -55,11 +52,11 @@ impl<'a, T: AsRef<[u8]> + 'a> ParseableParametrized, (AddressFamily, RouteType)> for Vec { - type Error = DecodeError; + type Error = RouteError; fn parse_with_param( buf: &RouteMessageBuffer<&'a T>, (address_family, route_type): (AddressFamily, RouteType), - ) -> Result { + ) -> Result { let mut attributes = vec![]; let mut encap_type = RouteLwEnCapType::None; // The RTA_ENCAP_TYPE is provided __after__ RTA_ENCAP, we should find diff --git a/src/route/metrics.rs b/src/route/metrics.rs index 5a9f5266..a3b0c9b0 100644 --- a/src/route/metrics.rs +++ b/src/route/metrics.rs @@ -1,15 +1,13 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::error::RouteError; use byteorder::{ByteOrder, NativeEndian}; -use std::mem::size_of; - use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::parse_u32, traits::Parseable, - DecodeError, }; +use std::mem::size_of; const RTAX_LOCK: u16 = 1; const RTAX_MTU: u16 = 2; @@ -127,66 +125,144 @@ impl Nla for RouteMetric { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RouteMetric { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = RouteError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { - RTAX_LOCK => Self::Lock( - parse_u32(payload).context("invalid RTAX_LOCK value")?, - ), - RTAX_MTU => { - Self::Mtu(parse_u32(payload).context("invalid RTAX_MTU value")?) + RTAX_LOCK => Self::Lock(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_LOCK", + error, + } + })?), + RTAX_MTU => Self::Mtu(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_MTU", + error, + } + })?), + RTAX_WINDOW => { + Self::Window(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_WINDOW", + error, + } + })?) + } + RTAX_RTT => Self::Rtt(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_RTT", + error, + } + })?), + RTAX_RTTVAR => { + Self::RttVar(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_RTTVAR", + error, + } + })?) + } + RTAX_SSTHRESH => { + Self::SsThresh(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_SSHTHRESH", + error, + } + })?) + } + RTAX_CWND => Self::Cwnd(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_CWND", + error, + } + })?), + RTAX_ADVMSS => { + Self::Advmss(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_ADVMSS", + error, + } + })?) + } + RTAX_REORDERING => { + Self::Reordering(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_REORDERING", + error, + } + })?) + } + RTAX_HOPLIMIT => { + Self::Hoplimit(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_HOPLIMIT", + error, + } + })?) + } + RTAX_INITCWND => { + Self::InitCwnd(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_INITCWND", + error, + } + })?) + } + RTAX_FEATURES => { + Self::Features(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_FEATURES", + error, + } + })?) + } + RTAX_RTO_MIN => { + Self::RtoMin(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_RTO_MIN", + error, + } + })?) + } + RTAX_INITRWND => { + Self::InitRwnd(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_INITRWND", + error, + } + })?) + } + RTAX_QUICKACK => { + Self::QuickAck(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_QUICKACK", + error, + } + })?) + } + RTAX_CC_ALGO => { + Self::CcAlgo(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_CC_ALGO", + error, + } + })?) } - RTAX_WINDOW => Self::Window( - parse_u32(payload).context("invalid RTAX_WINDOW value")?, - ), - RTAX_RTT => { - Self::Rtt(parse_u32(payload).context("invalid RTAX_RTT value")?) + RTAX_FASTOPEN_NO_COOKIE => { + Self::FastopenNoCookie(parse_u32(payload).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "RTAX_FASTOPEN_NO_COOKIE", + error, + } + })?) } - RTAX_RTTVAR => Self::RttVar( - parse_u32(payload).context("invalid RTAX_RTTVAR value")?, - ), - RTAX_SSTHRESH => Self::SsThresh( - parse_u32(payload).context("invalid RTAX_SSTHRESH value")?, - ), - RTAX_CWND => Self::Cwnd( - parse_u32(payload).context("invalid RTAX_CWND value")?, - ), - RTAX_ADVMSS => Self::Advmss( - parse_u32(payload).context("invalid RTAX_ADVMSS value")?, - ), - RTAX_REORDERING => Self::Reordering( - parse_u32(payload).context("invalid RTAX_REORDERING value")?, - ), - RTAX_HOPLIMIT => Self::Hoplimit( - parse_u32(payload).context("invalid RTAX_HOPLIMIT value")?, - ), - RTAX_INITCWND => Self::InitCwnd( - parse_u32(payload).context("invalid RTAX_INITCWND value")?, - ), - RTAX_FEATURES => Self::Features( - parse_u32(payload).context("invalid RTAX_FEATURES value")?, - ), - RTAX_RTO_MIN => Self::RtoMin( - parse_u32(payload).context("invalid RTAX_RTO_MIN value")?, - ), - RTAX_INITRWND => Self::InitRwnd( - parse_u32(payload).context("invalid RTAX_INITRWND value")?, - ), - RTAX_QUICKACK => Self::QuickAck( - parse_u32(payload).context("invalid RTAX_QUICKACK value")?, - ), - RTAX_CC_ALGO => Self::CcAlgo( - parse_u32(payload).context("invalid RTAX_CC_ALGO value")?, - ), - RTAX_FASTOPEN_NO_COOKIE => Self::FastopenNoCookie( - parse_u32(payload) - .context("invalid RTAX_FASTOPEN_NO_COOKIE value")?, - ), - _ => Self::Other( - DefaultNla::parse(buf) - .context("invalid NLA value (unknown type) value")?, - ), + _ => Self::Other(DefaultNla::parse(buf).map_err(|error| { + RouteError::InvalidRouteMetric { + kind: "NLA unkwnon", + error, + } + })?), }) } } @@ -194,12 +270,11 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RouteMetric { pub(crate) struct VecRouteMetric(pub(crate) Vec); impl + ?Sized> Parseable for VecRouteMetric { - type Error = DecodeError; - fn parse(payload: &T) -> Result { + type Error = RouteError; + fn parse(payload: &T) -> Result { let mut nlas = vec![]; for nla in NlasIterator::new(payload) { - let nla = nla.context("Invalid RTA_METRICS")?; - nlas.push(RouteMetric::parse(&nla).context("Invalid RTA_METRICS")?); + nlas.push(RouteMetric::parse(&nla?)?); } Ok(Self(nlas)) } diff --git a/src/route/mod.rs b/src/route/mod.rs index 497172db..e72f0f22 100644 --- a/src/route/mod.rs +++ b/src/route/mod.rs @@ -3,6 +3,7 @@ mod address; mod attribute; mod cache_info; +mod error; mod flags; mod header; mod lwtunnel; @@ -21,6 +22,7 @@ mod tests; pub use self::address::RouteAddress; pub use self::attribute::RouteAttribute; pub use self::cache_info::{RouteCacheInfo, RouteCacheInfoBuffer}; +pub use self::error::RouteError; pub use self::header::{ RouteHeader, RouteMessageBuffer, RouteProtocol, RouteScope, RouteType, }; diff --git a/src/route/mpls.rs b/src/route/mpls.rs index 0fc1a476..f5c9c094 100644 --- a/src/route/mpls.rs +++ b/src/route/mpls.rs @@ -1,11 +1,10 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::error::RouteError; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer}, parsers::parse_u8, traits::{Emitable, Parseable}, - DecodeError, }; const MPLS_IPTUNNEL_DST: u16 = 1; @@ -50,24 +49,20 @@ impl Nla for RouteMplsIpTunnel { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RouteMplsIpTunnel { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = RouteError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { - MPLS_IPTUNNEL_DST => Self::Destination( - VecMplsLabel::parse(payload) - .context(format!( - "invalid MPLS_IPTUNNEL_DST value {:?}", - payload - ))? - .0, - ), + MPLS_IPTUNNEL_DST => { + Self::Destination(VecMplsLabel::parse(payload)?.0) + } MPLS_IPTUNNEL_TTL => Self::Ttl( - parse_u8(payload).context("invalid MPLS_IPTUNNEL_TTL value")?, + parse_u8(payload) + .map_err(RouteError::InvalidMplsIpTunnelTtl)?, ), _ => Self::Other( DefaultNla::parse(buf) - .context("invalid NLA value (unknown type) value")?, + .map_err(RouteError::InvalidMplsIpTunnelTtl)?, ), }) } @@ -96,18 +91,16 @@ pub struct MplsLabel { } impl MplsLabel { - pub(crate) fn parse(payload: &[u8]) -> Result { + pub(crate) fn parse(payload: &[u8]) -> Result { if payload.len() == 4 { Ok(Self::from(u32::from_be_bytes([ payload[0], payload[1], payload[2], payload[3], ]))) } else { - Err(DecodeError::from(format!( - "Invalid u8 array length {}, expecting \ - 4 bytes for MPLS label, got {:?}", - payload.len(), - payload, - ))) + Err(RouteError::ParseMplsLabel { + expected: 4, + got: payload.len(), + }) } } } @@ -149,7 +142,7 @@ impl From for u32 { pub(crate) struct VecMplsLabel(pub(crate) Vec); impl VecMplsLabel { - pub(crate) fn parse(payload: &[u8]) -> Result { + pub(crate) fn parse(payload: &[u8]) -> Result { let mut labels = vec![]; let mut i: usize = 0; while i + 4 <= payload.len() { diff --git a/src/route/next_hops.rs b/src/route/next_hops.rs index 65499f49..71f93634 100644 --- a/src/route/next_hops.rs +++ b/src/route/next_hops.rs @@ -1,16 +1,15 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::{ + super::AddressFamily, RouteAttribute, RouteError, RouteLwEnCapType, + RouteType, +}; use netlink_packet_utils::{ - nla::{NlaBuffer, NlasIterator}, + nla::{NlaBuffer, NlaError, NlasIterator}, traits::{Emitable, ParseableParametrized}, DecodeError, }; -use super::{ - super::AddressFamily, RouteAttribute, RouteLwEnCapType, RouteType, -}; - pub(crate) const RTNH_F_DEAD: u8 = 1; pub(crate) const RTNH_F_PERVASIVE: u8 = 2; pub(crate) const RTNH_F_ONLINK: u8 = 4; @@ -54,18 +53,18 @@ impl> RouteNextHopBuffer { fn check_buffer_length(&self) -> Result<(), DecodeError> { let len = self.buffer.as_ref().len(); if len < PAYLOAD_OFFSET { - return Err(format!( - "invalid RouteNextHopBuffer: length {len} < {PAYLOAD_OFFSET}" - ) - .into()); + return Err(DecodeError::InvalidBufferLength { + name: "RouteNextHopBuffer", + len, + buffer_len: PAYLOAD_OFFSET, + }); } if len < self.length() as usize { - return Err(format!( - "invalid RouteNextHopBuffer: length {} < {}", + return Err(DecodeError::InvalidBufferLength { + name: "RouteNextHopBuffer", len, - 8 + self.length() - ) - .into()); + buffer_len: (8 + self.length()) as usize, + }); } Ok(()) } @@ -74,7 +73,7 @@ impl> RouteNextHopBuffer { impl<'a, T: AsRef<[u8]> + ?Sized> RouteNextHopBuffer<&'a T> { pub fn attributes( &self, - ) -> impl Iterator, DecodeError>> { + ) -> impl Iterator, NlaError>> { NlasIterator::new( &self.payload()[..(self.length() as usize - PAYLOAD_OFFSET)], ) @@ -100,7 +99,7 @@ impl<'a, T: AsRef<[u8]>> (AddressFamily, RouteType, RouteLwEnCapType), > for RouteNextHop { - type Error = DecodeError; + type Error = RouteError; fn parse_with_param( buf: &RouteNextHopBuffer<&T>, (address_family, route_type, encap_type): ( @@ -108,13 +107,11 @@ impl<'a, T: AsRef<[u8]>> RouteType, RouteLwEnCapType, ), - ) -> Result { + ) -> Result { let attributes = Vec::::parse_with_param( - &RouteNextHopBuffer::new_checked(buf.buffer) - .context("cannot parse route attributes in next-hop")?, + &RouteNextHopBuffer::new_checked(buf.buffer)?, (address_family, route_type, encap_type), - ) - .context("cannot parse route attributes in next-hop")?; + )?; Ok(RouteNextHop { flags: RouteNextHopFlags::from_bits_retain(buf.flags()), hops: buf.hops(), @@ -130,7 +127,7 @@ impl<'a, T: AsRef<[u8]> + 'a> (AddressFamily, RouteType, RouteLwEnCapType), > for Vec { - type Error = DecodeError; + type Error = RouteError; fn parse_with_param( buf: &RouteNextHopBuffer<&'a T>, (address_family, route_type, encap_type): ( @@ -138,7 +135,7 @@ impl<'a, T: AsRef<[u8]> + 'a> RouteType, RouteLwEnCapType, ), - ) -> Result { + ) -> Result { let mut nlas = vec![]; for nla_buf in buf.attributes() { nlas.push(RouteAttribute::parse_with_param( diff --git a/src/route/realm.rs b/src/route/realm.rs index 8b395ff5..7d743683 100644 --- a/src/route/realm.rs +++ b/src/route/realm.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT -use netlink_packet_utils::{DecodeError, Emitable}; +use super::RouteError; +use netlink_packet_utils::Emitable; const RULE_REALM_LEN: usize = 4; @@ -11,7 +12,7 @@ pub struct RouteRealm { } impl RouteRealm { - pub(crate) fn parse(buf: &[u8]) -> Result { + pub(crate) fn parse(buf: &[u8]) -> Result { let all = u32::from_ne_bytes([buf[0], buf[1], buf[2], buf[3]]); if buf.len() == RULE_REALM_LEN { Ok(Self { @@ -19,11 +20,10 @@ impl RouteRealm { destination: (all & 0xFFFF) as u16, }) } else { - Err(DecodeError::from(format!( - "Invalid rule port range data, expecting \ - {RULE_REALM_LEN} u8 array, but got {:?}", - buf - ))) + Err(RouteError::InvalidRulePortRange { + expected: RULE_REALM_LEN, + got: buf.len(), + }) } } } diff --git a/src/rule/attribute.rs b/src/rule/attribute.rs index 1cc60983..164ad14f 100644 --- a/src/rule/attribute.rs +++ b/src/rule/attribute.rs @@ -1,20 +1,17 @@ // SPDX-License-Identifier: MIT -use std::net::IpAddr; - -use anyhow::Context; +use crate::{ + ip::{emit_ip_addr, ip_addr_len, parse_ip_addr, IpProtocol}, + route::{RouteProtocol, RouteRealm}, + rule::{RuleError, RulePortRange, RuleUidRange}, +}; use netlink_packet_utils::{ byteorder::{ByteOrder, NativeEndian}, nla::{DefaultNla, Nla, NlaBuffer}, parsers::{parse_string, parse_u32, parse_u8}, - DecodeError, Emitable, Parseable, -}; - -use crate::{ - ip::{emit_ip_addr, ip_addr_len, parse_ip_addr, IpProtocol}, - route::{RouteProtocol, RouteRealm}, - rule::{RulePortRange, RuleUidRange}, + Emitable, Parseable, }; +use std::net::IpAddr; const FRA_DST: u16 = 1; const FRA_SRC: u16 = 2; @@ -152,79 +149,132 @@ impl Nla for RuleAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RuleAttribute { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = RuleError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { - FRA_DST => Self::Destination( - parse_ip_addr(payload) - .context(format!("Invalid FRA_DST value {payload:?}"))?, - ), - FRA_SRC => Self::Source( - parse_ip_addr(payload) - .context(format!("Invalid FRA_SRC value {payload:?}"))?, - ), - FRA_IIFNAME => Self::Iifname( - parse_string(payload).context("invalid FRA_IIFNAME value")?, - ), - FRA_GOTO => Self::Goto( - parse_u32(payload).context("invalid FRA_GOTO value")?, - ), - FRA_PRIORITY => Self::Priority( - parse_u32(payload).context("invalid FRA_PRIORITY value")?, - ), - FRA_FWMARK => Self::FwMark( - parse_u32(payload).context("invalid FRA_FWMARK value")?, - ), - FRA_FLOW => Self::Realm( - RouteRealm::parse(payload).context("invalid FRA_FLOW value")?, - ), - FRA_TUN_ID => Self::TunId( - parse_u32(payload).context("invalid FRA_TUN_ID value")?, - ), - FRA_SUPPRESS_IFGROUP => Self::SuppressIfGroup( - parse_u32(payload) - .context("invalid FRA_SUPPRESS_IFGROUP value")?, - ), - FRA_SUPPRESS_PREFIXLEN => Self::SuppressPrefixLen( - parse_u32(payload) - .context("invalid FRA_SUPPRESS_PREFIXLEN value")?, - ), - FRA_TABLE => Self::Table( - parse_u32(payload).context("invalid FRA_TABLE value")?, - ), - FRA_FWMASK => Self::FwMask( - parse_u32(payload).context("invalid FRA_FWMASK value")?, - ), - FRA_OIFNAME => Self::Oifname( - parse_string(payload).context("invalid FRA_OIFNAME value")?, - ), + FRA_DST => { + Self::Destination(parse_ip_addr(payload).map_err(|error| { + RuleError::InvalidValue { + kind: "FRA_DST", + error, + } + })?) + } + FRA_SRC => { + Self::Source(parse_ip_addr(payload).map_err(|error| { + RuleError::InvalidValue { + kind: "FRA_DST", + error, + } + })?) + } + FRA_IIFNAME => { + Self::Iifname(parse_string(payload).map_err(|error| { + RuleError::InvalidValue { + kind: "FRA_IIFNAME", + error, + } + })?) + } + FRA_GOTO => Self::Goto(parse_u32(payload).map_err(|error| { + RuleError::InvalidValue { + kind: "FRA_GOTO", + error, + } + })?), + FRA_PRIORITY => { + Self::Priority(parse_u32(payload).map_err(|error| { + RuleError::InvalidValue { + kind: "FRA_PRIORITY", + error, + } + })?) + } + FRA_FWMARK => { + Self::FwMark(parse_u32(payload).map_err(|error| { + RuleError::InvalidValue { + kind: "FRA_FWMARK", + error, + } + })?) + } + FRA_FLOW => Self::Realm(RouteRealm::parse(payload)?), + FRA_TUN_ID => Self::TunId(parse_u32(payload).map_err(|error| { + RuleError::InvalidValue { + kind: "FRA_TUN_ID", + error, + } + })?), + FRA_SUPPRESS_IFGROUP => { + Self::SuppressIfGroup(parse_u32(payload).map_err(|error| { + RuleError::InvalidValue { + kind: "FRA_SUPPRESS_IFGROUP", + error, + } + })?) + } + FRA_SUPPRESS_PREFIXLEN => { + Self::SuppressPrefixLen(parse_u32(payload).map_err( + |error| RuleError::InvalidValue { + kind: "FRA_SUPPRESS_PREFIXLEN", + error, + }, + )?) + } + FRA_TABLE => Self::Table(parse_u32(payload).map_err(|error| { + RuleError::InvalidValue { + kind: "FRA_TABLE", + error, + } + })?), + FRA_FWMASK => { + Self::FwMask(parse_u32(payload).map_err(|error| { + RuleError::InvalidValue { + kind: "FRA_FWMASK", + error, + } + })?) + } + FRA_OIFNAME => { + Self::Oifname(parse_string(payload).map_err(|error| { + RuleError::InvalidValue { + kind: "FRA_OIFNAME", + error, + } + })?) + } FRA_L3MDEV => Self::L3MDev( - parse_u8(payload).context("invalid FRA_L3MDEV value")? > 0, - ), - FRA_UID_RANGE => Self::UidRange( - RuleUidRange::parse(payload) - .context("invalid FRA_UID_RANGE value")?, + parse_u8(payload).map_err(|error| RuleError::InvalidValue { + kind: "FRA_L3MDEV", + error, + })? > 0, ), + FRA_UID_RANGE => Self::UidRange(RuleUidRange::parse(payload)?), FRA_PROTOCOL => Self::Protocol( parse_u8(payload) - .context("invalid FRA_PROTOCOL value")? + .map_err(|error| RuleError::InvalidValue { + kind: "FRA_PROTOCOL", + error, + })? .into(), ), FRA_IP_PROTO => Self::IpProtocol(IpProtocol::from( - parse_u8(payload).context("invalid FRA_IP_PROTO value")? as i32, + parse_u8(payload).map_err(|error| RuleError::InvalidValue { + kind: "FRA_IP_PROTO", + error, + })? as i32, )), - FRA_SPORT_RANGE => Self::SourcePortRange( - RulePortRange::parse(payload) - .context("invalid FRA_SPORT_RANGE value")?, - ), - FRA_DPORT_RANGE => Self::DestinationPortRange( - RulePortRange::parse(payload) - .context("invalid FRA_DPORT_RANGE value")?, - ), - _ => Self::Other( - DefaultNla::parse(buf).context("invalid NLA (unknown kind)")?, + FRA_SPORT_RANGE => { + Self::SourcePortRange(RulePortRange::parse(payload)?) + } + FRA_DPORT_RANGE => { + Self::DestinationPortRange(RulePortRange::parse(payload)?) + } + kind => Self::Other( + DefaultNla::parse(buf) + .map_err(|error| RuleError::UnknownNLA { kind, error })?, ), }) } diff --git a/src/rule/error.rs b/src/rule/error.rs new file mode 100644 index 00000000..d37d1a8d --- /dev/null +++ b/src/rule/error.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT + +use crate::route::RouteError; +use netlink_packet_utils::{nla::NlaError, DecodeError}; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum RuleError { + #[error("Invalid {kind}")] + InvalidValue { + kind: &'static str, + error: DecodeError, + }, + + #[error("Unknown NLA type: {kind}")] + UnknownNLA { kind: u16, error: DecodeError }, + + #[error(transparent)] + ParseNla(#[from] NlaError), + + #[error(transparent)] + ParseFraFlow(#[from] RouteError), + + #[error("Invalid rule uid range data, expecting {expected} u8 array, but got {got}")] + ParseUidRange { expected: usize, got: usize }, + + #[error("Invalid rule port range data, expecting {expected} u8 array, but got {got}")] + ParsePortRange { expected: usize, got: usize }, +} diff --git a/src/rule/header.rs b/src/rule/header.rs index fc710cbe..ab54288f 100644 --- a/src/rule/header.rs +++ b/src/rule/header.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT use netlink_packet_utils::{ - nla::{NlaBuffer, NlasIterator}, + nla::{NlaBuffer, NlaError, NlasIterator}, traits::{Emitable, Parseable}, DecodeError, }; @@ -26,7 +26,7 @@ buffer!(RuleMessageBuffer(RULE_HEADER_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> RuleMessageBuffer<&'a T> { pub fn attributes( &self, - ) -> impl Iterator, DecodeError>> { + ) -> impl Iterator, NlaError>> { NlasIterator::new(self.payload()) } } @@ -63,8 +63,8 @@ impl Emitable for RuleHeader { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for RuleHeader { - type Error = DecodeError; - fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result { + type Error = (); + fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result { Ok(RuleHeader { family: buf.family().into(), dst_len: buf.dst_len(), diff --git a/src/rule/message.rs b/src/rule/message.rs index 85934425..427f155e 100644 --- a/src/rule/message.rs +++ b/src/rule/message.rs @@ -1,12 +1,7 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; -use netlink_packet_utils::{ - traits::{Emitable, Parseable}, - DecodeError, -}; - -use super::{RuleAttribute, RuleHeader, RuleMessageBuffer}; +use super::{RuleAttribute, RuleError, RuleHeader, RuleMessageBuffer}; +use netlink_packet_utils::traits::{Emitable, Parseable}; #[derive(Debug, PartialEq, Eq, Clone, Default)] #[non_exhaustive] @@ -31,12 +26,11 @@ impl Emitable for RuleMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for RuleMessage { - type Error = DecodeError; - fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result { - let header = RuleHeader::parse(buf) - .context("failed to parse link message header")?; - let attributes = Vec::::parse(buf) - .context("failed to parse link message NLAs")?; + type Error = RuleError; + fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result { + // unwrap: RuleHeader never fails to parse. + let header = RuleHeader::parse(buf).unwrap(); + let attributes = Vec::::parse(buf)?; Ok(RuleMessage { header, attributes }) } } @@ -44,8 +38,8 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { - type Error = DecodeError; - fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result { + type Error = RuleError; + fn parse(buf: &RuleMessageBuffer<&'a T>) -> Result { let mut attributes = vec![]; for nla_buf in buf.attributes() { attributes.push(RuleAttribute::parse(&nla_buf?)?); diff --git a/src/rule/mod.rs b/src/rule/mod.rs index 8778dcd8..3ef9595a 100644 --- a/src/rule/mod.rs +++ b/src/rule/mod.rs @@ -2,6 +2,7 @@ mod action; mod attribute; +mod error; mod flags; mod header; mod message; @@ -12,6 +13,7 @@ mod uid_range; pub use self::action::RuleAction; pub use self::attribute::RuleAttribute; +pub use self::error::RuleError; pub use self::flags::RuleFlags; pub use self::header::{RuleHeader, RuleMessageBuffer}; pub use self::message::RuleMessage; diff --git a/src/rule/port_range.rs b/src/rule/port_range.rs index 04ae7fd9..5d1078c2 100644 --- a/src/rule/port_range.rs +++ b/src/rule/port_range.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT -use netlink_packet_utils::{DecodeError, Emitable}; +use crate::rule::RuleError; +use netlink_packet_utils::Emitable; const RULE_PORT_RANGE_LEN: usize = 4; @@ -11,18 +12,17 @@ pub struct RulePortRange { } impl RulePortRange { - pub(crate) fn parse(buf: &[u8]) -> Result { + pub(crate) fn parse(buf: &[u8]) -> Result { if buf.len() == RULE_PORT_RANGE_LEN { Ok(Self { start: u16::from_ne_bytes([buf[0], buf[1]]), end: u16::from_ne_bytes([buf[2], buf[3]]), }) } else { - Err(DecodeError::from(format!( - "Invalid rule port range data, expecting \ - {RULE_PORT_RANGE_LEN} u8 array, but got {:?}", - buf - ))) + Err(RuleError::ParsePortRange { + expected: RULE_PORT_RANGE_LEN, + got: buf.len(), + }) } } } diff --git a/src/rule/uid_range.rs b/src/rule/uid_range.rs index f63249ca..2b5c86e3 100644 --- a/src/rule/uid_range.rs +++ b/src/rule/uid_range.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT -use netlink_packet_utils::{DecodeError, Emitable}; +use crate::rule::RuleError; +use netlink_packet_utils::Emitable; const RULE_UID_RANGE_LEN: usize = 8; @@ -11,18 +12,17 @@ pub struct RuleUidRange { } impl RuleUidRange { - pub(crate) fn parse(buf: &[u8]) -> Result { + pub(crate) fn parse(buf: &[u8]) -> Result { if buf.len() == RULE_UID_RANGE_LEN { Ok(Self { start: u32::from_ne_bytes([buf[0], buf[1], buf[2], buf[3]]), end: u32::from_ne_bytes([buf[4], buf[5], buf[6], buf[7]]), }) } else { - Err(DecodeError::from(format!( - "Invalid rule port range data, expecting \ - {RULE_UID_RANGE_LEN} u8 array, but got {:?}", - buf - ))) + Err(RuleError::ParseUidRange { + expected: RULE_UID_RANGE_LEN, + got: buf.len(), + }) } } } diff --git a/src/tc/header.rs b/src/tc/header.rs index 019c964b..157e7af0 100644 --- a/src/tc/header.rs +++ b/src/tc/header.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT use netlink_packet_utils::{ - nla::{NlaBuffer, NlasIterator}, + nla::{NlaBuffer, NlaError, NlasIterator}, traits::{Emitable, Parseable}, DecodeError, }; @@ -24,7 +24,7 @@ buffer!(TcMessageBuffer(TC_HEADER_LEN) { impl<'a, T: AsRef<[u8]> + ?Sized> TcMessageBuffer<&'a T> { pub fn attributes( &self, - ) -> impl Iterator, DecodeError>> { + ) -> impl Iterator, NlaError>> { NlasIterator::new(self.payload()) } } From ab3263bc5ca224dd66b8cd549ea7439965e5fe5c Mon Sep 17 00:00:00 2001 From: Miguel Flores Ruiz de Eguino <1889916+miguelfrde@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:25:12 -0700 Subject: [PATCH 3/3] Update error types in the tc subdir --- src/message.rs | 13 +-- src/neighbour_table/param.rs | 2 +- src/tc/actions/action.rs | 87 +++++++++--------- src/tc/actions/nat.rs | 5 +- src/tc/attribute.rs | 84 +++++++++-------- src/tc/error.rs | 82 +++++++++++++++++ src/tc/filters/cls_u32.rs | 96 +++++++++++--------- src/tc/filters/matchall.rs | 42 +++++---- src/tc/header.rs | 7 +- src/tc/message.rs | 23 ++--- src/tc/mod.rs | 2 + src/tc/options.rs | 68 +++++++------- src/tc/qdiscs/fq_codel.rs | 170 ++++++++++++++++++++++------------- src/tc/qdiscs/ingress.rs | 5 +- src/tc/stats/basic.rs | 4 +- src/tc/stats/queue.rs | 4 +- src/tc/stats/stats2.rs | 41 +++++---- src/tc/stats/xstats.rs | 8 +- 18 files changed, 447 insertions(+), 296 deletions(-) create mode 100644 src/tc/error.rs diff --git a/src/message.rs b/src/message.rs index 3485128b..caaf41d7 100644 --- a/src/message.rs +++ b/src/message.rs @@ -13,7 +13,7 @@ use crate::{ prefix::{PrefixError, PrefixMessage, PrefixMessageBuffer}, route::{RouteError, RouteHeader, RouteMessage, RouteMessageBuffer}, rule::{RuleError, RuleMessage, RuleMessageBuffer}, - tc::{TcMessage, TcMessageBuffer}, + tc::{TcError, TcMessage, TcMessageBuffer}, }; use netlink_packet_core::{ NetlinkDeserializable, NetlinkHeader, NetlinkPayload, NetlinkSerializable, @@ -100,8 +100,8 @@ pub enum RouteNetlinkMessageParseError { #[error(transparent)] InvalidFibRuleMessage(#[from] RuleError), - #[error("Invalid tc message")] - InvalidTcMessage(#[source] DecodeError), + #[error(transparent)] + InvalidTcMessage(#[from] TcError), #[error(transparent)] InvalidNsidMessage(#[from] NsidError), @@ -290,9 +290,10 @@ impl<'a, T: AsRef<[u8]> + ?Sized> | RTM_DELTCLASS | RTM_GETTCLASS | RTM_NEWTFILTER | RTM_DELTFILTER | RTM_GETTFILTER | RTM_NEWCHAIN | RTM_DELCHAIN | RTM_GETCHAIN => { - let msg = TcMessageBuffer::new_checked(&buf.inner()) - .and_then(|buffer| TcMessage::parse(&buffer)) - .map_err(RouteNetlinkMessageParseError::InvalidTcMessage)?; + let buf_inner = buf.inner(); + let buffer = TcMessageBuffer::new_checked(&buf_inner) + .map_err(RouteNetlinkMessageParseError::ParseBuffer)?; + let msg = TcMessage::parse(&buffer)?; match message_type { RTM_NEWQDISC => { RouteNetlinkMessage::NewQueueDiscipline(msg) diff --git a/src/neighbour_table/param.rs b/src/neighbour_table/param.rs index c2588fb8..6008c59a 100644 --- a/src/neighbour_table/param.rs +++ b/src/neighbour_table/param.rs @@ -5,7 +5,7 @@ use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::{parse_u32, parse_u64}, - DecodeError, Parseable, + Parseable, }; const NDTPA_IFINDEX: u16 = 1; diff --git a/src/tc/actions/action.rs b/src/tc/actions/action.rs index df6f4c99..faf87cf3 100644 --- a/src/tc/actions/action.rs +++ b/src/tc/actions/action.rs @@ -1,8 +1,10 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::{ + TcActionMirror, TcActionMirrorOption, TcActionNat, TcActionNatOption, +}; +use crate::tc::{TcError, TcStats2}; use byteorder::{ByteOrder, NativeEndian}; - use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::{parse_string, parse_u32}, @@ -10,11 +12,6 @@ use netlink_packet_utils::{ DecodeError, }; -use super::{ - TcActionMirror, TcActionMirrorOption, TcActionNat, TcActionNatOption, -}; -use crate::tc::TcStats2; - const TCA_ACT_TAB: u16 = 1; #[derive(Debug, PartialEq, Eq, Clone)] @@ -48,61 +45,62 @@ impl Nla for TcAction { } impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcAction { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = TcError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let mut attributes = vec![]; let mut kind = String::new(); for iter in NlasIterator::new(buf.value()) { - let buf = iter.context("invalid action nla")?; + let buf = iter?; let payload = buf.value(); attributes.push(match buf.kind() { TCA_ACT_KIND => { - kind = parse_string(payload) - .context("failed to parse TCA_ACT_KIND")?; + kind = parse_string(payload).map_err(|error| { + TcError::ParseAction { + kind: "TCA_ACT_KIND", + error, + } + })?; TcActionAttribute::Kind(kind.clone()) } TCA_ACT_OPTIONS => { let mut nlas = vec![]; for nla in NlasIterator::new(payload) { - let nla = nla.context("invalid TCA_ACT_OPTIONS")?; - nlas.push( - TcActionOption::parse_with_param(&nla, &kind) - .context(format!( - "failed to parse TCA_ACT_OPTIONS \ - for kind {kind}" - ))?, - ) + let nla = nla?; + nlas.push(TcActionOption::parse_with_param( + &nla, &kind, + )?); } TcActionAttribute::Options(nlas) } - TCA_ACT_INDEX => TcActionAttribute::Index( - parse_u32(payload) - .context("failed to parse TCA_ACT_INDEX")?, - ), + TCA_ACT_INDEX => { + TcActionAttribute::Index(parse_u32(payload).map_err( + |error| TcError::ParseAction { + kind: "TCA_ACT_INDEX", + error, + }, + )?) + } TCA_ACT_STATS => { let mut nlas = vec![]; for nla in NlasIterator::new(payload) { - let nla = nla.context("invalid TCA_ACT_STATS")?; - nlas.push( - TcStats2::parse_with_param(&nla, &kind).context( - format!( - "failed to parse TCA_ACT_STATS for \ - kind {kind}", - ), - )?, - ); + let nla = nla?; + nlas.push(TcStats2::parse_with_param(&nla, &kind)?); } TcActionAttribute::Stats(nlas) } TCA_ACT_COOKIE => TcActionAttribute::Cookie(payload.to_vec()), - TCA_ACT_IN_HW_COUNT => TcActionAttribute::InHwCount( - parse_u32(payload) - .context("failed to parse TCA_ACT_IN_HW_COUNT")?, - ), - _ => TcActionAttribute::Other( + TCA_ACT_IN_HW_COUNT => { + TcActionAttribute::InHwCount(parse_u32(payload).map_err( + |error| TcError::ParseAction { + kind: "TCA_ACT_IN_HW_COUNT", + error, + }, + )?) + } + kind => TcActionAttribute::Other( DefaultNla::parse(&buf) - .context("failed to parse action nla")?, + .map_err(|error| TcError::UnknownNla { kind, error })?, ), }); } @@ -215,23 +213,22 @@ where T: AsRef<[u8]> + ?Sized, S: AsRef, { - type Error = DecodeError; + type Error = TcError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: S, - ) -> Result { + ) -> Result { Ok(match kind.as_ref() { TcActionMirror::KIND => Self::Mirror( TcActionMirrorOption::parse(buf) - .context("failed to parse mirror action")?, + .map_err(TcError::ParseMirrorAction)?, ), TcActionNat::KIND => Self::Nat( TcActionNatOption::parse(buf) - .context("failed to parse nat action")?, + .map_err(TcError::ParseMirrorAction)?, ), _ => Self::Other( - DefaultNla::parse(buf) - .context("failed to parse action options")?, + DefaultNla::parse(buf).map_err(TcError::ParseMirrorAction)?, ), }) } diff --git a/src/tc/actions/nat.rs b/src/tc/actions/nat.rs index 2218bed5..f1393049 100644 --- a/src/tc/actions/nat.rs +++ b/src/tc/actions/nat.rs @@ -141,10 +141,7 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcNat { fn parse_ipv4(data: &[u8]) -> Result { if data.len() != 4 { - Err(DecodeError::from(format!( - "Invalid length of IPv4 Address, expecting 4 bytes, but got {:?}", - data - ))) + Err(DecodeError::InvalidIPAddress) } else { Ok(Ipv4Addr::new(data[0], data[1], data[2], data[3])) } diff --git a/src/tc/attribute.rs b/src/tc/attribute.rs index 9d8051b3..38d349ae 100644 --- a/src/tc/attribute.rs +++ b/src/tc/attribute.rs @@ -1,15 +1,13 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::{ + TcError, TcOption, TcStats, TcStats2, TcStatsBuffer, TcXstats, VecTcOption, +}; use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::{parse_string, parse_u32, parse_u8}, - DecodeError, Emitable, Parseable, ParseableParametrized, -}; - -use super::{ - TcOption, TcStats, TcStats2, TcStatsBuffer, TcXstats, VecTcOption, + Emitable, Parseable, ParseableParametrized, }; const TCA_KIND: u16 = 1; @@ -109,54 +107,70 @@ impl Nla for TcAttribute { impl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized, &str> for TcAttribute { - type Error = DecodeError; + type Error = TcError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: &str, - ) -> Result { + ) -> Result { let payload = buf.value(); Ok(match buf.kind() { - TCA_KIND => TcAttribute::Kind( - parse_string(payload).context("invalid TCA_KIND")?, - ), + TCA_KIND => { + TcAttribute::Kind(parse_string(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_KIND", + error, + } + })?) + } TCA_OPTIONS => TcAttribute::Options( - VecTcOption::parse_with_param(buf, kind) - .context(format!("Invalid TCA_OPTIONS for kind: {kind}"))? - .0, + VecTcOption::parse_with_param(buf, kind)?.0, ), TCA_STATS => TcAttribute::Stats( - TcStats::parse( - &TcStatsBuffer::new_checked(payload) - .context("invalid TCA_STATS")?, - ) - .context("failed to parse TCA_STATS")?, - ), - TCA_XSTATS => TcAttribute::Xstats( - TcXstats::parse_with_param(buf, kind) - .context("invalid TCA_XSTATS")?, + TcStats::parse(&TcStatsBuffer::new_checked(payload).map_err( + |error| TcError::InvalidValue { + kind: "TCA_STATS", + error, + }, + )?) + .map_err(|error| TcError::InvalidValue { + kind: "TCA_STATS", + error, + })?, ), + TCA_XSTATS => { + TcAttribute::Xstats(TcXstats::parse_with_param(buf, kind)?) + } TCA_RATE => TcAttribute::Rate(payload.to_vec()), TCA_FCNT => TcAttribute::Fcnt(payload.to_vec()), TCA_STATS2 => { let mut nlas = vec![]; for nla in NlasIterator::new(payload) { - let nla = nla.context("invalid TCA_STATS2")?; - nlas.push(TcStats2::parse_with_param(&nla, kind).context( - format!("failed to parse TCA_STATS2 for kind {kind}"), - )?); + let nla = nla?; + nlas.push(TcStats2::parse_with_param(&nla, kind)?); } TcAttribute::Stats2(nlas) } TCA_STAB => TcAttribute::Stab(payload.to_vec()), - TCA_CHAIN => TcAttribute::Chain( - parse_u32(payload).context("failed to parse TCA_CHAIN")?, - ), - TCA_HW_OFFLOAD => TcAttribute::HwOffload( - parse_u8(payload).context("failed to parse TCA_HW_OFFLOAD")?, - ), + TCA_CHAIN => { + TcAttribute::Chain(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_CHAIN", + error, + } + })?) + } + TCA_HW_OFFLOAD => { + TcAttribute::HwOffload(parse_u8(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_HW_OFFLOAD", + error, + } + })?) + } TCA_DUMP_INVISIBLE => TcAttribute::DumpInvisible(true), - _ => TcAttribute::Other( - DefaultNla::parse(buf).context("failed to parse tc nla")?, + kind => TcAttribute::Other( + DefaultNla::parse(buf) + .map_err(|error| TcError::UnknownNla { kind, error })?, ), }) } diff --git a/src/tc/error.rs b/src/tc/error.rs new file mode 100644 index 00000000..c4c22411 --- /dev/null +++ b/src/tc/error.rs @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT + +use netlink_packet_utils::{nla::NlaError, DecodeError}; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum TcError { + #[error("Invalid {kind}")] + InvalidValue { + kind: &'static str, + #[source] + error: DecodeError, + }, + + #[error("failed to parse {kind} TCA_OPTIONS attributes")] + ParseTcaOptionAttributes { + kind: &'static str, + #[source] + error: DecodeError, + }, + + #[error("failed to parse {kind}")] + ParseFilterMatchallOption { + kind: &'static str, + #[source] + error: DecodeError, + }, + + #[error("failed to parse {kind}")] + ParseAction { + kind: &'static str, + #[source] + error: DecodeError, + }, + + #[error("failed to parse TCA_ACT_OPTIONS for kind {kind}")] + ParseActOptions { + kind: String, + #[source] + error: DecodeError, + }, + + #[error("failed to parse mirror action")] + ParseMirrorAction(#[source] DecodeError), + + #[error("Unknown matchall option: {kind}")] + UnknownFilterMatchAllOption { + kind: String, + #[source] + error: DecodeError, + }, + + #[error("Unknown NLA type: {kind}")] + UnknownNla { + kind: u16, + #[source] + error: DecodeError, + }, + + #[error("Unknown TC_OPTIONS: {kind}")] + UnknownOption { + kind: String, + #[source] + error: DecodeError, + }, + + #[error(transparent)] + ParseNla(#[from] NlaError), + + #[error("failed to parse TCA_STATS2 for kind {kind}")] + ParseTcaStats2 { + kind: String, + #[source] + error: DecodeError, + }, + + #[error("Invalid u32 key")] + InvalidU32Key(#[source] DecodeError), + + #[error("Invalid TcFqCodelXstats length: {0}")] + InvalidXstatsLength(usize), +} diff --git a/src/tc/filters/cls_u32.rs b/src/tc/filters/cls_u32.rs index 3b08de3a..99fda321 100644 --- a/src/tc/filters/cls_u32.rs +++ b/src/tc/filters/cls_u32.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MIT +use super::u32_flags::{TcU32OptionFlags, TcU32SelectorFlags}; +use crate::tc::{TcAction, TcError, TcHandle}; /// U32 filter /// /// In its simplest form the U32 filter is a list of records, each @@ -7,7 +9,6 @@ /// described below, are compared with the currently processed IP packet /// until the first match occurs, and then the associated action is /// performed. -use anyhow::Context; use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, @@ -16,9 +17,6 @@ use netlink_packet_utils::{ DecodeError, }; -use super::u32_flags::{TcU32OptionFlags, TcU32SelectorFlags}; -use crate::tc::{TcAction, TcHandle}; - const TC_U32_SEL_BUF_LEN: usize = 16; const TC_U32_KEY_BUF_LEN: usize = 16; @@ -115,39 +113,54 @@ impl Nla for TcFilterU32Option { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcFilterU32Option { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = TcError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { TCA_U32_CLASSID => Self::ClassId(TcHandle::from( - parse_u32(payload).context("failed to parse TCA_U32_UNSPEC")?, + parse_u32(payload).map_err(|error| TcError::InvalidValue { + kind: "TCA_U32_UNSPEC", + error, + })?, )), - TCA_U32_HASH => Self::Hash( - parse_u32(payload).context("failed to parse TCA_U32_HASH")?, - ), - TCA_U32_LINK => Self::Link( - parse_u32(payload).context("failed to parse TCA_U32_LINK")?, - ), - TCA_U32_DIVISOR => Self::Divisor( - parse_u32(payload) - .context("failed to parse TCA_U32_DIVISOR")?, - ), - TCA_U32_SEL => Self::Selector( - TcU32Selector::parse( - &TcU32SelectorBuffer::new_checked(payload) - .context("invalid TCA_U32_SEL")?, - ) - .context("failed to parse TCA_U32_SEL")?, - ), + TCA_U32_HASH => { + Self::Hash(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_U32_HASH", + error, + } + })?) + } + TCA_U32_LINK => { + Self::Link(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_U32_LINK", + error, + } + })?) + } + TCA_U32_DIVISOR => { + Self::Divisor(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_U32_DIVISOR", + error, + } + })?) + } + TCA_U32_SEL => Self::Selector(TcU32Selector::parse( + &TcU32SelectorBuffer::new_checked(payload).map_err( + |error| TcError::InvalidValue { + kind: "TCA_U32_SEL", + error, + }, + )?, + )?), TCA_U32_POLICE => Self::Police(payload.to_vec()), TCA_U32_ACT => { let mut acts = vec![]; for act in NlasIterator::new(payload) { - let act = act.context("invalid TCA_U32_ACT")?; - acts.push( - TcAction::parse(&act) - .context("failed to parse TCA_U32_ACT")?, - ); + let act = act?; + acts.push(TcAction::parse(&act)?); } Self::Action(acts) } @@ -155,10 +168,14 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> TCA_U32_PCNT => Self::Pnct(payload.to_vec()), TCA_U32_MARK => Self::Mark(payload.to_vec()), TCA_U32_FLAGS => Self::Flags(TcU32OptionFlags::from_bits_retain( - parse_u32(payload).context("failed to parse TCA_U32_FLAGS")?, + parse_u32(payload).map_err(|error| TcError::InvalidValue { + kind: "TCA_U32_FLAGS", + error, + })?, )), - _ => Self::Other( - DefaultNla::parse(buf).context("failed to parse u32 nla")?, + kind => Self::Other( + DefaultNla::parse(buf) + .map_err(|error| TcError::UnknownNla { kind, error })?, ), }) } @@ -220,8 +237,8 @@ impl Emitable for TcU32Selector { impl + ?Sized> Parseable> for TcU32Selector { - type Error = DecodeError; - fn parse(buf: &TcU32SelectorBuffer<&T>) -> Result { + type Error = TcError; + fn parse(buf: &TcU32SelectorBuffer<&T>) -> Result { let nkeys = buf.nkeys(); let mut keys = Vec::::with_capacity(nkeys.into()); let key_payload = buf.keys(); @@ -231,10 +248,9 @@ impl + ?Sized> Parseable> &key_payload [(i * TC_U32_KEY_BUF_LEN)..(i + 1) * TC_U32_KEY_BUF_LEN], ) - .context("invalid u32 key")?; - keys.push( - TcU32Key::parse(&keybuf).context("failed to parse u32 key")?, - ); + .map_err(|error| TcError::InvalidU32Key(error))?; + // unwrap: this never fails to parse. + keys.push(TcU32Key::parse(&keybuf).unwrap()); } Ok(Self { @@ -281,8 +297,8 @@ impl Emitable for TcU32Key { } impl> Parseable> for TcU32Key { - type Error = DecodeError; - fn parse(buf: &TcU32KeyBuffer) -> Result { + type Error = (); + fn parse(buf: &TcU32KeyBuffer) -> Result { Ok(Self { mask: buf.mask(), val: buf.val(), diff --git a/src/tc/filters/matchall.rs b/src/tc/filters/matchall.rs index fef22e00..016c59db 100644 --- a/src/tc/filters/matchall.rs +++ b/src/tc/filters/matchall.rs @@ -1,19 +1,16 @@ // SPDX-License-Identifier: MIT +use crate::tc::{TcAction, TcError, TcHandle}; /// Matchall filter /// /// Matches all packets and performs an action on them. -use anyhow::Context; use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, parsers::parse_u32, traits::{Emitable, Parseable}, - DecodeError, }; -use crate::tc::{TcAction, TcHandle}; - const TCA_MATCHALL_CLASSID: u16 = 1; const TCA_MATCHALL_ACT: u16 = 2; const TCA_MATCHALL_FLAGS: u16 = 3; @@ -71,34 +68,41 @@ impl Nla for TcFilterMatchAllOption { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcFilterMatchAllOption { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = TcError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { TCA_MATCHALL_CLASSID => Self::ClassId( parse_u32(payload) - .context("failed to parse TCA_MATCHALL_UNSPEC")? + .map_err(|error| TcError::ParseFilterMatchallOption { + kind: "TCA_MATCHALL_UNSPEC", + error, + })? .into(), ), TCA_MATCHALL_ACT => { let mut acts = vec![]; for act in NlasIterator::new(payload) { - let act = act.context("invalid TCA_MATCHALL_ACT")?; - acts.push( - TcAction::parse(&act) - .context("failed to parse TCA_MATCHALL_ACT")?, - ); + let act = act?; + acts.push(TcAction::parse(&act)?); } Self::Action(acts) } TCA_MATCHALL_PCNT => Self::Pnct(payload.to_vec()), - TCA_MATCHALL_FLAGS => Self::Flags( - parse_u32(payload) - .context("failed to parse TCA_MATCHALL_FLAGS")?, - ), - _ => Self::Other( - DefaultNla::parse(buf).context("failed to parse u32 nla")?, - ), + TCA_MATCHALL_FLAGS => { + Self::Flags(parse_u32(payload).map_err(|error| { + TcError::ParseFilterMatchallOption { + kind: "TCA_MATCHALL_FLAGS", + error, + } + })?) + } + kind => Self::Other(DefaultNla::parse(buf).map_err(|error| { + TcError::UnknownFilterMatchAllOption { + kind: kind.to_string(), + error, + } + })?), }) } } diff --git a/src/tc/header.rs b/src/tc/header.rs index 157e7af0..13765f6d 100644 --- a/src/tc/header.rs +++ b/src/tc/header.rs @@ -1,13 +1,12 @@ // SPDX-License-Identifier: MIT +use crate::AddressFamily; use netlink_packet_utils::{ nla::{NlaBuffer, NlaError, NlasIterator}, traits::{Emitable, Parseable}, DecodeError, }; -use crate::AddressFamily; - const TC_HEADER_LEN: usize = 20; buffer!(TcMessageBuffer(TC_HEADER_LEN) { @@ -61,8 +60,8 @@ impl Emitable for TcHeader { } impl> Parseable> for TcHeader { - type Error = DecodeError; - fn parse(buf: &TcMessageBuffer) -> Result { + type Error = (); + fn parse(buf: &TcMessageBuffer) -> Result { Ok(Self { family: buf.family().into(), index: buf.index(), diff --git a/src/tc/message.rs b/src/tc/message.rs index a6e75196..740b2088 100644 --- a/src/tc/message.rs +++ b/src/tc/message.rs @@ -1,13 +1,10 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; -use netlink_packet_utils::{ - traits::{Emitable, Parseable, ParseableParametrized}, - DecodeError, +use super::{TcAttribute, TcError, TcHeader, TcMessageBuffer}; +use netlink_packet_utils::traits::{ + Emitable, Parseable, ParseableParametrized, }; -use super::{TcAttribute, TcHeader, TcMessageBuffer}; - #[derive(Debug, PartialEq, Eq, Clone, Default)] #[non_exhaustive] pub struct TcMessage { @@ -37,13 +34,11 @@ impl TcMessage { } impl<'a, T: AsRef<[u8]> + 'a> Parseable> for TcMessage { - type Error = DecodeError; - fn parse(buf: &TcMessageBuffer<&'a T>) -> Result { + type Error = TcError; + fn parse(buf: &TcMessageBuffer<&'a T>) -> Result { Ok(Self { - header: TcHeader::parse(buf) - .context("failed to parse tc message header")?, - attributes: Vec::::parse(buf) - .context("failed to parse tc message NLAs")?, + header: TcHeader::parse(buf).unwrap(), + attributes: Vec::::parse(buf)?, }) } } @@ -51,8 +46,8 @@ impl<'a, T: AsRef<[u8]> + 'a> Parseable> for TcMessage { impl<'a, T: AsRef<[u8]> + 'a> Parseable> for Vec { - type Error = DecodeError; - fn parse(buf: &TcMessageBuffer<&'a T>) -> Result { + type Error = TcError; + fn parse(buf: &TcMessageBuffer<&'a T>) -> Result { let mut attributes = vec![]; let mut kind = String::new(); diff --git a/src/tc/mod.rs b/src/tc/mod.rs index 56608bd2..b67485fc 100644 --- a/src/tc/mod.rs +++ b/src/tc/mod.rs @@ -2,6 +2,7 @@ mod actions; mod attribute; +mod error; mod filters; mod header; mod message; @@ -16,6 +17,7 @@ pub use self::actions::{ TcNat, TcNatBuffer, TcNatFlags, }; pub use self::attribute::TcAttribute; +pub use self::error::TcError; pub use self::filters::{ TcFilterMatchAll, TcFilterMatchAllOption, TcFilterU32, TcFilterU32Option, TcU32Key, TcU32OptionFlags, TcU32Selector, TcU32SelectorFlags, diff --git a/src/tc/options.rs b/src/tc/options.rs index 80a69719..c6a9e1ce 100644 --- a/src/tc/options.rs +++ b/src/tc/options.rs @@ -1,15 +1,13 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use super::{ + TcError, TcFilterMatchAll, TcFilterMatchAllOption, TcFilterU32, + TcFilterU32Option, TcQdiscFqCodel, TcQdiscFqCodelOption, TcQdiscIngress, + TcQdiscIngressOption, +}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer, NlasIterator}, traits::{Parseable, ParseableParametrized}, - DecodeError, -}; - -use super::{ - TcFilterMatchAll, TcFilterMatchAllOption, TcFilterU32, TcFilterU32Option, - TcQdiscFqCodel, TcQdiscFqCodelOption, TcQdiscIngress, TcQdiscIngressOption, }; #[derive(Debug, PartialEq, Eq, Clone)] @@ -62,32 +60,33 @@ impl<'a, T> ParseableParametrized, &str> for TcOption where T: AsRef<[u8]> + ?Sized, { - type Error = DecodeError; + type Error = TcError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: &str, - ) -> Result { + ) -> Result { Ok(match kind { TcQdiscIngress::KIND => { - Self::Ingress(TcQdiscIngressOption::parse(buf).context( - "failed to parse ingress TCA_OPTIONS attributes", + Self::Ingress(TcQdiscIngressOption::parse(buf).map_err( + |error| TcError::ParseTcaOptionAttributes { + kind: "ingress", + error, + }, )?) } TcQdiscFqCodel::KIND => { - Self::FqCodel(TcQdiscFqCodelOption::parse(buf).context( - "failed to parse fq_codel TCA_OPTIONS attributes", - )?) + Self::FqCodel(TcQdiscFqCodelOption::parse(buf)?) } - TcFilterU32::KIND => Self::U32( - TcFilterU32Option::parse(buf) - .context("failed to parse u32 TCA_OPTIONS attributes")?, - ), + TcFilterU32::KIND => Self::U32(TcFilterU32Option::parse(buf)?), TcFilterMatchAll::KIND => { - Self::MatchAll(TcFilterMatchAllOption::parse(buf).context( - "failed to parse matchall TCA_OPTIONS attributes", - )?) + Self::MatchAll(TcFilterMatchAllOption::parse(buf)?) } - _ => Self::Other(DefaultNla::parse(buf)?), + kind => Self::Other(DefaultNla::parse(buf).map_err(|error| { + TcError::UnknownOption { + kind: kind.to_string(), + error, + } + })?), }) } } @@ -98,11 +97,11 @@ impl<'a, T> ParseableParametrized, &str> for VecTcOption where T: AsRef<[u8]> + ?Sized, { - type Error = DecodeError; + type Error = TcError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: &str, - ) -> Result { + ) -> Result { Ok(match kind { TcFilterU32::KIND | TcFilterMatchAll::KIND @@ -110,16 +109,8 @@ where | TcQdiscFqCodel::KIND => { let mut nlas = vec![]; for nla in NlasIterator::new(buf.value()) { - let nla = nla.context(format!( - "Invalid TCA_OPTIONS for kind: {kind}", - ))?; - nlas.push( - TcOption::parse_with_param(&nla, kind).context( - format!( - "Failed to parse TCA_OPTIONS for kind: {kind}", - ), - )?, - ) + let nla = nla?; + nlas.push(TcOption::parse_with_param(&nla, kind)?) } Self(nlas) } @@ -127,7 +118,14 @@ where // should place a nla_nest here. The `sfq` qdisc kernel code is // using single NLA instead nested ones. Hence we are storing // unknown Nla as Vec with single item. - _ => Self(vec![TcOption::Other(DefaultNla::parse(buf)?)]), + kind => { + Self(vec![TcOption::Other(DefaultNla::parse(buf).map_err( + |error| TcError::UnknownOption { + kind: kind.to_string(), + error, + }, + )?)]) + } }) } } diff --git a/src/tc/qdiscs/fq_codel.rs b/src/tc/qdiscs/fq_codel.rs index fe330545..11d5e378 100644 --- a/src/tc/qdiscs/fq_codel.rs +++ b/src/tc/qdiscs/fq_codel.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -use anyhow::Context; +use crate::tc::TcError; use byteorder::{ByteOrder, NativeEndian}; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer}, @@ -32,13 +32,10 @@ pub enum TcFqCodelXstats { } impl + ?Sized> Parseable for TcFqCodelXstats { - type Error = DecodeError; - fn parse(buf: &T) -> Result { + type Error = TcError; + fn parse(buf: &T) -> Result { if buf.as_ref().len() < 4 { - return Err(DecodeError::from(format!( - "Invalid TcFqCodelXstats {:?}", - buf.as_ref() - ))); + return Err(TcError::InvalidXstatsLength(buf.as_ref().len())); } let mut buf_type_bytes = [0; 4]; buf_type_bytes.copy_from_slice(&buf.as_ref()[0..4]); @@ -47,14 +44,22 @@ impl + ?Sized> Parseable for TcFqCodelXstats { match buf_type { TCA_FQ_CODEL_XSTATS_QDISC => { - Ok(Self::Qdisc(TcFqCodelQdStats::parse( - &TcFqCodelQdStatsBuffer::new(&buf.as_ref()[4..]), - )?)) + // unwrap: we never fail below to parse TcFqCodelQdStats. + Ok(Self::Qdisc( + TcFqCodelQdStats::parse(&TcFqCodelQdStatsBuffer::new( + &buf.as_ref()[4..], + )) + .unwrap(), + )) } TCA_FQ_CODEL_XSTATS_CLASS => { - Ok(Self::Class(TcFqCodelClStats::parse( - &TcFqCodelClStatsBuffer::new(&buf.as_ref()[4..]), - )?)) + // unwrap: we never fail below to parse TcFqCodelQdStats. + Ok(Self::Class( + TcFqCodelClStats::parse(&TcFqCodelClStatsBuffer::new( + &buf.as_ref()[4..], + )) + .unwrap(), + )) } _ => Ok(Self::Other(buf.as_ref().to_vec())), } @@ -118,8 +123,8 @@ buffer!(TcFqCodelQdStatsBuffer(TC_FQ_CODEL_QD_STATS_LEN) { }); impl> Parseable> for TcFqCodelQdStats { - type Error = DecodeError; - fn parse(buf: &TcFqCodelQdStatsBuffer) -> Result { + type Error = (); + fn parse(buf: &TcFqCodelQdStatsBuffer) -> Result { Ok(Self { maxpacket: buf.maxpacket(), drop_overlimit: buf.drop_overlimit(), @@ -288,58 +293,99 @@ impl Nla for TcQdiscFqCodelOption { impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for TcQdiscFqCodelOption { - type Error = DecodeError; - fn parse(buf: &NlaBuffer<&'a T>) -> Result { + type Error = TcError; + fn parse(buf: &NlaBuffer<&'a T>) -> Result { let payload = buf.value(); Ok(match buf.kind() { - TCA_FQ_CODEL_TARGET => Self::Target( - parse_u32(payload) - .context("failed to parse TCA_FQ_CODEL_TARGET")?, - ), - TCA_FQ_CODEL_LIMIT => Self::Limit( - parse_u32(payload) - .context("failed to parse TCA_FQ_CODEL_LIMIT")?, - ), - TCA_FQ_CODEL_INTERVAL => Self::Interval( - parse_u32(payload) - .context("failed to parse TCA_FQ_CODEL_INTERVAL")?, - ), - TCA_FQ_CODEL_ECN => Self::Ecn( - parse_u32(payload) - .context("failed to parse TCA_FQ_CODEL_ECN")?, - ), - TCA_FQ_CODEL_FLOWS => Self::Flows( - parse_u32(payload) - .context("failed to parse TCA_FQ_CODEL_FLOWS")?, - ), - TCA_FQ_CODEL_QUANTUM => Self::Quantum( - parse_u32(payload) - .context("failed to parse TCA_FQ_CODEL_QUANTUM")?, - ), - TCA_FQ_CODEL_CE_THRESHOLD => Self::CeThreshold( - parse_u32(payload) - .context("failed to parse TCA_FQ_CODEL_CETHRESHOLD")?, - ), - TCA_FQ_CODEL_DROP_BATCH_SIZE => Self::DropBatchSize( - parse_u32(payload) - .context("failed to parse TCA_FQ_CODEL_DROP_BATCH_SIZE")?, - ), - TCA_FQ_CODEL_MEMORY_LIMIT => Self::MemoryLimit( - parse_u32(payload) - .context("failed to parse TCA_FQ_CODEL_MEMORY_LIMIT")?, - ), - TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR => { - Self::CeThresholdSelector(parse_u8(payload).context( - "failed to parse TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR", - )?) + TCA_FQ_CODEL_TARGET => { + Self::Target(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_FQ_CODEL_TARGET", + error, + } + })?) + } + TCA_FQ_CODEL_LIMIT => { + Self::Limit(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_FQ_CODEL_LIMIT", + error, + } + })?) + } + TCA_FQ_CODEL_INTERVAL => { + Self::Interval(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_FQ_CODEL_INTERVAL", + error, + } + })?) + } + TCA_FQ_CODEL_ECN => { + Self::Ecn(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_FQ_CODEL_ECN", + error, + } + })?) + } + TCA_FQ_CODEL_FLOWS => { + Self::Flows(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_FQ_CODEL_FLOWS", + error, + } + })?) } + TCA_FQ_CODEL_QUANTUM => { + Self::Quantum(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_FQ_CODEL_QUANTUM", + error, + } + })?) + } + TCA_FQ_CODEL_CE_THRESHOLD => { + Self::CeThreshold(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_FQ_CODEL_CE_THRESHOLD", + error, + } + })?) + } + TCA_FQ_CODEL_DROP_BATCH_SIZE => { + Self::DropBatchSize(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_FQ_CODEL_DROP_BATCH_SIZE", + error, + } + })?) + } + TCA_FQ_CODEL_MEMORY_LIMIT => { + Self::MemoryLimit(parse_u32(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_FQ_CODEL_MEMORY_LIMIT", + error, + } + })?) + } + TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR => Self::CeThresholdSelector( + parse_u8(payload).map_err(|error| TcError::InvalidValue { + kind: "TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR", + error, + })?, + ), TCA_FQ_CODEL_CE_THRESHOLD_MASK => { - Self::CeThresholdMask(parse_u8(payload).context( - "failed to parse TCA_FQ_CODEL_CE_THRESHOLD_MASK", - )?) + Self::CeThresholdMask(parse_u8(payload).map_err(|error| { + TcError::InvalidValue { + kind: "TCA_FQ_CODEL_CE_THRESHOLD_MASK", + error, + } + })?) } - _ => Self::Other( - DefaultNla::parse(buf).context("failed to parse u32 nla")?, + kind => Self::Other( + DefaultNla::parse(buf) + .map_err(|error| TcError::UnknownNla { kind, error })?, ), }) } diff --git a/src/tc/qdiscs/ingress.rs b/src/tc/qdiscs/ingress.rs index 4479ca53..a369ef70 100644 --- a/src/tc/qdiscs/ingress.rs +++ b/src/tc/qdiscs/ingress.rs @@ -3,7 +3,6 @@ // Currently, the qdisc ingress does not have any attribute, kernel // just start a empty nla_nest. This is just a place holder -use anyhow::Context; use netlink_packet_utils::{ nla::{DefaultNla, Nla, NlaBuffer}, DecodeError, Parseable, @@ -48,8 +47,6 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> { type Error = DecodeError; fn parse(buf: &NlaBuffer<&'a T>) -> Result { - Ok(Self::Other( - DefaultNla::parse(buf).context("failed to parse ingress nla")?, - )) + Ok(Self::Other(DefaultNla::parse(buf)?)) } } diff --git a/src/tc/stats/basic.rs b/src/tc/stats/basic.rs index acfb717e..bb5ecca8 100644 --- a/src/tc/stats/basic.rs +++ b/src/tc/stats/basic.rs @@ -24,8 +24,8 @@ buffer!(TcStatsBasicBuffer(STATS_BASIC_LEN) { }); impl> Parseable> for TcStatsBasic { - type Error = DecodeError; - fn parse(buf: &TcStatsBasicBuffer) -> Result { + type Error = (); + fn parse(buf: &TcStatsBasicBuffer) -> Result { Ok(TcStatsBasic { bytes: buf.bytes(), packets: buf.packets(), diff --git a/src/tc/stats/queue.rs b/src/tc/stats/queue.rs index 893d2a7e..fff0186f 100644 --- a/src/tc/stats/queue.rs +++ b/src/tc/stats/queue.rs @@ -32,8 +32,8 @@ buffer!(TcStatsQueueBuffer( STATS_QUEUE_LEN) { }); impl> Parseable> for TcStatsQueue { - type Error = DecodeError; - fn parse(buf: &TcStatsQueueBuffer) -> Result { + type Error = (); + fn parse(buf: &TcStatsQueueBuffer) -> Result { Ok(Self { qlen: buf.qlen(), backlog: buf.backlog(), diff --git a/src/tc/stats/stats2.rs b/src/tc/stats/stats2.rs index 931497fa..8239a34b 100644 --- a/src/tc/stats/stats2.rs +++ b/src/tc/stats/stats2.rs @@ -1,15 +1,14 @@ // SPDX-License-Identifier: MIT -use netlink_packet_utils::{ - nla::{DefaultNla, Nla, NlaBuffer}, - traits::{Emitable, Parseable, ParseableParametrized}, - DecodeError, -}; - use super::{ TcStatsBasic, TcStatsBasicBuffer, TcStatsQueue, TcStatsQueueBuffer, TcXstats, }; +use crate::tc::TcError; +use netlink_packet_utils::{ + nla::{DefaultNla, Nla, NlaBuffer}, + traits::{Emitable, Parseable, ParseableParametrized}, +}; const TCA_STATS_BASIC: u16 = 1; // const TCA_STATS_RATE_EST: u16 = 2; // TODO @@ -65,24 +64,30 @@ impl<'a, T> ParseableParametrized, &str> for TcStats2 where T: AsRef<[u8]> + ?Sized, { - type Error = DecodeError; + type Error = TcError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: &str, - ) -> Result { + ) -> Result { let payload = buf.value(); Ok(match buf.kind() { TCA_STATS_APP => Self::App(TcXstats::parse_with_param(buf, kind)?), - TCA_STATS_BASIC => Self::Basic(TcStatsBasic::parse( - &TcStatsBasicBuffer::new(payload), - )?), - TCA_STATS_QUEUE => Self::Queue(TcStatsQueue::parse( - &TcStatsQueueBuffer::new(payload), - )?), - TCA_STATS_BASIC_HW => Self::BasicHw(TcStatsBasic::parse( - &TcStatsBasicBuffer::new(payload), - )?), - _ => Self::Other(DefaultNla::parse(buf)?), + TCA_STATS_BASIC => Self::Basic( + // unwrap: TCStatsBasic doesn't fail to parse. + TcStatsBasic::parse(&TcStatsBasicBuffer::new(payload)).unwrap(), + ), + TCA_STATS_QUEUE => Self::Queue( + // unwrap: TCStatsQueue doesn't fail to parse. + TcStatsQueue::parse(&TcStatsQueueBuffer::new(payload)).unwrap(), + ), + TCA_STATS_BASIC_HW => Self::BasicHw( + // unwrap: TCStatsBasic doesn't fail to parse. + TcStatsBasic::parse(&TcStatsBasicBuffer::new(payload)).unwrap(), + ), + kind => Self::Other( + DefaultNla::parse(buf) + .map_err(|error| TcError::UnknownNla { kind, error })?, + ), }) } } diff --git a/src/tc/stats/xstats.rs b/src/tc/stats/xstats.rs index 876d064f..bea137c8 100644 --- a/src/tc/stats/xstats.rs +++ b/src/tc/stats/xstats.rs @@ -1,13 +1,11 @@ // SPDX-License-Identifier: MIT +use crate::tc::{TcError, TcFqCodelXstats, TcQdiscFqCodel}; use netlink_packet_utils::{ nla::NlaBuffer, traits::{Emitable, Parseable, ParseableParametrized}, - DecodeError, }; -use crate::tc::{TcFqCodelXstats, TcQdiscFqCodel}; - #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] pub enum TcXstats { @@ -35,11 +33,11 @@ impl<'a, T> ParseableParametrized, &str> for TcXstats where T: AsRef<[u8]> + ?Sized, { - type Error = DecodeError; + type Error = TcError; fn parse_with_param( buf: &NlaBuffer<&'a T>, kind: &str, - ) -> Result { + ) -> Result { Ok(match kind { TcQdiscFqCodel::KIND => { TcXstats::FqCodel(TcFqCodelXstats::parse(buf.value())?)