netlink_packet_route/route/
metrics.rs

1// SPDX-License-Identifier: MIT
2
3use super::error::RouteError;
4use byteorder::{ByteOrder, NativeEndian};
5use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator};
6use netlink_packet_utils::parsers::parse_u32;
7use netlink_packet_utils::traits::Parseable;
8use std::mem::size_of;
9
10const RTAX_LOCK: u16 = 1;
11const RTAX_MTU: u16 = 2;
12const RTAX_WINDOW: u16 = 3;
13const RTAX_RTT: u16 = 4;
14const RTAX_RTTVAR: u16 = 5;
15const RTAX_SSTHRESH: u16 = 6;
16const RTAX_CWND: u16 = 7;
17const RTAX_ADVMSS: u16 = 8;
18const RTAX_REORDERING: u16 = 9;
19const RTAX_HOPLIMIT: u16 = 10;
20const RTAX_INITCWND: u16 = 11;
21const RTAX_FEATURES: u16 = 12;
22const RTAX_RTO_MIN: u16 = 13;
23const RTAX_INITRWND: u16 = 14;
24const RTAX_QUICKACK: u16 = 15;
25const RTAX_CC_ALGO: u16 = 16;
26const RTAX_FASTOPEN_NO_COOKIE: u16 = 17;
27
28#[derive(Debug, PartialEq, Eq, Clone)]
29#[non_exhaustive]
30pub enum RouteMetric {
31    Lock(u32),
32    Mtu(u32),
33    Window(u32),
34    Rtt(u32),
35    RttVar(u32),
36    SsThresh(u32),
37    Cwnd(u32),
38    Advmss(u32),
39    Reordering(u32),
40    Hoplimit(u32),
41    InitCwnd(u32),
42    Features(u32),
43    RtoMin(u32),
44    InitRwnd(u32),
45    QuickAck(u32),
46    CcAlgo(u32),
47    FastopenNoCookie(u32),
48    Other(DefaultNla),
49}
50
51impl Nla for RouteMetric {
52    fn value_len(&self) -> usize {
53        match self {
54            Self::Lock(_)
55            | Self::Mtu(_)
56            | Self::Window(_)
57            | Self::Rtt(_)
58            | Self::RttVar(_)
59            | Self::SsThresh(_)
60            | Self::Cwnd(_)
61            | Self::Advmss(_)
62            | Self::Reordering(_)
63            | Self::Hoplimit(_)
64            | Self::InitCwnd(_)
65            | Self::Features(_)
66            | Self::RtoMin(_)
67            | Self::InitRwnd(_)
68            | Self::QuickAck(_)
69            | Self::CcAlgo(_)
70            | Self::FastopenNoCookie(_) => size_of::<u32>(),
71            Self::Other(attr) => attr.value_len(),
72        }
73    }
74
75    #[rustfmt::skip]
76    fn emit_value(&self, buffer: &mut [u8]) {
77        match self {
78            Self::Lock(value)
79                 | Self:: Mtu(value)
80                 | Self:: Window(value)
81                 | Self:: Rtt(value)
82                 | Self:: RttVar(value)
83                 | Self:: SsThresh(value)
84                 | Self:: Cwnd(value)
85                 | Self:: Advmss(value)
86                 | Self:: Reordering(value)
87                 | Self:: Hoplimit(value)
88                 | Self:: InitCwnd(value)
89                 | Self:: Features(value)
90                 | Self:: RtoMin(value)
91                 | Self:: InitRwnd(value)
92                 | Self:: QuickAck(value)
93                 | Self:: CcAlgo(value)
94                 | Self:: FastopenNoCookie(value)
95                => NativeEndian::write_u32(buffer, *value),
96
97            Self::Other(attr) => attr.emit_value(buffer),
98        }
99    }
100
101    fn kind(&self) -> u16 {
102        match self {
103            Self::Lock(_) => RTAX_LOCK,
104            Self::Mtu(_) => RTAX_MTU,
105            Self::Window(_) => RTAX_WINDOW,
106            Self::Rtt(_) => RTAX_RTT,
107            Self::RttVar(_) => RTAX_RTTVAR,
108            Self::SsThresh(_) => RTAX_SSTHRESH,
109            Self::Cwnd(_) => RTAX_CWND,
110            Self::Advmss(_) => RTAX_ADVMSS,
111            Self::Reordering(_) => RTAX_REORDERING,
112            Self::Hoplimit(_) => RTAX_HOPLIMIT,
113            Self::InitCwnd(_) => RTAX_INITCWND,
114            Self::Features(_) => RTAX_FEATURES,
115            Self::RtoMin(_) => RTAX_RTO_MIN,
116            Self::InitRwnd(_) => RTAX_INITRWND,
117            Self::QuickAck(_) => RTAX_QUICKACK,
118            Self::CcAlgo(_) => RTAX_CC_ALGO,
119            Self::FastopenNoCookie(_) => RTAX_FASTOPEN_NO_COOKIE,
120            Self::Other(attr) => attr.kind(),
121        }
122    }
123}
124
125impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for RouteMetric {
126    type Error = RouteError;
127    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, RouteError> {
128        let payload = buf.value();
129        Ok(match buf.kind() {
130            RTAX_LOCK => Self::Lock(
131                parse_u32(payload)
132                    .map_err(|error| RouteError::InvalidRouteMetric { kind: "RTAX_LOCK", error })?,
133            ),
134            RTAX_MTU => Self::Mtu(
135                parse_u32(payload)
136                    .map_err(|error| RouteError::InvalidRouteMetric { kind: "RTAX_MTU", error })?,
137            ),
138            RTAX_WINDOW => {
139                Self::Window(parse_u32(payload).map_err(|error| {
140                    RouteError::InvalidRouteMetric { kind: "RTAX_WINDOW", error }
141                })?)
142            }
143            RTAX_RTT => Self::Rtt(
144                parse_u32(payload)
145                    .map_err(|error| RouteError::InvalidRouteMetric { kind: "RTAX_RTT", error })?,
146            ),
147            RTAX_RTTVAR => {
148                Self::RttVar(parse_u32(payload).map_err(|error| {
149                    RouteError::InvalidRouteMetric { kind: "RTAX_RTTVAR", error }
150                })?)
151            }
152            RTAX_SSTHRESH => Self::SsThresh(parse_u32(payload).map_err(|error| {
153                RouteError::InvalidRouteMetric { kind: "RTAX_SSHTHRESH", error }
154            })?),
155            RTAX_CWND => Self::Cwnd(
156                parse_u32(payload)
157                    .map_err(|error| RouteError::InvalidRouteMetric { kind: "RTAX_CWND", error })?,
158            ),
159            RTAX_ADVMSS => {
160                Self::Advmss(parse_u32(payload).map_err(|error| {
161                    RouteError::InvalidRouteMetric { kind: "RTAX_ADVMSS", error }
162                })?)
163            }
164            RTAX_REORDERING => Self::Reordering(parse_u32(payload).map_err(|error| {
165                RouteError::InvalidRouteMetric { kind: "RTAX_REORDERING", error }
166            })?),
167            RTAX_HOPLIMIT => Self::Hoplimit(parse_u32(payload).map_err(|error| {
168                RouteError::InvalidRouteMetric { kind: "RTAX_HOPLIMIT", error }
169            })?),
170            RTAX_INITCWND => Self::InitCwnd(parse_u32(payload).map_err(|error| {
171                RouteError::InvalidRouteMetric { kind: "RTAX_INITCWND", error }
172            })?),
173            RTAX_FEATURES => Self::Features(parse_u32(payload).map_err(|error| {
174                RouteError::InvalidRouteMetric { kind: "RTAX_FEATURES", error }
175            })?),
176            RTAX_RTO_MIN => {
177                Self::RtoMin(parse_u32(payload).map_err(|error| {
178                    RouteError::InvalidRouteMetric { kind: "RTAX_RTO_MIN", error }
179                })?)
180            }
181            RTAX_INITRWND => Self::InitRwnd(parse_u32(payload).map_err(|error| {
182                RouteError::InvalidRouteMetric { kind: "RTAX_INITRWND", error }
183            })?),
184            RTAX_QUICKACK => Self::QuickAck(parse_u32(payload).map_err(|error| {
185                RouteError::InvalidRouteMetric { kind: "RTAX_QUICKACK", error }
186            })?),
187            RTAX_CC_ALGO => {
188                Self::CcAlgo(parse_u32(payload).map_err(|error| {
189                    RouteError::InvalidRouteMetric { kind: "RTAX_CC_ALGO", error }
190                })?)
191            }
192            RTAX_FASTOPEN_NO_COOKIE => {
193                Self::FastopenNoCookie(parse_u32(payload).map_err(|error| {
194                    RouteError::InvalidRouteMetric { kind: "RTAX_FASTOPEN_NO_COOKIE", error }
195                })?)
196            }
197            _ => {
198                Self::Other(DefaultNla::parse(buf).map_err(|error| {
199                    RouteError::InvalidRouteMetric { kind: "NLA unkwnon", error }
200                })?)
201            }
202        })
203    }
204}
205
206pub(crate) struct VecRouteMetric(pub(crate) Vec<RouteMetric>);
207
208impl<T: AsRef<[u8]> + ?Sized> Parseable<T> for VecRouteMetric {
209    type Error = RouteError;
210    fn parse(payload: &T) -> Result<Self, RouteError> {
211        let mut nlas = vec![];
212        for nla in NlasIterator::new(payload) {
213            nlas.push(RouteMetric::parse(&nla?)?);
214        }
215        Ok(Self(nlas))
216    }
217}