Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support ip route get #86

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Conversation

hack3ric
Copy link

Rework of #23. Only adds RouteGetRequest::dump option, where specifying req.dump(false) will mimic the behaviour of ip route get, and replacing impl TryStream with impl Stream<Item = Result<...>>. There is no breaking change.

@nhed
Copy link

nhed commented Dec 26, 2024

Any idea bout the status f this PR?
I need ip route get functionality and hacked out the dump locally.

@hack3ric
Copy link
Author

Seems the maintainer has been inactive for some time on this repo, so we have to either wait or fork.

@nhed
Copy link

nhed commented Dec 26, 2024

not sure if valuable - but as an alternate to adding a dump variable at construction time I thought it might make sense to drive this behavior by the presence of a destination attribute.

If destination attribute was added (as one would have to to obtain a route) user is looking for a single route
otherwise - dump all the routes

diff --git a/src/route/get.rs b/src/route/get.rs
index a938532..68f27bf 100644
--- a/src/route/get.rs
+++ b/src/route/get.rs
@@ -11,7 +11,7 @@ use netlink_packet_route::{
     route::RouteMessage, AddressFamily, RouteNetlinkMessage,
 };
 
-use crate::{try_rtnl, Error, Handle};
+use crate::{try_rtnl, Error, Handle, packet_route::route::RouteAttribute};
 
 pub struct RouteGetRequest {
     handle: Handle,
@@ -51,9 +51,14 @@ impl RouteGetRequest {
             message,
         } = self;
 
+        let has_dest = message.attributes.iter().any(|attr| match attr {
+            RouteAttribute::Destination(_) => true,
+            _ => false,
+        });
+
         let mut req =
             NetlinkMessage::from(RouteNetlinkMessage::GetRoute(message));
-        req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;
+        req.header.flags = NLM_F_REQUEST | if has_dest { 0 } else { NLM_F_DUMP };
 
         match handle.request(req) {
             Ok(response) => Either::Left(response.map(move |msg| {

edit: slightly cleaner version of ^^

diff --git a/src/route/get.rs b/src/route/get.rs
index a938532..3e61f29 100644
--- a/src/route/get.rs
+++ b/src/route/get.rs
@@ -11,7 +11,7 @@ use netlink_packet_route::{
     route::RouteMessage, AddressFamily, RouteNetlinkMessage,
 };
 
-use crate::{try_rtnl, Error, Handle};
+use crate::{packet_route::route::RouteAttribute, try_rtnl, Error, Handle};
 
 pub struct RouteGetRequest {
     handle: Handle,
@@ -51,9 +51,18 @@ impl RouteGetRequest {
             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 | NLM_F_DUMP;
+        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| {

@nhed
Copy link

nhed commented Dec 27, 2024

My rust is not so great - so I wasn't able to use your fix - so you have an example of how you would modify the existing examples? Reading your commit message I tried this but dump is just a field, not an access method.

+++ b/examples/get_route.rs
@@ -35,7 +35,7 @@ async fn dump_addresses(
         IpVersion::V4 => RouteMessageBuilder::<Ipv4Addr>::new().build(),
         IpVersion::V6 => RouteMessageBuilder::<Ipv6Addr>::new().build(),
     };
-    let mut routes = handle.route().get(route).execute();
+    let mut routes = handle.route().get(route).dump(false).execute();
     while let Some(route) = routes.try_next().await? {
         println!("{route:?}");
     }

yielding

error[E0599]: no method named `dump` found for struct `RouteGetRequest` in the current scope
  --> examples/get_route.rs:38:48
   |
38 |     let mut routes = handle.route().get(route).dump(false).execute();
   |                                                ^^^^ private field, not a method

Feels like one would need to add an access method, might just make my own temporary for till that clears up as the solution I outlined in the prior comment works transparently

@hack3ric
Copy link
Author

Oops, seems like I somehow missed .dump() method when cherry-picking from my own branch. Fixed now. Thanks for the review!

If destination attribute was added (as one would have to to obtain a route) user is looking for a single route otherwise - dump all the routes

This definitely seems feasible! I wonder if there are corner cases, though. I will integrate your changes and mention you in the commit message when I am less busy (or create a new PR superseding this one) :)

@nhed
Copy link

nhed commented Dec 27, 2024

I will integrate your changes

if you do please note i updated my comment with slightly cleaner code

…specified

We can have the behaviour of `ip route get` now.

Co-Developed-By: Nevo Hed <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants