Skip to content

Commit 8e0e9ce

Browse files
committed
route: add support for multipath routes
Add support for configuring multipath (ECMP) routes. This includes a new `RouteNextHopBuilder` for creating nexthop entries with various attributes. `RouteMessageBuilder` now has a `multipath()` method to attach multiple nexthops using the `RTA_MULTIPATH` attribute. Signed-off-by: Renato Westphal <[email protected]>
1 parent 23fddd5 commit 8e0e9ce

File tree

3 files changed

+85
-2
lines changed

3 files changed

+85
-2
lines changed

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub use crate::neighbour::{
4848
pub use crate::ns::{NetworkNamespace, NETNS_PATH, NONE_FS, SELF_NS_PATH};
4949
pub use crate::route::{
5050
IpVersion, RouteAddRequest, RouteDelRequest, RouteGetRequest, RouteHandle,
51-
RouteMessageBuilder,
51+
RouteMessageBuilder, RouteNextHopBuilder,
5252
};
5353
pub use crate::rule::{
5454
RuleAddRequest, RuleDelRequest, RuleGetRequest, RuleHandle,

src/route/builder.rs

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use netlink_packet_route::{
99
route::{
1010
MplsLabel, RouteAddress, RouteAttribute, RouteFlags, RouteHeader,
1111
RouteLwEnCapType, RouteLwTunnelEncap, RouteMessage, RouteMplsIpTunnel,
12-
RouteProtocol, RouteScope, RouteType,
12+
RouteNextHop, RouteNextHopFlags, RouteProtocol, RouteScope, RouteType,
13+
RouteVia,
1314
},
1415
AddressFamily,
1516
};
@@ -20,6 +21,12 @@ pub struct RouteMessageBuilder<T = IpAddr> {
2021
_phantom: PhantomData<T>,
2122
}
2223

24+
#[derive(Debug, Clone)]
25+
pub struct RouteNextHopBuilder {
26+
address_family: AddressFamily,
27+
nexthop: RouteNextHop,
28+
}
29+
2330
impl<T> RouteMessageBuilder<T> {
2431
/// Create default RouteMessage with header set to:
2532
/// * route: [RouteHeader::RT_TABLE_MAIN]
@@ -76,6 +83,14 @@ impl<T> RouteMessageBuilder<T> {
7683
self
7784
}
7885

86+
/// Sets multiple nexthop entries for the route.
87+
pub fn multipath(mut self, nexthops: Vec<RouteNextHop>) -> Self {
88+
self.message
89+
.attributes
90+
.push(RouteAttribute::MultiPath(nexthops));
91+
self
92+
}
93+
7994
/// Sets the route priority (metric)
8095
pub fn priority(mut self, priority: u32) -> Self {
8196
self.message
@@ -467,3 +482,70 @@ impl Default for RouteMessageBuilder<MplsLabel> {
467482
Self::new()
468483
}
469484
}
485+
486+
impl RouteNextHopBuilder {
487+
/// Create default RouteNexthop for a route with the given address family.
488+
pub fn new(address_family: AddressFamily) -> Self {
489+
Self {
490+
address_family,
491+
nexthop: Default::default(),
492+
}
493+
}
494+
495+
/// Sets the nexthop interface index.
496+
pub fn interface(mut self, index: u32) -> Self {
497+
self.nexthop.interface_index = index;
498+
self
499+
}
500+
501+
/// Sets the nexthop (via) address.
502+
pub fn via(mut self, addr: IpAddr) -> Result<Self, InvalidRouteMessage> {
503+
use AddressFamily::*;
504+
let attr = match (self.address_family, addr) {
505+
(Inet, addr @ IpAddr::V4(_)) | (Inet6, addr @ IpAddr::V6(_)) => {
506+
RouteAttribute::Gateway(addr.into())
507+
}
508+
(Inet, IpAddr::V6(v6)) => RouteAttribute::Via(RouteVia::Inet6(v6)),
509+
(Mpls, _) => RouteAttribute::Via(addr.into()),
510+
(af, _) => return Err(InvalidRouteMessage::AddressFamily(af)),
511+
};
512+
self.nexthop.attributes.push(attr);
513+
Ok(self)
514+
}
515+
516+
/// Marks the nexthop as directly reachable (on-link).
517+
///
518+
/// Indicates that the nexthop is reachable without passing through a
519+
/// connected subnet.
520+
pub fn onlink(mut self) -> Self {
521+
self.nexthop.flags.insert(RouteNextHopFlags::Onlink);
522+
self
523+
}
524+
525+
/// Sets the nexthop MPLS encapsulation labels.
526+
pub fn mpls(mut self, labels: Vec<MplsLabel>) -> Self {
527+
if labels.is_empty() {
528+
return self;
529+
}
530+
if self.address_family == AddressFamily::Mpls {
531+
self.nexthop
532+
.attributes
533+
.push(RouteAttribute::NewDestination(labels));
534+
} else {
535+
self.nexthop
536+
.attributes
537+
.push(RouteAttribute::EncapType(RouteLwEnCapType::Mpls));
538+
let encap = RouteLwTunnelEncap::Mpls(
539+
RouteMplsIpTunnel::Destination(labels),
540+
);
541+
self.nexthop
542+
.attributes
543+
.push(RouteAttribute::Encap(vec![encap]));
544+
}
545+
self
546+
}
547+
548+
pub fn build(self) -> RouteNextHop {
549+
self.nexthop
550+
}
551+
}

src/route/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod handle;
88

99
pub use self::add::RouteAddRequest;
1010
pub use self::builder::RouteMessageBuilder;
11+
pub use self::builder::RouteNextHopBuilder;
1112
pub use self::del::RouteDelRequest;
1213
pub use self::get::{IpVersion, RouteGetRequest};
1314
pub use self::handle::RouteHandle;

0 commit comments

Comments
 (0)