Skip to content

Commit 1fe2569

Browse files
acst1223cathay4t
authored andcommitted
Create AddressMessageBuilder
Resolves #105. This change creates a builder that builds address messages for AddressAddRequest and AddressDelRequest. This simplifies the way to delete an IP address. Also creates an example for address deletion. This change does not introduce any crate API change.
1 parent 6485710 commit 1fe2569

File tree

5 files changed

+205
-39
lines changed

5 files changed

+205
-39
lines changed

examples/del_address.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use futures::stream::TryStreamExt;
4+
use std::{
5+
env,
6+
net::{IpAddr, Ipv4Addr, Ipv6Addr},
7+
};
8+
9+
use ipnetwork::IpNetwork;
10+
use rtnetlink::{new_connection, AddressMessageBuilder, Error, Handle};
11+
12+
#[tokio::main]
13+
async fn main() -> Result<(), ()> {
14+
let args: Vec<String> = env::args().collect();
15+
if args.len() != 3 {
16+
usage();
17+
return Ok(());
18+
}
19+
20+
let link_name = &args[1];
21+
let ip: IpNetwork = args[2].parse().unwrap_or_else(|_| {
22+
eprintln!("invalid address");
23+
std::process::exit(1);
24+
});
25+
26+
let (connection, handle, _) = new_connection().unwrap();
27+
tokio::spawn(connection);
28+
29+
if let Err(e) = del_address(link_name, ip, handle.clone()).await {
30+
eprintln!("{e}");
31+
}
32+
Ok(())
33+
}
34+
35+
async fn del_address(
36+
link_name: &str,
37+
ip: IpNetwork,
38+
handle: Handle,
39+
) -> Result<(), Error> {
40+
let mut links = handle
41+
.link()
42+
.get()
43+
.match_name(link_name.to_string())
44+
.execute();
45+
if let Some(link) = links.try_next().await? {
46+
let index = link.header.index;
47+
let address = ip.ip();
48+
let prefix_len = ip.prefix();
49+
let message = match address {
50+
IpAddr::V4(address) => AddressMessageBuilder::<Ipv4Addr>::new()
51+
.index(index)
52+
.address(address, prefix_len)
53+
.build(),
54+
IpAddr::V6(address) => AddressMessageBuilder::<Ipv6Addr>::new()
55+
.index(index)
56+
.address(address, prefix_len)
57+
.build(),
58+
};
59+
handle.address().del(message).execute().await?
60+
}
61+
Ok(())
62+
}
63+
64+
fn usage() {
65+
eprintln!(
66+
"usage:
67+
cargo run --example del_address -- <link_name> <ip_address>
68+
69+
Note that you need to run this program as root. Instead of running cargo as root,
70+
build the example normally:
71+
72+
cd rtnetlink ; cargo build --example del_address
73+
74+
Then find the binary in the target directory:
75+
76+
cd ../target/debug/example ; sudo ./del_address <link_name> <ip_address>"
77+
);
78+
}

src/addr/add.rs

Lines changed: 12 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
// SPDX-License-Identifier: MIT
22

33
use futures::stream::StreamExt;
4-
use std::net::{IpAddr, Ipv4Addr};
4+
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
55

66
use netlink_packet_core::{
77
NetlinkMessage, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REPLACE,
88
NLM_F_REQUEST,
99
};
1010

11-
use netlink_packet_route::{
12-
address::{AddressAttribute, AddressMessage},
13-
AddressFamily, RouteNetlinkMessage,
14-
};
11+
use netlink_packet_route::{address::AddressMessage, RouteNetlinkMessage};
1512

16-
use crate::{try_nl, Error, Handle};
13+
use crate::{addr::AddressMessageBuilder, try_nl, Error, Handle};
1714

