Skip to content

Commit 3f3859b

Browse files
feat(link): add support of creating ipvlan and ipvtap.
feat: - add support of creating ipvlan and ipvtap - add examples.
1 parent 6896bae commit 3f3859b

File tree

3 files changed

+175
-4
lines changed

3 files changed

+175
-4
lines changed

examples/create_ipvlan.rs

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

examples/create_ipvtap.rs

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

src/link/add.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ use netlink_packet_core::{
1313

1414
use netlink_packet_route::{
1515
link::{
16-
BondMode, InfoBond, InfoData, InfoKind, InfoMacVlan, InfoMacVtap,
17-
InfoVeth, InfoVlan, InfoVrf, InfoVxlan, InfoXfrm, LinkAttribute,
18-
LinkFlags, LinkInfo, LinkMessage, MacVlanMode, MacVtapMode,
19-
VlanQosMapping,
16+
BondMode, InfoBond, InfoData, InfoIpVlan, InfoIpVtap, InfoKind,
17+
InfoMacVlan, InfoMacVtap, InfoVeth, InfoVlan, InfoVrf, InfoVxlan,
18+
InfoXfrm, IpVlanMode, IpVtapMode, LinkAttribute, LinkFlags, LinkInfo,
19+
LinkMessage, MacVlanMode, MacVtapMode, VlanQosMapping,
2020
},
2121
RouteNetlinkMessage,
2222
};
@@ -714,6 +714,36 @@ impl LinkAddRequest {
714714
.up()
715715
}
716716

717+
/// Create ipvlan on a link.
718+
/// This is equivalent to `ip link add name NAME link LINK type ipvlan mode
719+
/// IPVLAN_MODE`, but instead of specifying a link name (`LINK`), we
720+
/// specify a link index. The mode is an integer consisting of
721+
/// ipvlan modes. 0 is L2, 1 is L3, 2 is L3S.
722+
pub fn ipvlan(self, name: String, index: u32, mode: IpVlanMode) -> Self {
723+
self.name(name)
724+
.link_info(
725+
InfoKind::IpVlan,
726+
Some(InfoData::IpVlan(vec![InfoIpVlan::Mode(mode)])),
727+
)
728+
.append_nla(LinkAttribute::Link(index))
729+
.up()
730+
}
731+
732+
/// Create ipvtap on a link.
733+
/// This is equivalent to `ip link add name NAME link LINK type ipvtap mode
734+
/// IPVTAP_MODE`, but instead of specifying a link name (`LINK`), we
735+
/// specify a link index. The mode is an integer consisting of
736+
/// ipvtap modes. 0 is L2, 1 is L3, 2 is L3S.
737+
pub fn ipvtap(self, name: String, index: u32, mode: IpVtapMode) -> Self {
738+
self.name(name)
739+
.link_info(
740+
InfoKind::IpVtap,
741+
Some(InfoData::IpVtap(vec![InfoIpVtap::Mode(mode)])),
742+
)
743+
.append_nla(LinkAttribute::Link(index))
744+
.up()
745+
}
746+
717747
/// Create a VxLAN
718748
/// This is equivalent to `ip link add name NAME type vxlan id VNI`,
719749
/// it returns a VxlanAddRequest to further customize the vxlan

0 commit comments

Comments
 (0)