Skip to content

Add a builder for route messages #57

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

Merged
merged 2 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions examples/add_route.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT

use std::env;
use std::{env, net::Ipv4Addr};

use ipnetwork::Ipv4Network;
use rtnetlink::{new_connection, Error, Handle};
use rtnetlink::{new_connection, Error, Handle, RouteMessageBuilder};

const TEST_TABLE_ID: u32 = 299;

Expand Down Expand Up @@ -40,15 +40,12 @@ async fn add_route(
gateway: &Ipv4Network,
handle: Handle,
) -> Result<(), Error> {
let route = handle.route();
route
.add()
.v4()
let route = RouteMessageBuilder::<Ipv4Addr>::new()
.destination_prefix(dest.ip(), dest.prefix())
.gateway(gateway.ip())
.table_id(TEST_TABLE_ID)
.execute()
.await?;
.build();
handle.route().add(route).execute().await?;
Ok(())
}

Expand Down
11 changes: 4 additions & 7 deletions examples/add_route_pref_src.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use futures::TryStreamExt;
use std::{env, net::Ipv4Addr};

use ipnetwork::Ipv4Network;
use rtnetlink::{new_connection, Error, Handle};
use rtnetlink::{new_connection, Error, Handle, RouteMessageBuilder};

#[tokio::main]
async fn main() -> Result<(), ()> {
Expand Down Expand Up @@ -53,15 +53,12 @@ async fn add_route(
.header
.index;

let route = handle.route();
route
.add()
.v4()
let route = RouteMessageBuilder::<Ipv4Addr>::new()
.destination_prefix(dest.ip(), dest.prefix())
.output_interface(iface_idx)
.pref_source(source)
.execute()
.await?;
.build();
handle.route().add(route).execute().await?;
Ok(())
}

Expand Down
11 changes: 9 additions & 2 deletions examples/listen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
use futures::stream::StreamExt;
use netlink_sys::{AsyncSocket, SocketAddr};
use rtnetlink::{
constants::{RTMGRP_IPV4_ROUTE, RTMGRP_IPV6_ROUTE},
constants::{
RTMGRP_IPV4_IFADDR, RTMGRP_IPV4_ROUTE, RTMGRP_IPV6_IFADDR,
RTMGRP_IPV6_ROUTE, RTMGRP_LINK,
},
new_connection,
};

Expand All @@ -18,7 +21,11 @@ async fn main() -> Result<(), String> {

// These flags specify what kinds of broadcast messages we want to listen
// for.
let mgroup_flags = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
let mgroup_flags = RTMGRP_LINK
| RTMGRP_IPV4_IFADDR
| RTMGRP_IPV4_ROUTE
| RTMGRP_IPV6_IFADDR
| RTMGRP_IPV6_ROUTE;

// A netlink socket address is created with said flags.
let addr = SocketAddr::new(0, mgroup_flags);
Expand Down
196 changes: 6 additions & 190 deletions src/route/add.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,27 @@
// SPDX-License-Identifier: MIT

use futures::stream::StreamExt;
use std::{
marker::PhantomData,
net::{Ipv4Addr, Ipv6Addr},
};
use std::{marker::PhantomData, net::IpAddr};

use netlink_packet_core::{
NetlinkMessage, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REPLACE,
NLM_F_REQUEST,
};
use netlink_packet_route::{
route::{
RouteAddress, RouteAttribute, RouteHeader, RouteMessage, RouteProtocol,
RouteScope, RouteType,
},
AddressFamily, RouteNetlinkMessage,
};
use netlink_packet_route::{route::RouteMessage, RouteNetlinkMessage};

use crate::{try_nl, Error, Handle};

/// A request to create a new route. This is equivalent to the `ip route add`
/// commands.
pub struct RouteAddRequest<T = ()> {
pub struct RouteAddRequest<T = IpAddr> {
handle: Handle,
message: RouteMessage,
replace: bool,
_phantom: PhantomData<T>,
}

impl<T> RouteAddRequest<T> {
pub(crate) fn new(handle: Handle) -> Self {
let mut message = RouteMessage::default();

message.header.table = RouteHeader::RT_TABLE_MAIN;
message.header.protocol = RouteProtocol::Static;
message.header.scope = RouteScope::Universe;
message.header.kind = RouteType::Unicast;

pub(crate) fn new(handle: Handle, message: RouteMessage) -> Self {
RouteAddRequest {
handle,
message,
Expand All @@ -46,91 +30,8 @@ impl<T> RouteAddRequest<T> {
}
}

/// Sets the input interface index.
pub fn input_interface(mut self, index: u32) -> Self {
self.message.attributes.push(RouteAttribute::Iif(index));
self
}

/// Sets the output interface index.
pub fn output_interface(mut self, index: u32) -> Self {
self.message.attributes.push(RouteAttribute::Oif(index));
self
}

/// Sets the route priority (metric)
pub fn priority(mut self, priority: u32) -> Self {
self.message
.attributes
.push(RouteAttribute::Priority(priority));
self
}

/// Sets the route table.
///
/// Default is main route table.
#[deprecated(note = "Please use `table_id` instead")]
pub fn table(mut self, table: u8) -> Self {
self.message.header.table = table;
self
}

/// Sets the route table ID.
///
/// Default is main route table.
pub fn table_id(mut self, table: u32) -> Self {
if table > 255 {
self.message.attributes.push(RouteAttribute::Table(table));
} else {
self.message.header.table = table as u8;
}
self
}

/// Sets the route protocol.
///
/// Default is static route protocol.
pub fn protocol(mut self, protocol: RouteProtocol) -> Self {
self.message.header.protocol = protocol;
self
}

/// Sets the route scope.
///
/// Default is universe route scope.
pub fn scope(mut self, scope: RouteScope) -> Self {
self.message.header.scope = scope;
self
}

/// Sets the route kind.
///
/// Default is unicast route kind.
pub fn kind(mut self, kind: RouteType) -> Self {
self.message.header.kind = kind;
self
}

/// Build an IP v4 route request
pub fn v4(mut self) -> RouteAddRequest<Ipv4Addr> {
self.message.header.address_family = AddressFamily::Inet;
RouteAddRequest {
handle: self.handle,
message: self.message,
replace: false,
_phantom: Default::default(),
}
}

/// Build an IP v6 route request
pub fn v6(mut self) -> RouteAddRequest<Ipv6Addr> {
self.message.header.address_family = AddressFamily::Inet6;
RouteAddRequest {
handle: self.handle,
message: self.message,
replace: false,
_phantom: Default::default(),
}
pub fn message_mut(&mut self) -> &mut RouteMessage {
&mut self.message
}

/// Replace existing matching route.
Expand Down Expand Up @@ -160,89 +61,4 @@ impl<T> RouteAddRequest<T> {
}
Ok(())
}

/// Return a mutable reference to the request message.
pub fn message_mut(&mut self) -> &mut RouteMessage {
&mut self.message
}
}

impl RouteAddRequest<Ipv4Addr> {
/// Sets the source address prefix.
pub fn source_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {
self.message.header.source_prefix_length = prefix_length;
self.message
.attributes
.push(RouteAttribute::Source(RouteAddress::Inet(addr)));
self
}

/// Sets the preferred source address.
pub fn pref_source(mut self, addr: Ipv4Addr) -> Self {
self.message
.attributes
.push(RouteAttribute::PrefSource(RouteAddress::Inet(addr)));
self
}

/// Sets the destination address prefix.
pub fn destination_prefix(
mut self,
addr: Ipv4Addr,
prefix_length: u8,
) -> Self {
self.message.header.destination_prefix_length = prefix_length;
self.message
.attributes
.push(RouteAttribute::Destination(RouteAddress::Inet(addr)));
self
}

/// Sets the gateway (via) address.
pub fn gateway(mut self, addr: Ipv4Addr) -> Self {
self.message
.attributes
.push(RouteAttribute::Gateway(RouteAddress::Inet(addr)));
self
}
}

impl RouteAddRequest<Ipv6Addr> {
/// Sets the source address prefix.
pub fn source_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {
self.message.header.source_prefix_length = prefix_length;
self.message
.attributes
.push(RouteAttribute::Source(RouteAddress::Inet6(addr)));
self
}

/// Sets the preferred source address.
pub fn pref_source(mut self, addr: Ipv6Addr) -> Self {
self.message
.attributes
.push(RouteAttribute::PrefSource(RouteAddress::Inet6(addr)));
self
}

/// Sets the destination address prefix.
pub fn destination_prefix(
mut self,
addr: Ipv6Addr,
prefix_length: u8,
) -> Self {
self.message.header.destination_prefix_length = prefix_length;
self.message
.attributes
.push(RouteAttribute::Destination(RouteAddress::Inet6(addr)));
self
}

/// Sets the gateway (via) address.
pub fn gateway(mut self, addr: Ipv6Addr) -> Self {
self.message
.attributes
.push(RouteAttribute::Gateway(RouteAddress::Inet6(addr)));
self
}
}
Loading
Loading