use futures_util::{
future::{self, Either},
stream::{Stream, StreamExt},
FutureExt,
};
use netlink_packet_core::{NetlinkMessage, NLM_F_DUMP, NLM_F_REQUEST};
use netlink_packet_route::{
route::{RouteAttribute, RouteMessage},
AddressFamily, RouteNetlinkMessage,
};
use crate::{try_rtnl, Error, Handle};
#[derive(Debug, Clone)]
pub struct RouteGetRequest {
handle: Handle,
message: RouteMessage,
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]
pub enum IpVersion {
V4,
V6,
}
impl IpVersion {
pub(crate) fn family(self) -> AddressFamily {
match self {
IpVersion::V4 => AddressFamily::Inet,
IpVersion::V6 => AddressFamily::Inet6,
}
}
}
impl RouteGetRequest {
pub(crate) fn new(handle: Handle, message: RouteMessage) -> Self {
RouteGetRequest { handle, message }
}
pub fn message_mut(&mut self) -> &mut RouteMessage {
&mut self.message
}
pub fn execute(self) -> impl Stream<Item = Result<RouteMessage, Error>> {
let RouteGetRequest {
mut handle,
message,
} = self;
let has_dest = message
.attributes
.iter()
.any(|attr| matches!(attr, RouteAttribute::Destination(_)));
let mut req =
NetlinkMessage::from(RouteNetlinkMessage::GetRoute(message));
req.header.flags = NLM_F_REQUEST;
if !has_dest {
req.header.flags |= NLM_F_DUMP;
}
match handle.request(req) {
Ok(response) => Either::Left(response.map(move |msg| {
Ok(try_rtnl!(msg, RouteNetlinkMessage::NewRoute))
})),
Err(e) => Either::Right(
future::err::<RouteMessage, Error>(e).into_stream(),
),
}
}
}