@@ -4,10 +4,11 @@ use crate::net::{Afi, IpPrefix};
44use crate :: util:: grace;
55use clap:: Args ;
66use futures:: channel:: mpsc:: UnboundedReceiver ;
7- use futures:: { try_join, StreamExt , TryStreamExt } ;
7+ use futures:: { try_join, StreamExt } ;
8+ use libc:: ENETUNREACH ;
89use rtnetlink:: packet_core:: { NetlinkMessage , NetlinkPayload } ;
910use rtnetlink:: packet_route:: address:: { AddressAttribute , AddressMessage } ;
10- use rtnetlink:: packet_route:: route:: { RouteAddress , RouteAttribute , RouteMessage , RouteVia } ;
11+ use rtnetlink:: packet_route:: route:: { RouteAddress , RouteAttribute , RouteMessage , RouteType , RouteVia } ;
1112use rtnetlink:: packet_route:: rule:: { RuleAction , RuleAttribute , RuleMessage } ;
1213use rtnetlink:: packet_route:: { AddressFamily , RouteNetlinkMessage } ;
1314use rtnetlink:: { Handle , RouteMessageBuilder } ;
@@ -28,7 +29,7 @@ pub struct RtNetlink<K: Kernel> {
2829 args : RtNetlinkArgs ,
2930 handle : Handle ,
3031 msgs : UnboundedReceiver < ( NetlinkMessage < RouteNetlinkMessage > , rtnetlink:: sys:: SocketAddr ) > ,
31- routes : BTreeMap < K :: Handle , ( IpPrefix , IpAddr , u32 , Vec < RouteAttribute > ) > ,
32+ routes : BTreeMap < K :: Handle , RouteEntry > ,
3233 rules : BTreeMap < u32 , BTreeSet < IpPrefix > > ,
3334 timer : Interval ,
3435}
@@ -80,7 +81,11 @@ impl<K: Kernel> RtNetlink<K> {
8081 . expect ( "destination prefix should be valid" )
8182 . table_id ( table_id)
8283 . build ( ) ;
83- msg. attributes . extend ( attrs. iter ( ) . cloned ( ) ) ;
84+ if let Some ( attrs) = & attrs {
85+ msg. attributes . extend ( attrs. iter ( ) . cloned ( ) ) ;
86+ } else {
87+ msg. header . kind = RouteType :: Unreachable ;
88+ } ;
8489 if let Err ( error) = self . handle . route ( ) . add ( msg) . execute ( ) . await {
8590 if table_created {
8691 self . rules . remove ( & table_id) ;
@@ -90,7 +95,7 @@ impl<K: Kernel> RtNetlink<K> {
9095 }
9196
9297 // ...and finally insert to our own database
93- self . routes . insert ( id, ( prefix, next_hop, table_id, attrs) ) ;
98+ self . routes . insert ( id, RouteEntry { prefix, next_hop, table_id, attrs } ) ;
9499
95100 Ok ( table_id)
96101 }
@@ -111,7 +116,7 @@ impl<K: Kernel> RtNetlink<K> {
111116 }
112117
113118 pub async fn del ( & mut self , id : & K :: Handle ) {
114- let Some ( ( prefix, _ , table_id, _ ) ) = self . routes . remove ( id) else {
119+ let Some ( RouteEntry { prefix, table_id, .. } ) = self . routes . remove ( id) else {
115120 return ;
116121 } ;
117122 self . del_route ( table_id, prefix) . await ;
@@ -156,6 +161,10 @@ impl<K: Kernel> RtNetlink<K> {
156161 ) ;
157162 }
158163
164+ pub fn is_empty ( & self ) -> bool {
165+ self . routes . is_empty ( )
166+ }
167+
159168 // route & addr change: check if next hop in changed prefix
160169 // rule change: full update for AF
161170 // link change: full update
@@ -219,67 +228,76 @@ impl<K: Kernel> RtNetlink<K> {
219228 }
220229 }
221230
222- pub fn is_empty ( & self ) -> bool {
223- self . routes . is_empty ( )
224- }
225-
226231 async fn process_prefix ( & mut self , prefix : IpPrefix ) -> Result < ( ) > {
227- Self :: process_iter ( & self . handle , self . routes . values_mut ( ) . filter ( |x| prefix. contains ( x. 1 ) ) ) . await
232+ Self :: process_iter (
233+ & self . handle ,
234+ self . routes . values_mut ( ) . filter ( |x| prefix. contains ( x. next_hop ) ) ,
235+ )
236+ . await
228237 }
238+
229239 async fn process_all ( & mut self ) -> Result < ( ) > {
230240 Self :: process_iter ( & self . handle , self . routes . values_mut ( ) ) . await
231241 }
232- async fn process_iter (
233- handle : & Handle ,
234- iter : impl Iterator < Item = & mut ( IpPrefix , IpAddr , u32 , Vec < RouteAttribute > ) > ,
235- ) -> Result < ( ) > {
242+
243+ async fn process_iter ( handle : & Handle , iter : impl Iterator < Item = & mut RouteEntry > ) -> Result < ( ) > {
236244 // TODO: remove route if next hop becomes unreachable
237- for ( prefix, next_hop, table_id, attrs) in iter {
238- let new_attrs = Self :: get_route2 ( handle, prefix. afi ( ) , * next_hop) . await ?;
245+ for RouteEntry { prefix, next_hop, table_id, attrs } in iter {
246+ let new_attrs = Self :: get_route_from_handle ( handle, prefix. afi ( ) , * next_hop) . await ?;
239247 if * attrs != new_attrs {
240248 * attrs = new_attrs. clone ( ) ;
241249 let mut msg = RouteMessageBuilder :: < IpAddr > :: new ( )
242250 . destination_prefix ( prefix. prefix ( ) , prefix. len ( ) )
243251 . expect ( "destination prefix should be valid" )
244252 . table_id ( * table_id)
245253 . build ( ) ;
246- msg. attributes . extend ( new_attrs) ;
254+ if let Some ( attrs) = & attrs {
255+ msg. attributes . extend ( attrs. iter ( ) . cloned ( ) ) ;
256+ } else {
257+ msg. header . kind = RouteType :: Unreachable ;
258+ } ;
247259 handle. route ( ) . add ( msg) . replace ( ) . execute ( ) . await ?;
248260 }
249261 }
250262 Ok ( ( ) )
251263 }
252264
253- async fn get_route ( & self , afi : Afi , ip : IpAddr ) -> Result < Vec < RouteAttribute > > {
254- Self :: get_route2 ( & self . handle , afi, ip) . await
265+ async fn get_route ( & self , afi : Afi , ip : IpAddr ) -> Result < Option < Vec < RouteAttribute > > > {
266+ Self :: get_route_from_handle ( & self . handle , afi, ip) . await
255267 }
256- async fn get_route2 ( handle : & Handle , afi : Afi , ip : IpAddr ) -> Result < Vec < RouteAttribute > > {
268+
269+ async fn get_route_from_handle ( handle : & Handle , prefix_afi : Afi , ip : IpAddr ) -> Result < Option < Vec < RouteAttribute > > > {
257270 let msg = RouteMessageBuilder :: < IpAddr > :: new ( )
258271 . destination_prefix ( ip, if ip. is_ipv4 ( ) { 32 } else { 128 } )
259272 . expect ( "destination prefix should be valid" )
260273 . build ( ) ;
261- let mut msg = handle. route ( ) . get ( msg) . execute ( ) ;
262- let Some ( rt) = msg. try_next ( ) . await ? else {
263- unreachable ! ( ) ;
274+ let rt = match handle. route ( ) . get ( msg) . execute ( ) . next ( ) . await . unwrap ( ) {
275+ Ok ( rt) => rt,
276+ Err ( rtnetlink:: Error :: NetlinkError ( error) ) if error. raw_code ( ) == ENETUNREACH => return Ok ( None ) ,
277+ Err ( error) => return Err ( error. into ( ) ) ,
264278 } ;
279+
265280 let mut has_gateway = false ;
266- let attrs = rt. attributes . into_iter ( ) . filter ( |x| {
267- if matches ! ( x, RouteAttribute :: Gateway ( _) | RouteAttribute :: Via ( _) ) {
268- has_gateway = true ;
269- true
270- } else {
271- matches ! ( x, RouteAttribute :: Oif ( _) )
272- }
273- } ) ;
274- let mut attrs: Vec < _ > = attrs. collect ( ) ;
281+ let mut attrs = rt
282+ . attributes
283+ . into_iter ( )
284+ . filter ( |x| {
285+ if matches ! ( x, RouteAttribute :: Gateway ( _) | RouteAttribute :: Via ( _) ) {
286+ has_gateway = true ;
287+ true
288+ } else {
289+ matches ! ( x, RouteAttribute :: Oif ( _) )
290+ }
291+ } )
292+ . collect :: < Vec < _ > > ( ) ;
275293 if !has_gateway {
276- if let ( Afi :: Ipv4 , IpAddr :: V6 ( v6) ) = ( afi , ip) {
294+ if let ( Afi :: Ipv4 , IpAddr :: V6 ( v6) ) = ( prefix_afi , ip) {
277295 attrs. push ( RouteAttribute :: Via ( RouteVia :: Inet6 ( v6) ) ) ;
278296 } else {
279297 attrs. push ( RouteAttribute :: Gateway ( ip. into ( ) ) ) ;
280298 }
281299 }
282- Ok ( attrs)
300+ Ok ( Some ( attrs) )
283301 }
284302
285303 pub async fn terminate ( self ) {
@@ -292,6 +310,14 @@ impl<K: Kernel> RtNetlink<K> {
292310 }
293311}
294312
313+ #[ derive( Debug , Clone ) ]
314+ pub struct RouteEntry {
315+ prefix : IpPrefix ,
316+ next_hop : IpAddr ,
317+ table_id : u32 ,
318+ attrs : Option < Vec < RouteAttribute > > ,
319+ }
320+
295321#[ derive( Debug , Clone , Args , Serialize , Deserialize ) ]
296322pub struct RtNetlinkArgs {
297323 /// Time between each routing table scan.
0 commit comments