Skip to content

Commit 8bab098

Browse files
feat(link): add support of creating ipvlan and ipvtap.
feat: - add support of creating ipvlan and ipvtap - add examples.
1 parent c0edfbf commit 8bab098

File tree

6 files changed

+317
-4
lines changed

6 files changed

+317
-4
lines changed

examples/create_ipvlan.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use std::env;
4+
5+
use futures::stream::TryStreamExt;
6+
use rtnetlink::{
7+
new_connection,
8+
packet_route::link::{IpVlanFlags, IpVlanMode},
9+
Error, Handle, LinkIpVlan,
10+
};
11+
12+
#[tokio::main]
13+
async fn main() -> Result<(), String> {
14+
let args: Vec<String> = env::args().collect();
15+
if args.len() != 3 {
16+
usage();
17+
return Ok(());
18+
}
19+
let link_name = &args[1];
20+
let mode_str = &args[2];
21+
let mode = match mode_str.as_str() {
22+
"l2" => IpVlanMode::L2,
23+
"l3" => IpVlanMode::L3,
24+
"l3s" => IpVlanMode::L3S,
25+
_ => {
26+
usage();
27+
return Ok(());
28+
}
29+
};
30+
31+
let (connection, handle, _) = new_connection().unwrap();
32+
tokio::spawn(connection);
33+
34+
create_ipvlan(handle, link_name.to_string(), mode, IpVlanFlags::empty())
35+
.await
36+
.map_err(|e| format!("{e}"))
37+
}
38+
39+
async fn create_ipvlan(
40+
handle: Handle,
41+
link_name: String,
42+
mode: IpVlanMode,
43+
flag: IpVlanFlags,
44+
) -> Result<(), Error> {
45+
let mut parent_links =
46+
handle.link().get().match_name(link_name.clone()).execute();
47+
if let Some(parent) = parent_links.try_next().await? {
48+
let builder =
49+
LinkIpVlan::new("ipvlan_test", parent.header.index, mode, flag)
50+
.up();
51+
let message = builder.build();
52+
let request = handle.link().add(message);
53+
54+
request.execute().await?
55+
} else {
56+
println!("no link {link_name} found");
57+
}
58+
Ok(())
59+
}
60+
61+
fn usage() {
62+
eprintln!(
63+
"usage:
64+
cargo run --example create_ipvlan -- <link_name> <ipvlan_mode>
65+
ipvlan_mode can be one of the following:
66+
l2: L2 mode
67+
l3: L3 mode
68+
l3s: L3S mode
69+
Note that you need to run this program as root. Instead of running cargo as root,
70+
build the example normally:
71+
cargo build --example create_ipvlan
72+
Then find the binary in the target directory:
73+
cd target/debug/examples ; sudo ./create_ipvlan <link_name> <ipvlan_mode>"
74+
);
75+
}

examples/create_ipvtap.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use std::env;
4+
5+
use futures::stream::TryStreamExt;
6+
use rtnetlink::{
7+
new_connection,
8+
packet_route::link::{IpVtapFlags, IpVtapMode},
9+
Error, Handle, LinkIpVtap,
10+
};
11+
12+
#[tokio::main]
13+
async fn main() -> Result<(), String> {
14+
let args: Vec<String> = env::args().collect();
15+
if args.len() != 3 {
16+
usage();
17+
return Ok(());
18+
}
19+
let link_name = &args[1];
20+
let mode_str = &args[2];
21+
let mode = match mode_str.as_str() {
22+
"l2" => IpVtapMode::L2,
23+
"l3" => IpVtapMode::L3,
24+
"l3s" => IpVtapMode::L3S,
25+
_ => {
26+
usage();
27+
return Ok(());
28+
}
29+
};
30+
31+
let (connection, handle, _) = new_connection().unwrap();
32+
tokio::spawn(connection);
33+
34+
create_ipvtap(handle, link_name.to_string(), mode, IpVtapFlags::empty())
35+
.await
36+
.map_err(|e| format!("{e}"))
37+
}
38+
39+
async fn create_ipvtap(
40+
handle: Handle,
41+
link_name: String,
42+
mode: IpVtapMode,
43+
flags: IpVtapFlags,
44+
) -> Result<(), Error> {
45+
let mut parent_links =
46+
handle.link().get().match_name(link_name.clone()).execute();
47+
if let Some(parent) = parent_links.try_next().await? {
48+
let builder =
49+
LinkIpVtap::new("ipvtap_test", parent.header.index, mode, flags)
50+
.up();
51+
let message = builder.build();
52+
let request = handle.link().add(message);
53+
54+
request.execute().await?
55+
} else {
56+
println!("no link {link_name} found");
57+
}
58+
Ok(())
59+
}
60+
61+
fn usage() {
62+
eprintln!(
63+
"usage:
64+
cargo run --example create_ipvtap -- <link_name> <ipvtap_mode>
65+
66+
ipvtap_mode can be one of the following:
67+
l2: L2 mode
68+
l3: L3 mode
69+
l3s: L3S mode
70+
71+
Note that you need to run this program as root. Instead of running cargo as root,
72+
build the example normally:
73+
74+
cargo build --example create_ipvtap
75+
76+
Then find the binary in the target directory:
77+
78+
cd target/debug/examples ; sudo ./create_ipvtap <link_name> <ipvtap_mode>"
79+
);
80+
}

