Skip to content

Commit

Permalink
feat(link): add support of creating ipvlan and ipvtap.
Browse files Browse the repository at this point in the history
feat:
- add support of creating ipvlan and ipvtap
- add examples.
  • Loading branch information
xujunjie-cover committed Apr 27, 2024
1 parent 6896bae commit 3f3859b
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 4 deletions.
68 changes: 68 additions & 0 deletions examples/create_ipvlan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: MIT

use futures::stream::TryStreamExt;
use netlink_packet_route::link::IpVlanMode;
use rtnetlink::{new_connection, Error, Handle};
use std::env;

#[tokio::main]
async fn main() -> Result<(), String> {
let args: Vec<String> = env::args().collect();
if args.len() != 3 {
usage();
return Ok(());
}
let link_name = &args[1];
let mode_str = &args[2];
let mode = match mode_str.as_str() {
"l2" => IpVlanMode::L2,
"l3" => IpVlanMode::L3,
"l3s" => IpVlanMode::L3S,
_ => {
usage();
return Ok(());
}
};

let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

create_ipvlan(handle, link_name.to_string(), mode)
.await
.map_err(|e| format!("{e}"))
}

async fn create_ipvlan(
handle: Handle,
link_name: String,
mode: IpVlanMode,
) -> Result<(), Error> {
let mut links = handle.link().get().match_name(link_name.clone()).execute();
if let Some(link) = links.try_next().await? {
let request = handle.link().add().ipvlan(
"test_ipvlan".into(),
link.header.index,
mode,
);
request.execute().await?
} else {
println!("no link {link_name} found");
}
Ok(())
}

fn usage() {
eprintln!(
"usage:
cargo run --example create_ipvlan -- <link_name> <ipvlan_mode>
ipvlan_mode can be one of the following:
l2: L2 mode
l3: L3 mode
l3s: L3S mode
Note that you need to run this program as root. Instead of running cargo as root,
build the example normally:
cargo build --example create_ipvlan
Then find the binary in the target directory:
cd target/debug/examples ; sudo ./create_ipvlan <link_name> <ipvlan_mode>"
);
}
73 changes: 73 additions & 0 deletions examples/create_ipvtap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: MIT

use futures::stream::TryStreamExt;
use netlink_packet_route::link::IpVtapMode;
use rtnetlink::{new_connection, Error, Handle};
use std::env;

#[tokio::main]
async fn main() -> Result<(), String> {
let args: Vec<String> = env::args().collect();
if args.len() != 3 {
usage();
return Ok(());
}
let link_name = &args[1];
let mode_str = &args[2];
let mode = match mode_str.as_str() {
"l2" => IpVtapMode::L2,
"l3" => IpVtapMode::L3,
"l3s" => IpVtapMode::L3S,
_ => {
usage();
return Ok(());
}
};

let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

create_ipvtap(handle, link_name.to_string(), mode)
.await
.map_err(|e| format!("{e}"))
}

async fn create_ipvtap(
handle: Handle,
link_name: String,
mode: IpVtapMode,
) -> Result<(), Error> {
let mut links = handle.link().get().match_name(link_name.clone()).execute();
if let Some(link) = links.try_next().await? {
let request = handle.link().add().ipvtap(
"test_ipvtap".into(),
link.header.index,
mode,
);
request.execute().await?
} else {
println!("no link {link_name} found");
}
Ok(())
}

fn usage() {
eprintln!(
"usage:
cargo run --example create_ipvtap -- <link_name> <ipvtap_mode>
ipvtap_mode can be one of the following:
l2: L2 mode
l3: L3 mode
l3s: L3S mode
Note that you need to run this program as root. Instead of running cargo as root,
build the example normally:
cargo build --example create_ipvtap
Then find the binary in the target directory:
cd target/debug/examples ; sudo ./create_ipvtap <link_name> <ipvtap_mode>"
);
}
38 changes: 34 additions & 4 deletions src/link/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ use netlink_packet_core::{

use netlink_packet_route::{
link::{
BondMode, InfoBond, InfoData, InfoKind, InfoMacVlan, InfoMacVtap,
InfoVeth, InfoVlan, InfoVrf, InfoVxlan, InfoXfrm, LinkAttribute,
LinkFlags, LinkInfo, LinkMessage, MacVlanMode, MacVtapMode,
VlanQosMapping,
BondMode, InfoBond, InfoData, InfoIpVlan, InfoIpVtap, InfoKind,
InfoMacVlan, InfoMacVtap, InfoVeth, InfoVlan, InfoVrf, InfoVxlan,
InfoXfrm, IpVlanMode, IpVtapMode, LinkAttribute, LinkFlags, LinkInfo,
LinkMessage, MacVlanMode, MacVtapMode, VlanQosMapping,
},
RouteNetlinkMessage,
};
Expand Down Expand Up @@ -714,6 +714,36 @@ impl LinkAddRequest {
.up()
}

/// Create ipvlan on a link.
/// This is equivalent to `ip link add name NAME link LINK type ipvlan mode
/// IPVLAN_MODE`, but instead of specifying a link name (`LINK`), we
/// specify a link index. The mode is an integer consisting of
/// ipvlan modes. 0 is L2, 1 is L3, 2 is L3S.
pub fn ipvlan(self, name: String, index: u32, mode: IpVlanMode) -> Self {
self.name(name)
.link_info(
InfoKind::IpVlan,
Some(InfoData::IpVlan(vec![InfoIpVlan::Mode(mode)])),
)
.append_nla(LinkAttribute::Link(index))
.up()
}

/// Create ipvtap on a link.
/// This is equivalent to `ip link add name NAME link LINK type ipvtap mode
/// IPVTAP_MODE`, but instead of specifying a link name (`LINK`), we
/// specify a link index. The mode is an integer consisting of
/// ipvtap modes. 0 is L2, 1 is L3, 2 is L3S.
pub fn ipvtap(self, name: String, index: u32, mode: IpVtapMode) -> Self {
self.name(name)
.link_info(
InfoKind::IpVtap,
Some(InfoData::IpVtap(vec![InfoIpVtap::Mode(mode)])),
)
.append_nla(LinkAttribute::Link(index))
.up()
}

/// Create a VxLAN
/// This is equivalent to `ip link add name NAME type vxlan id VNI`,
/// it returns a VxlanAddRequest to further customize the vxlan
Expand Down

0 comments on commit 3f3859b

Please sign in to comment.