-
Notifications
You must be signed in to change notification settings - Fork 58
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
Route get supports querying the route tables #23
base: main
Are you sure you want to change the base?
Conversation
}; | ||
|
||
use crate::{try_rtnl, Error, Handle}; | ||
|
||
pub struct RouteGetRequest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like the generic struct is not required here, you can just use the generic function parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The generic parameter on the struct prevent the user from calling to(ipv6_ipaddr)
on an ipv4 RouteGetRequest because it would result in an unsupported rtnetlink request. Once the RouteGetRequest<()>
is specialized into a RouteGetRequest<Ipv4Addr>
, you can only pass it ipv4 addresses when calling to
and from
. This is enforced by the type system, and there is no way for the user to turn it into a RouteGetRequest<Ipv6Addr>
.
Moving the generics on the function instead would not prevent the user to create a RouteGetRequest
, call to::<Ipv4Addr>(dest_ip)
and then from::<Ipv6Addr>(source_ip)
, which is invalid.
This looks similar to #20 . Please try not not break API. |
@Orycterope This break the API which is widely used, can we find a way for this without breaking API? |
@Orycterope ping again |
I like these changes and would like to use them. Could you please indicate more clear, what API has been broken? Maybe I could've fixed it. |
Closes #22
This MR adds support for querying the route tables for the best route to a given destination, which as of now only supports dumping all route tables.
Design
The idea behind the design is pretty simple and inspired by what route::add and neighbour::get do: the user gets a
RouteRequest<()>
from the handle, which they must specialize into either aRouteRequest<Ipv4Addr>
orRouteRequest<Ipv6Addr>
by callingv4()
orv6()
before being able to callexecute()
. Once specialized, the user can optionally add a destination address, but only of the same address family as the generic parameter (you can't put a ipv6 destination inRouteRequest<Ipv4Addr>
). Doing this will turn the request into a lookup request instead of dump request.Unfortunately, this design introduces a change to the API for the user, and will require a version bump.
It also adds a new
examples/get_route_to.rs
example to showcase this use case.execute()
opaque return typeWhile writing this PR, I faced a lot of troubles related to opaque types. Like all other requests in this crate,
RouteRequest::execute()
used to return a opaqueimpl TryStream<Ok = RouteMessage, Error = Error>
. This becomes a problem if the user tries to handle ipv4 and ipv6 in a single code path, like so:Because
RouteRequest
is now generic, the return type ofRouteRequest<Ipv4Addr>
andRouteRequest<Ipv6Addr>
are no longer the same concrete type, even though they have the exact same opaque type signature. Because of this, the two match arms differ in type, androutes
cannot have a valid type.The only way I found around this problem is dynamic dispatch, which means asking the user to turn the concrete opaque type returned by
execute()
into aBox<dyn TryStream<...>>
in both match arms. But for that the user has to write the full type signature of the trait, including the associated typeSteam::Item
which is erased in the returned opaque type, and this unprovable constraint makes rustc refuse to compile.I solved this by changing the opaque type returned by
execute()
into a simpler opaqueimpl Stream<Item = Result<...>>
, which automatically implementsTryStream
anyway, so this is transparent for the user.The final solution is
which I'm not super happy about, because it asks the user to write a complicated dyn type.
Another solution would have been to make
RouteRequest
an exception, and haveexecute()
return aBox<Stream<Item = ...>
.