netlink_packet_route/rtnl/route/nlas/
next_hops.rs1use anyhow::Context;
4use std::net::IpAddr;
5
6use crate::{
7 constants,
8 nlas::{NlaBuffer, NlasIterator},
9 parsers::parse_ip,
10 route::nlas::Nla,
11 traits::{Emitable, Parseable},
12 DecodeError,
13};
14
15bitflags! {
16 pub struct NextHopFlags: u8 {
17 const RTNH_F_EMPTY = 0;
18 const RTNH_F_DEAD = constants::RTNH_F_DEAD as u8;
19 const RTNH_F_PERVASIVE = constants::RTNH_F_PERVASIVE as u8;
20 const RTNH_F_ONLINK = constants::RTNH_F_ONLINK as u8;
21 const RTNH_F_OFFLOAD = constants::RTNH_F_OFFLOAD as u8;
22 const RTNH_F_LINKDOWN = constants::RTNH_F_LINKDOWN as u8;
23 const RTNH_F_UNRESOLVED = constants::RTNH_F_UNRESOLVED as u8;
24 }
25}
26
27const PAYLOAD_OFFSET: usize = 8;
28
29buffer!(NextHopBuffer {
30 length: (u16, 0..2),
31 flags: (u8, 2),
32 hops: (u8, 3),
33 interface_id: (u32, 4..8),
34 payload: (slice, PAYLOAD_OFFSET..),
35});
36
37impl<T: AsRef<[u8]>> NextHopBuffer<T> {
38 pub fn new_checked(buffer: T) -> Result<Self, DecodeError> {
39 let packet = Self::new(buffer);
40 packet.check_buffer_length()?;
41 Ok(packet)
42 }
43
44 fn check_buffer_length(&self) -> Result<(), DecodeError> {
45 let len = self.buffer.as_ref().len();
46 if len < PAYLOAD_OFFSET {
47 return Err(
48 format!("invalid NextHopBuffer: length {} < {}", len, PAYLOAD_OFFSET).into(),
49 );
50 }
51 if len < self.length() as usize {
52 return Err(format!(
53 "invalid NextHopBuffer: length {} < {}",
54 len,
55 8 + self.length()
56 )
57 .into());
58 }
59 Ok(())
60 }
61}
62
63impl<'a, T: AsRef<[u8]> + ?Sized> NextHopBuffer<&'a T> {
64 pub fn nlas(&self) -> impl Iterator<Item = Result<NlaBuffer<&'a [u8]>, DecodeError>> {
65 NlasIterator::new(&self.payload()[..(self.length() as usize - PAYLOAD_OFFSET)])
66 }
67}
68
69#[derive(Debug, Clone, Eq, PartialEq)]
70pub struct NextHop {
71 pub flags: NextHopFlags,
73 pub hops: u8,
75 pub interface_id: u32,
77 pub nlas: Vec<Nla>,
79}
80
81impl<'a, T: AsRef<[u8]>> Parseable<NextHopBuffer<&'a T>> for NextHop {
82 fn parse(buf: &NextHopBuffer<&T>) -> Result<NextHop, DecodeError> {
83 let nlas = Vec::<Nla>::parse(
84 &NextHopBuffer::new_checked(buf.buffer)
85 .context("cannot parse route attributes in next-hop")?,
86 )
87 .context("cannot parse route attributes in next-hop")?;
88 Ok(NextHop {
89 flags: NextHopFlags::from_bits_truncate(buf.flags()),
90 hops: buf.hops(),
91 interface_id: buf.interface_id(),
92 nlas,
93 })
94 }
95}
96
97impl<'a, T: AsRef<[u8]> + 'a> Parseable<NextHopBuffer<&'a T>> for Vec<Nla> {
98 fn parse(buf: &NextHopBuffer<&'a T>) -> Result<Self, DecodeError> {
99 let mut nlas = vec![];
100 for nla_buf in buf.nlas() {
101 nlas.push(Nla::parse(&nla_buf?)?);
102 }
103 Ok(nlas)
104 }
105}
106
107impl Emitable for NextHop {
108 fn buffer_len(&self) -> usize {
109 PAYLOAD_OFFSET + self.nlas.as_slice().buffer_len()
111 }
112
113 fn emit(&self, buffer: &mut [u8]) {
114 let mut nh_buffer = NextHopBuffer::new(buffer);
115 nh_buffer.set_length(self.buffer_len() as u16);
116 nh_buffer.set_flags(self.flags.bits());
117 nh_buffer.set_hops(self.hops);
118 nh_buffer.set_interface_id(self.interface_id);
119 self.nlas.as_slice().emit(nh_buffer.payload_mut())
120 }
121}
122
123impl NextHop {
124 pub fn gateway(&self) -> Option<IpAddr> {
126 self.nlas.iter().find_map(|nla| {
127 if let Nla::Gateway(ip) = nla {
128 parse_ip(ip).ok()
129 } else {
130 None
131 }
132 })
133 }
134}