1815
/// A request to create a new address. This is equivalent to the `ip address
1916
/// add` commands.
@@ -30,41 +27,17 @@ impl AddressAddRequest {
3027
address: IpAddr,
3128
prefix_len: u8,
3229
) -> Self {
33-
let mut message = AddressMessage::default();
34-
35-
message.header.prefix_len = prefix_len;
36-
message.header.index = index;
37-
38-
message.header.family = match address {
39-
IpAddr::V4(_) => AddressFamily::Inet,
40-
IpAddr::V6(_) => AddressFamily::Inet6,
30+
let message = match address {
31+
IpAddr::V4(address) => AddressMessageBuilder::<Ipv4Addr>::new()
32+
.index(index)
33+
.address(address, prefix_len)
34+
.build(),
35+
IpAddr::V6(address) => AddressMessageBuilder::<Ipv6Addr>::new()
36+
.index(index)
37+
.address(address, prefix_len)
38+
.build(),
4139
};
4240

43-
if address.is_multicast() {
44-
if let IpAddr::V6(a) = address {
45-
message.attributes.push(AddressAttribute::Multicast(a));
46-
}
47-
} else {
48-
message.attributes.push(AddressAttribute::Address(address));
49-
50-
// for IPv4 the IFA_LOCAL address can be set to the same value as
51-
// IFA_ADDRESS
52-
message.attributes.push(AddressAttribute::Local(address));
53-
54-
// set the IFA_BROADCAST address as well (IPv6 does not support
55-
// broadcast)
56-
if let IpAddr::V4(a) = address {
57-
if prefix_len == 32 {
58-
message.attributes.push(AddressAttribute::Broadcast(a));
59-
} else {
60-
let ip_addr = u32::from(a);
61-
let brd = Ipv4Addr::from(
62-
(0xffff_ffff_u32) >> u32::from(prefix_len) | ip_addr,
63-
);
64-
message.attributes.push(AddressAttribute::Broadcast(brd));
65-
};
66-
}
67-
}
6841
AddressAddRequest {
6942
handle,
7043
message,

src/addr/builder.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use std::{
4+
marker::PhantomData,
5+
net::{Ipv4Addr, Ipv6Addr},
6+
};
7+
8+
use netlink_packet_route::{
9+
address::{AddressAttribute, AddressMessage},
10+
AddressFamily,
11+
};
12+
13+
#[derive(Debug)]
14+
/// Helper struct for building [AddressMessage].
15+
pub struct AddressMessageBuilder<T> {
16+
message: AddressMessage,
17+
_phantom: PhantomData<T>,
18+
}
19+
20+
impl<T> AddressMessageBuilder<T> {
21+
/// Create a new [AddressMessageBuilder] without specifying the address family.
22+
fn new_no_address_family() -> Self {
23+
AddressMessageBuilder {
24+
message: AddressMessage::default(),
25+
_phantom: PhantomData,
26+
}
27+
}
28+
29+
/// Sets the interface index.
30+
pub fn index(mut self, index: u32) -> Self {
31+
self.message.header.index = index;
32+
self
33+
}
34+
35+
/// Builds [AddressMessage].
36+
pub fn build(self) -> AddressMessage {
37+
self.message
38+
}
39+
}
40+
41+
impl AddressMessageBuilder<Ipv4Addr> {
42+
/// Create a new [AddressMessageBuilder] for IPv4 addresses.
43+
pub fn new() -> Self {
44+
let mut builder = Self::new_no_address_family();
45+
builder.message.header.family = AddressFamily::Inet;
46+
builder
47+
}
48+
49+
/// Sets the address and prefix length.
50+
pub fn address(mut self, address: Ipv4Addr, prefix_len: u8) -> Self {
51+
self.message.header.prefix_len = prefix_len;
52+
53+
if !address.is_multicast() {
54+
self.message
55+
.attributes
56+
.push(AddressAttribute::Address(address.into()));
57+
58+
// The IFA_LOCAL address can be set to the same value as IFA_ADDRESS.
59+
self.message
60+
.attributes
61+
.push(AddressAttribute::Local(address.into()));
62+
63+
// Set the IFA_BROADCAST address as well.
64+
if prefix_len == 32 {
65+
self.message
66+
.attributes
67+
.push(AddressAttribute::Broadcast(address));
68+
} else {
69+
let ip_addr = u32::from(address);
70+
let brd = Ipv4Addr::from(
71+
(0xffff_ffff_u32) >> u32::from(prefix_len) | ip_addr,
72+
);
73+
self.message
74+
.attributes
75+
.push(AddressAttribute::Broadcast(brd));
76+
};
77+
}
78+
79+
self
80+
}
81+
}
82+
83+
impl AddressMessageBuilder<Ipv6Addr> {
84+
/// Create a new [AddressMessageBuilder] for IPv6 addresses.
85+
pub fn new() -> Self {
86+
let mut builder = Self::new_no_address_family();
87+
builder.message.header.family = AddressFamily::Inet6;
88+
builder
89+
}
90+
91+
/// Sets the address and prefix length.
92+
pub fn address(mut self, address: Ipv6Addr, prefix_len: u8) -> Self {
93+
self.message.header.prefix_len = prefix_len;
94+
95+
if address.is_multicast() {
96+
self.message
97+
.attributes
98+
.push(AddressAttribute::Multicast(address));
99+
} else {
100+
self.message
101+
.attributes
102+
.push(AddressAttribute::Address(address.into()));
103+
104+
// The IFA_LOCAL address can be set to the same value as IFA_ADDRESS.
105+
self.message
106+
.attributes
107+
.push(AddressAttribute::Local(address.into()));
108+
}
109+
110+
self
111+
}
112+
}

src/addr/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
// SPDX-License-Identifier: MIT
22

33
mod add;
4+
mod builder;
45
mod del;
56
mod get;
67
mod handle;
78

89
pub use self::add::AddressAddRequest;
10+
pub use self::builder::AddressMessageBuilder;
911
pub use self::del::AddressDelRequest;
1012
pub use self::get::AddressGetRequest;
1113
pub use self::handle::AddressHandle;

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ mod traffic_control;
2828

2929
pub use crate::addr::{
3030
AddressAddRequest, AddressDelRequest, AddressGetRequest, AddressHandle,
31+
AddressMessageBuilder,
3132
};
3233
pub use crate::connection::from_socket;
3334
#[cfg(feature = "tokio_socket")]

0 commit comments

Comments
 (0)