From 7e0f0c5b00960435ca7607cbab644d090d43ddb5 Mon Sep 17 00:00:00 2001 From: Miguel Duarte Barroso Date: Wed, 4 Oct 2023 15:48:24 +0200 Subject: [PATCH] macvlan: unit test Add unit test asserting a macvlan interface can be added / retrieved / deleted and the expected parameters are there. Some default settings are set by the kernel - i.e. Flags, BcQueueLen, BcQueueLenUsed, and MacAddrCount. Signed-off-by: Miguel Duarte Barroso --- src/link/test.rs | 84 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 5 deletions(-) diff --git a/src/link/test.rs b/src/link/test.rs index 1032053..bb5878e 100644 --- a/src/link/test.rs +++ b/src/link/test.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT use futures::stream::TryStreamExt; +use netlink_packet_route::link::nlas::{InfoData, InfoMacVlan}; use netlink_packet_route::link::{ nlas::{Info, InfoKind, Nla}, LinkMessage, @@ -17,14 +18,65 @@ fn create_get_delete_wg() { let handle = rt.block_on(_create_wg()); assert!(handle.is_ok()); let mut handle = handle.unwrap(); - let msg = rt.block_on(_get_wg(&mut handle)); + let msg = rt.block_on(_get_iface(&mut handle, IFACE_NAME.to_owned())); assert!(msg.is_ok()); let msg = msg.unwrap(); assert!(has_nla( &msg, &Nla::Info(vec![Info::Kind(InfoKind::Wireguard)]) )); - rt.block_on(_del_wg(&mut handle, msg.header.index)).unwrap(); + rt.block_on(_del_iface(&mut handle, msg.header.index)) + .unwrap(); +} + +#[test] +fn create_get_delete_macvlan() { + const MACVLAN_IFACE_NAME: &str = "mvlan1"; + const LOWER_DEVICE_IDX: u32 = 2; + const MACVLAN_MODE: u32 = 4; // bridge + let mac_address = &vec![2u8, 0, 0, 0, 0, 1]; + + let rt = Runtime::new().unwrap(); + let handle = rt.block_on(_create_macvlan( + &MACVLAN_IFACE_NAME.to_owned(), + LOWER_DEVICE_IDX, // assuming there's always a network interface in the system ... + MACVLAN_MODE, + mac_address.to_vec(), + )); + assert!(handle.is_ok()); + + let mut handle = handle.unwrap(); + let msg = + rt.block_on(_get_iface(&mut handle, MACVLAN_IFACE_NAME.to_owned())); + assert!(msg.is_ok()); + assert!(has_nla( + &msg.as_ref().unwrap(), + &Nla::Info(vec![ + Info::Kind(InfoKind::MacVlan), + Info::Data(InfoData::MacVlan(vec![ + InfoMacVlan::Mode(MACVLAN_MODE), + InfoMacVlan::Flags(0), // defaulted by the kernel + InfoMacVlan::MacAddrCount(0), // defaulted by the kernel + InfoMacVlan::BcQueueLen(1000), // defaulted by the kernel + InfoMacVlan::BcQueueLenUsed(1000) // defaulted by the kernel + ])) + ]) + )); + assert!(has_nla( + &msg.as_ref().unwrap(), + &Nla::IfName(MACVLAN_IFACE_NAME.to_string()) + )); + assert!(has_nla( + &msg.as_ref().unwrap(), + &Nla::Link(LOWER_DEVICE_IDX) + )); + assert!(has_nla( + &msg.as_ref().unwrap(), + &Nla::Address(mac_address.to_vec()) + )); + + rt.block_on(_del_iface(&mut handle, msg.unwrap().header.index)) + .unwrap(); } fn has_nla(msg: &LinkMessage, nla: &Nla) -> bool { @@ -44,12 +96,34 @@ async fn _create_wg() -> Result { Ok(link_handle) } -async fn _get_wg(handle: &mut LinkHandle) -> Result { - let mut links = handle.get().match_name(IFACE_NAME.to_owned()).execute(); +async fn _get_iface( + handle: &mut LinkHandle, + iface_name: String, +) -> Result { + let mut links = handle.get().match_name(iface_name).execute(); let msg = links.try_next().await?; msg.ok_or(Error::RequestFailed) } -async fn _del_wg(handle: &mut LinkHandle, index: u32) -> Result<(), Error> { +async fn _del_iface(handle: &mut LinkHandle, index: u32) -> Result<(), Error> { handle.del(index).execute().await } + +async fn _create_macvlan( + name: &String, + lower_device_index: u32, + mode: u32, + mac: Vec, +) -> Result { + let (conn, handle, _) = new_connection().unwrap(); + tokio::spawn(conn); + let link_handle = handle.link(); + let mut req = + link_handle + .add() + .macvlan(name.to_string(), lower_device_index, mode); + req.message_mut().nlas.push(Nla::IfName(name.to_owned())); + req.message_mut().nlas.push(Nla::Address(mac)); + req.execute().await?; + Ok(link_handle) +}