diff --git a/rtnetlink/examples/create_macvlan.rs b/rtnetlink/examples/create_macvlan.rs new file mode 100644 index 00000000..22277464 --- /dev/null +++ b/rtnetlink/examples/create_macvlan.rs @@ -0,0 +1,55 @@ +use futures::stream::TryStreamExt; +use rtnetlink::{new_connection, Error, Handle}; +use std::env; + +#[tokio::main] +async fn main() -> Result<(), String> { + let args: Vec = env::args().collect(); + if args.len() != 2 { + usage(); + return Ok(()); + } + let link_name = &args[1]; + + let (connection, handle, _) = new_connection().unwrap(); + tokio::spawn(connection); + + create_macvlan(handle, link_name.to_string()) + .await + .map_err(|e| format!("{}", e)) +} + +async fn create_macvlan(handle: Handle, veth_name: String) -> Result<(), Error> { + let mut links = handle + .link() + .get() + .set_name_filter(veth_name.clone()) + .execute(); + if let Some(link) = links.try_next().await? { + // hard code mode: 4u32 i.e bridge mode + let request = handle + .link() + .add() + .macvlan("test_macvlan".into(), link.header.index, 4u32); + request.execute().await? + } else { + println!("no link link {} found", veth_name); + } + Ok(()) +} + +fn usage() { + eprintln!( + "usage: + cargo run --example create_macvlan -- + +Note that you need to run this program as root. Instead of running cargo as root, +build the example normally: + + cd netlink-ip ; cargo build --example create_macvlan + +Then find the binary in the target directory: + + cd ../target/debug/example ; sudo ./create_macvlan " + ); +} diff --git a/rtnetlink/src/link/add.rs b/rtnetlink/src/link/add.rs index 02810429..0e5f878c 100644 --- a/rtnetlink/src/link/add.rs +++ b/rtnetlink/src/link/add.rs @@ -2,19 +2,11 @@ use futures::stream::StreamExt; use crate::{ packet::{ - nlas::link::{Info, InfoData, InfoKind, InfoVlan, InfoVxlan, Nla, VethInfo}, - LinkMessage, - NetlinkMessage, - RtnlMessage, - IFF_UP, - NLM_F_ACK, - NLM_F_CREATE, - NLM_F_EXCL, + nlas::link::{Info, InfoData, InfoKind, InfoMacVlan, InfoVlan, InfoVxlan, Nla, VethInfo}, + LinkMessage, NetlinkMessage, RtnlMessage, IFF_UP, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REQUEST, }, - try_nl, - Error, - Handle, + try_nl, Error, Handle, }; /// A request to create a new vxlan link. @@ -334,6 +326,19 @@ impl LinkAddRequest { .up() } + /// Create macvlan on a link. + /// This is equivalent to `ip link add NAME name link LINK type macvlan mode MACVLAN_MODE`, + /// but instead of specifying a link name (`LINK`), we specify a link index. + pub fn macvlan(self, name: String, index: u32, mode: u32) -> Self { + self.name(name) + .link_info( + InfoKind::MacVlan, + Some(InfoData::MacVlan(vec![InfoMacVlan::Mode(mode)])), + ) + .append_nla(Nla::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