Skip to content

Commit 230a729

Browse files
committed
Introduce LinkMessageBuilder
**API BREAK** To remove the duplicate error of `LinkAddRequest` and `LinkSetRequest`, this patch introduce `LinkMessageBuilder` to generate `LinkMessage` for link handlers to use. The `impl LinkMessageBuilder<T>` holds the common functions available for all interface types. The `impl LinkMessageBuilder<LinkVlan>` holds VLAN specific functions. The LinkMessageBuilder is designed for advanced user, wrapper functions are created for common use cases. For example, to create a VLAN interface: ```rus let (connection, handle, _) = new_connection().unwrap(); tokio::spawn(connection); handle .link() .add( LinkVlan::new("vlan100", 10, 100) .up() .build() ) .execute() .await .map_err(|e| format!("{e}")) ``` These patches included these new structures to generate matching LinkMessageBuilder: * `LinkUnspec` (for matching existing interface) * `LinkDummy` * `LinkVeth` * `LinkVlan` * `LinkVxlan` * `LinkMacVlan` * `LinkMacVtap` * `LinkWireguard` * `LinkBondPort` Special note: * Due to confliction, the previous VxLAN `link()` function changed to `dev()`. The `link()` is the share function for all interface types. The API is matching with `ip link` command line option for vxlan. Please check `examples/create_vxlan.rs` for usage. * The `LinkHandler::set_bond_port()` changed to `LinkHandler::set_port()`, please check `examples/set_bond_port.rs` for usage. * The `message_mut()` function is removed from `LinkSetRequest` and `LinkAddRequest`, user should modify the LinkMessage before sent to handler. Signed-off-by: Gris Ge <[email protected]>
1 parent d6e8b4c commit 230a729

37 files changed

+1784
-1192
lines changed

examples/create_bond.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
// SPDX-License-Identifier: MIT
22

3-
use netlink_packet_route::link::BondMode;
4-
use rtnetlink::new_connection;
53
use std::net::{Ipv4Addr, Ipv6Addr};
64

5+
use rtnetlink::{new_connection, packet_route::link::BondMode, LinkBond};
6+
77
#[tokio::main]
88
async fn main() -> Result<(), String> {
99
let (connection, handle, _) = new_connection().unwrap();
1010
tokio::spawn(connection);
11-
handle
12-
.link()
13-
.add()
14-
.bond("my-bond".into())
11+
12+
let message = LinkBond::new("my-bond")
1513
.mode(BondMode::ActiveBackup)
1614
.miimon(100)
1715
.updelay(100)
@@ -26,6 +24,11 @@ async fn main() -> Result<(), String> {
2624
Ipv6Addr::new(0xfd02, 0, 0, 0, 0, 0, 0, 2),
2725
])
2826
.up()
27+
.build();
28+
29+
handle
30+
.link()
31+
.add(message)
2932
.execute()
3033
.await
3134
.map_err(|e| format!("{e}"))

examples/create_bridge.rs

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

3-
use rtnetlink::new_connection;
3+
use rtnetlink::{new_connection, LinkBridge};
44