src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ pub use crate::{
5050
handle::Handle,
5151
link::{
5252
LinkAddRequest, LinkBond, LinkBondPort, LinkBridge, LinkDelPropRequest,
53-
LinkDelRequest, LinkDummy, LinkGetRequest, LinkHandle, LinkMacSec,
54-
LinkMacVlan, LinkMacVtap, LinkMessageBuilder, LinkSetRequest,
55-
LinkUnspec, LinkVeth, LinkVlan, LinkVrf, LinkVxlan, LinkWireguard,
56-
LinkXfrm, QosMapping,
53+
LinkDelRequest, LinkDummy, LinkGetRequest, LinkHandle, LinkIpVlan,
54+
LinkIpVtap, LinkMacSec, LinkMacVlan, LinkMacVtap, LinkMessageBuilder,
55+
LinkSetRequest, LinkUnspec, LinkVeth, LinkVlan, LinkVrf, LinkVxlan,
56+
LinkWireguard, LinkXfrm, QosMapping,
5757
},
5858
multicast::MulticastGroup,
5959
neighbour::{

src/link/ip_vlan.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use crate::{
4+
link::LinkMessageBuilder,
5+
packet_route::link::{
6+
InfoData, InfoIpVlan, InfoKind, IpVlanFlags, IpVlanMode,
7+
},
8+
};
9+
10+
/// Represent IP VLAN interface.
11+
/// Example code on creating a IP VLAN interface
12+
/// ```no_run
13+
/// use rtnetlink::{new_connection, packet_route::link::{IpVlanFlags, IpVlanMode},
14+
/// LinkIpVlan};
15+
///
16+
/// #[tokio::main]
17+
/// async fn main() -> Result<(), String> {
18+
/// let (connection, handle, _) = new_connection().unwrap();
19+
/// tokio::spawn(connection);
20+
///
21+
/// handle
22+
/// .link()
23+
/// .add(
24+
/// LinkIpVlan::new("ipvlan100", 10, IpVlanMode::L2, IpVlanFlags::empty())
25+
/// .up()
26+
/// .build(),
27+
/// )
28+
/// .execute()
29+
/// .await
30+
/// .map_err(|e| format!("{e}"))
31+
/// }
32+
/// ```
33+
///
34+
/// Please check LinkMessageBuilder::<LinkIpVlan> for more detail.
35+
#[derive(Debug)]
36+
pub struct LinkIpVlan;
37+
38+
impl LinkIpVlan {
39+
/// Wrapper of `LinkMessageBuilder::<LinkIpVlan>::new().link().mode()`
40+
pub fn new(
41+
name: &str,
42+
base_iface_index: u32,
43+
mode: IpVlanMode,
44+
flags: IpVlanFlags,
45+
) -> LinkMessageBuilder<Self> {
46+
LinkMessageBuilder::<LinkIpVlan>::new(name)
47+
.link(base_iface_index)
48+
.mode(mode)
49+
.flags(flags)
50+
}
51+
}
52+
53+
impl LinkMessageBuilder<LinkIpVlan> {
54+
/// Create [LinkMessageBuilder] for IP VLAN
55+
pub fn new(name: &str) -> Self {
56+
LinkMessageBuilder::<LinkIpVlan>::new_with_info_kind(InfoKind::IpVlan)
57+
.name(name.to_string())
58+
}
59+
60+
pub fn append_info_data(mut self, info: InfoIpVlan) -> Self {
61+
if let InfoData::IpVlan(infos) = self
62+
.info_data
63+
.get_or_insert_with(|| InfoData::IpVlan(Vec::new()))
64+
{
65+
infos.push(info);
66+
}
67+
self
68+
}
69+
70+
pub fn mode(self, mode: IpVlanMode) -> Self {
71+
self.append_info_data(InfoIpVlan::Mode(mode))
72+
}
73+
74+
pub fn flags(self, flags: IpVlanFlags) -> Self {
75+
self.append_info_data(InfoIpVlan::Flags(flags))
76+
}
77+
}

src/link/ip_vtap.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use crate::{
4+
link::LinkMessageBuilder,
5+
packet_route::link::{
6+
InfoData, InfoIpVtap, InfoKind, IpVtapFlags, IpVtapMode,
7+
},
8+
};
9+
10+
/// Represent IP VTAP interface.
11+
/// Example code on creating a IP VTAP interface
12+
/// ```no_run
13+
/// use rtnetlink::{new_connection, packet_route::link::{IpVtapFlags, IpVtapMode},
14+
/// LinkIpVtap};
15+
///
16+
/// #[tokio::main]
17+
/// async fn main() -> Result<(), String> {
18+
/// let (connection, handle, _) = new_connection().unwrap();
19+
/// tokio::spawn(connection);
20+
///
21+
/// handle
22+
/// .link()
23+
/// .add(
24+
/// LinkIpVtap::new("ipvtap100", 10, IpVtapMode::L2, IpVtapFlags::empty())
25+
/// .up()
26+
/// .build(),
27+
/// )
28+
/// .execute()
29+
/// .await
30+
/// .map_err(|e| format!("{e}"))
31+
/// }
32+
/// ```
33+
///
34+
/// Please check LinkMessageBuilder::<LinkIpVtap> for more detail.
35+
#[derive(Debug)]
36+
pub struct LinkIpVtap;
37+
38+
impl LinkIpVtap {
39+
/// Wrapper of `LinkMessageBuilder::<LinkIpVtap>::new().link().mode()`
40+
pub fn new(
41+
name: &str,
42+
base_iface_index: u32,
43+
mode: IpVtapMode,
44+
flags: IpVtapFlags,
45+
) -> LinkMessageBuilder<Self> {
46+
LinkMessageBuilder::<LinkIpVtap>::new(name)
47+
.link(base_iface_index)
48+
.mode(mode)
49+
.flags(flags)
50+
}
51+
}
52+
53+
impl LinkMessageBuilder<LinkIpVtap> {
54+
/// Create [LinkMessageBuilder] for IP VLAN
55+
pub fn new(name: &str) -> Self {
56+
LinkMessageBuilder::<LinkIpVtap>::new_with_info_kind(InfoKind::IpVtap)
57+
.name(name.to_string())
58+
}
59+
60+
pub fn append_info_data(mut self, info: InfoIpVtap) -> Self {
61+
if let InfoData::IpVtap(infos) = self
62+
.info_data
63+
.get_or_insert_with(|| InfoData::IpVtap(Vec::new()))
64+
{
65+
infos.push(info);
66+
}
67+
self
68+
}
69+
70+
pub fn mode(self, mode: IpVtapMode) -> Self {
71+
self.append_info_data(InfoIpVtap::Mode(mode))
72+
}
73+
74+
pub fn flags(self, flags: IpVtapFlags) -> Self {
75+
self.append_info_data(InfoIpVtap::Flags(flags))
76+
}
77+
}

src/link/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ mod del;
99
mod dummy;
1010
mod get;
1111
mod handle;
12+
mod ip_vlan;
13+
mod ip_vtap;
1214
mod mac_vlan;
1315
mod mac_vtap;
1416
mod macsec;
@@ -32,6 +34,8 @@ pub use self::{
3234
dummy::LinkDummy,
3335
get::LinkGetRequest,
3436
handle::LinkHandle,
37+
ip_vlan::LinkIpVlan,
38+
ip_vtap::LinkIpVtap,
3539
mac_vlan::LinkMacVlan,
3640
mac_vtap::LinkMacVtap,
3741
macsec::LinkMacSec,

0 commit comments

Comments
 (0)