rtnetlink/link/
get.rs

1// SPDX-License-Identifier: MIT
2
3use futures_util::{
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    link::{LinkAttribute, LinkExtentMask, LinkMessage},
11    AddressFamily, RouteNetlinkMessage,
12};
13
14use crate::{try_rtnl, Error, Handle};
15
16pub struct LinkGetRequest {
17    handle: Handle,
18    message: LinkMessage,
19    // There are two ways to retrieve links: we can either dump them
20    // all and filter the result, or if we already know the index or
21    // the name of the link we're looking for, we can just retrieve
22    // that one. If `dump` is `true`, all the links are fetched.
23    // Otherwise, only the link that match the given index or name
24    // is fetched.
25    dump: bool,
26}
27
28impl LinkGetRequest {
29    pub(crate) fn new(handle: Handle) -> Self {
30        LinkGetRequest {
31            handle,
32            message: LinkMessage::default(),
33            dump: true,
34        }
35    }
36
37    /// Setting filter mask
38    pub fn set_filter_mask(
39        mut self,
40        family: AddressFamily,
41        filter_mask: Vec<LinkExtentMask>,
42    ) -> Self {
43        self.message.header.interface_family = family;
44        self.message
45            .attributes
46            .push(LinkAttribute::ExtMask(filter_mask));
47        self
48    }
49
50    /// Execute the request
51    pub fn execute(self) -> impl Stream<Item = Result<LinkMessage, Error>> {
52        let LinkGetRequest {
53            mut handle,
54            message,
55            dump,
56        } = self;
57
58        let mut req =
59            NetlinkMessage::from(RouteNetlinkMessage::GetLink(message));
60
61        if dump {
62            req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;
63        } else {
64            req.header.flags = NLM_F_REQUEST;
65        }
66
67        match handle.request(req) {
68            Ok(response) => Either::Left(response.map(move |msg| {
69                Ok(try_rtnl!(msg, RouteNetlinkMessage::NewLink))
70            })),
71            Err(e) => Either::Right(
72                future::err::<LinkMessage, Error>(e).into_stream(),
73            ),
74        }
75    }
76
77    /// Return a mutable reference to the request
78    pub fn message_mut(&mut self) -> &mut LinkMessage {
79        &mut self.message
80    }
81
82    /// Lookup a link by index
83    pub fn match_index(mut self, index: u32) -> Self {
84        self.dump = false;
85        self.message.header.index = index;
86        self
87    }
88
89    /// Lookup a link by name
90    ///
91    /// This function requires support from your kernel (>= 2.6.33). If yours is
92    /// older, consider filtering the resulting stream of links.
93    pub fn match_name(mut self, name: String) -> Self {
94        self.dump = false;
95        self.message.attributes.push(LinkAttribute::IfName(name));
96        self
97    }
98}