55
#[tokio::main]
66
async fn main() -> Result<(), String> {
77
let (connection, handle, _) = new_connection().unwrap();
88
tokio::spawn(connection);
9+
910
handle
1011
.link()
11-
.add()
12-
.bridge("my-bridge-1".into())
12+
.add(LinkBridge::new("my-bridge").build())
1313
.execute()
1414
.await
1515
.map_err(|e| format!("{e}"))

examples/create_dummy.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use rtnetlink::{new_connection, LinkDummy};
4+
5+
#[tokio::main]
6+
async fn main() -> Result<(), String> {
7+
let (connection, handle, _) = new_connection().unwrap();
8+
tokio::spawn(connection);
9+
10+
handle
11+
.link()
12+
.add(LinkDummy::new("dummy0").build())
13+
.execute()
14+
.await
15+
.map_err(|e| format!("{e}"))
16+
}

examples/create_macvlan.rs

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

3-
use futures::stream::TryStreamExt;
4-
use macaddr::MacAddr;
5-
use rtnetlink::{new_connection, Error, Handle};
63
use std::{env, str::FromStr};
74

8-
use netlink_packet_route::link::{LinkAttribute, MacVlanMode};
5+
use futures::stream::TryStreamExt;
6+
use macaddr::MacAddr;
7+
use rtnetlink::{
8+
new_connection, packet_route::link::MacVlanMode, Error, Handle, LinkMacVlan,
9+
};
910

1011
#[tokio::main]
1112
async fn main() -> Result<(), String> {
@@ -37,19 +38,20 @@ async fn create_macvlan(
3738
link_name: String,
3839
mac_address: Option<Vec<u8>>,
3940
) -> Result<(), Error> {
40-
let mut links = handle.link().get().match_name(link_name.clone()).execute();
41-
if let Some(link) = links.try_next().await? {
42-
let mut request = handle.link().add().macvlan(
43-
"test_macvlan".into(),
44-
link.header.index,
41+
let mut parent_links =
42+
handle.link().get().match_name(link_name.clone()).execute();
43+
if let Some(parent) = parent_links.try_next().await? {
44+
let mut builder = LinkMacVlan::new(
45+
"my-macvlan",
46+
parent.header.index,
4547
MacVlanMode::Bridge,
4648
);
4749
if let Some(mac) = mac_address {
48-
request
49-
.message_mut()
50-
.attributes
51-
.push(LinkAttribute::Address(mac));
50+
builder = builder.address(mac);
5251
}
52+
let message = builder.build();
53+
let request = handle.link().add(message);
54+
5355
request.execute().await?
5456
} else {
5557
println!("no link {link_name} found");

examples/create_macvtap.rs

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

3-
use futures::stream::TryStreamExt;
4-
use netlink_packet_route::link::MacVtapMode;
5-
use rtnetlink::{new_connection, Error, Handle};
63
use std::env;
74

5+
use futures::stream::TryStreamExt;
6+
use rtnetlink::{
7+
new_connection, packet_route::link::MacVtapMode, Error, Handle, LinkMacVtap,
8+
};
9+
810
#[tokio::main]
911
async fn main() -> Result<(), String> {
1012
let args: Vec<String> = env::args().collect();
@@ -24,18 +26,22 @@ async fn main() -> Result<(), String> {
2426

2527
async fn create_macvtap(
2628
handle: Handle,
27-
veth_name: String,
29+
link_name: String,
2830
) -> Result<(), Error> {
29-
let mut links = handle.link().get().match_name(veth_name.clone()).execute();
30-
if let Some(link) = links.try_next().await? {
31-
let request = handle.link().add().macvtap(
32-
"test_macvtap".into(),
33-
link.header.index,
31+
let mut parent_links =
32+
handle.link().get().match_name(link_name.clone()).execute();
33+
if let Some(parent) = parent_links.try_next().await? {
34+
let message = LinkMacVtap::new(
35+
"test_macvtap",
36+
parent.header.index,
3437
MacVtapMode::Bridge,
35-
);
38+
)
39+
.build();
40+
41+
let request = handle.link().add(message);
3642
request.execute().await?
3743
} else {
38-
println!("no link link {veth_name} found");
44+
println!("no link link {link_name} found");
3945
}
4046
Ok(())
4147
}

examples/create_veth.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
// SPDX-License-Identifier: MIT
22

3-
use rtnetlink::new_connection;
4-
3+
use rtnetlink::{new_connection, LinkVeth};
54
#[tokio::main]
65
async fn main() -> Result<(), String> {
76
let (connection, handle, _) = new_connection().unwrap();
87
tokio::spawn(connection);
8+
99
handle
1010
.link()
11-
.add()
12-
.veth("veth-rs-1".into(), "veth-rs-2".into())
11+
.add(LinkVeth::new("veth1", "veth1-peer").build())
1312
.execute()
1413
.await
1514
.map_err(|e| format!("{e}"))

examples/create_vlan.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use std::{env, error::Error as StdError, str::FromStr};
44

5-
use rtnetlink::{new_connection, QosMapping};
5+
use rtnetlink::{new_connection, LinkVlan, QosMapping};
66

77
fn parse_mapping(parameter: &str) -> Result<QosMapping, Box<dyn StdError>> {
88
let (from, to) = parameter
@@ -109,10 +109,14 @@ async fn main() -> Result<(), String> {
109109
let (connection, handle, _) = new_connection().unwrap();
110110
tokio::spawn(connection);
111111

112+
let message = LinkVlan::new(&name, base, id)
113+
.up()
114+
.qos(ingress, egress)
115+
.build();
116+
112117
handle
113118
.link()
114-
.add()
115-
.vlan_with_qos(name, base, id, ingress, egress)
119+
.add(message)
116120
.execute()
117121
.await
118122
.map_err(|err| format!("Netlink request failed: {err}"))

examples/create_vrf.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use rtnetlink::{new_connection, LinkVrf};
4+
5+
#[tokio::main]
6+
async fn main() -> Result<(), String> {
7+
let (connection, handle, _) = new_connection().unwrap();
8+
tokio::spawn(connection);
9+
10+
handle
11+
.link()
12+
.add(LinkVrf::new("my-vrf", 101).build())
13+
.execute()
14+
.await
15+
.map_err(|e| format!("{e}"))
16+
}

examples/create_vxlan.rs

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

33
use futures::stream::TryStreamExt;
4-
use rtnetlink::{new_connection, Error, Handle};
4+
use rtnetlink::{new_connection, Error, Handle, LinkVxlan};
55
use std::env;
66

77
#[tokio::main]
@@ -24,15 +24,13 @@ async fn main() -> Result<(), String> {
2424
async fn create_vxlan(handle: Handle, name: String) -> Result<(), Error> {
2525
let mut links = handle.link().get().match_name(name.clone()).execute();
2626
if let Some(link) = links.try_next().await? {
27-
handle
28-
.link()
29-
.add()
30-
.vxlan("vxlan0".into(), 10u32)
31-
.link(link.header.index)
32-
.port(4789)
27+
let message = LinkVxlan::new("vxlan0", 10)
28+
.dev(link.header.index)
3329
.up()
34-
.execute()
35-
.await?
30+
.port(4789)
31+
.build();
32+
33+
handle.link().add(message).execute().await?
3634
} else {
3735
println!("no link link {name} found");
3836
}

examples/create_wireguard.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use rtnetlink::{new_connection, LinkWireguard};
4+
5+
#[tokio::main]
6+
async fn main() -> Result<(), String> {
7+
let (connection, handle, _) = new_connection().unwrap();
8+
tokio::spawn(connection);
9+
10+
handle
11+
.link()
12+
.add(LinkWireguard::new("my-wg").build())
13+
.execute()
14+
.await
15+
.map_err(|e| format!("{e}"))
16+
}

examples/create_xfrm.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use futures::stream::TryStreamExt;
4+
use rtnetlink::{new_connection, Error, Handle, LinkXfrm};
5+
6+
#[tokio::main]
7+
async fn main() -> Result<(), String> {
8+
let args: Vec<String> = std::env::args().collect();
9+
if args.len() != 2 {
10+
usage();
11+
return Ok(());
12+
}
13+
let link_name = &args[1];
14+
15+
let (connection, handle, _) = new_connection().unwrap();
16+
tokio::spawn(connection);
17+
18+
create_xfrm(handle, link_name.to_string())
19+
.await
20+
.map_err(|e| format!("{e}"))
21+
}
22+
23+
async fn create_xfrm(handle: Handle, link_name: String) -> Result<(), Error> {
24+
let mut parent_links =
25+
handle.link().get().match_name(link_name.clone()).execute();
26+
if let Some(parent) = parent_links.try_next().await? {
27+
let request = handle
28+
.link()
29+
.add(LinkXfrm::new("my-xfrm", parent.header.index, 0x08).build());
30+
31+
request.execute().await?
32+
} else {
33+
println!("no link {link_name} found");
34+
}
35+
Ok(())
36+
}
37+
38+
fn usage() {
39+
eprintln!(
40+
"usage:
41+
cargo run --example create_xfrm -- <link name>
42+
43+
Note that you need to run this program as root. Instead of running cargo as
44+
root, build the example normally:
45+
46+
cargo build --example create_xfrm
47+
48+
Then find the binary in the target directory:
49+
50+
cd target/debug/examples ; sudo ./create_xfrm <link_name>"
51+
);
52+
}

examples/get_bond_port_settings.rs

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

33
use futures::stream::TryStreamExt;
4-
use rtnetlink::{new_connection, Error, Handle};
4+
use rtnetlink::{
5+
new_connection, packet_route::link::LinkAttribute, Error, Handle,
6+
};
57
use std::env;
68

79
#[tokio::main]
@@ -35,7 +37,11 @@ async fn dump_bond_port_settings(
3537
let mut link_messgage =
3638
handle.link().get().match_name(linkname).execute();
3739
while let Some(msg) = link_messgage.try_next().await? {
38-
println!("{msg:?}");
40+
for nla in msg.attributes {
41+
if let LinkAttribute::LinkInfo(i) = &nla {
42+
println!("{:?}", i);
43+
}
44+
}
3945
}
4046
Ok(())
4147
} else {

0 commit comments

Comments
 (0)