1use futures::{
4 future::{self, Either},
5 stream::{Stream, StreamExt},
6 FutureExt,
7};
8use netlink_packet_core::{NetlinkMessage, NLM_F_DUMP, NLM_F_REQUEST};
9use netlink_packet_route::{
10 route::{RouteAttribute, RouteMessage},
11 AddressFamily, RouteNetlinkMessage,
12};
13
14use crate::{try_rtnl, Error, Handle};
15
16#[derive(Debug, Clone)]
17pub struct RouteGetRequest {
18 handle: Handle,
19 message: RouteMessage,
20}
21
22#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]
24pub enum IpVersion {
25 V4,
27 V6,
29}
30
31impl IpVersion {
32 pub(crate) fn family(self) -> AddressFamily {
33 match self {
34 IpVersion::V4 => AddressFamily::Inet,
35 IpVersion::V6 => AddressFamily::Inet6,
36 }
37 }
38}
39
40impl RouteGetRequest {
41 pub(crate) fn new(handle: Handle, message: RouteMessage) -> Self {
42 RouteGetRequest { handle, message }
43 }
44
45 pub fn message_mut(&mut self) -> &mut RouteMessage {
46 &mut self.message
47 }
48
49 pub fn execute(self) -> impl Stream<Item = Result<RouteMessage, Error>> {
50 let RouteGetRequest {
51 mut handle,
52 message,
53 } = self;
54
55 let has_dest = message
56 .attributes
57 .iter()
58 .any(|attr| matches!(attr, RouteAttribute::Destination(_)));
59
60 let mut req =
61 NetlinkMessage::from(RouteNetlinkMessage::GetRoute(message));
62 req.header.flags = NLM_F_REQUEST;
63
64 if !has_dest {
65 req.header.flags |= NLM_F_DUMP;
66 }
67
68 match handle.request(req) {
69 Ok(response) => Either::Left(response.map(move |msg| {
70 Ok(try_rtnl!(msg, RouteNetlinkMessage::NewRoute))
71 })),
72 Err(e) => Either::Right(
73 future::err::<RouteMessage, Error>(e).into_stream(),
74 ),
75 }
76 }
77}