Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 98 additions & 93 deletions src/ip/address/tests/address.rs
Original file line number Diff line number Diff line change
@@ -1,132 +1,137 @@
// SPDX-License-Identifier: MIT

use crate::tests::{assert_alias_output, exec_cmd, ip_rs_exec_cmd};
use crate::tests::{NetnsGuard, with_netns};

#[test]
fn test_address_show() {
let dummy_name = "atest-dummy1";
const DUMMY_NAME: &str = "test-dummy";

with_dummy_iface(dummy_name, || {
let expected_output = exec_cmd(&["ip", "address", "show", dummy_name]);
let our_output = ip_rs_exec_cmd(&["address", "show", dummy_name]);
fn with_dummy_iface<T>(test: T)
where
T: FnOnce(&NetnsGuard),
{
with_netns(|ns| {
ns.exec_cmd(&["ip", "link", "add", DUMMY_NAME, "type", "dummy"]);
ns.exec_cmd(&["ip", "link", "set", DUMMY_NAME, "up"]);

ns.exec_cmd(&[
"ip",
"addr",
"add",
"192.168.1.1/24",
"dev",
DUMMY_NAME,
]);
ns.exec_cmd(&[
"ip",
"addr",
"add",
"192.168.1.2/24",
"dev",
DUMMY_NAME,
]);
ns.exec_cmd(&["ip", "addr", "add", "ff::ab:cd/64", "dev", DUMMY_NAME]);
ns.exec_cmd(&[
"ip",
"addr",
"add",
"2001:db8:beef::1/64",
"dev",
DUMMY_NAME,
"valid_lft",
"21384",
"preferred_lft",
"21384",
"scope",
"global",
"mngtmpaddr",
"proto",
"kernel_ra",
]);
ns.exec_cmd(&[
"ip",
"addr",
"add",
"2001:db8:beef::2/64",
"dev",
DUMMY_NAME,
"valid_lft",
"21381",
"preferred_lft",
"21381",
"scope",
"global",
"home",
"proto",
"kernel_ra",
]);

// Wait 2 seconds for interface to be up and addresses to be assigned
std::thread::sleep(std::time::Duration::from_secs(2));

test(ns);
});
}

pretty_assertions::assert_eq!(expected_output, our_output);
#[test]
fn test_address_show() {
with_dummy_iface(|ns| {
ns.assert_eq_output(&["address", "show", DUMMY_NAME]);
});
}

#[test]
fn test_address_detailed_show() {
let dummy_name = "atest-dummy2";

with_dummy_iface(dummy_name, || {
let expected_output =
exec_cmd(&["ip", "-d", "address", "show", dummy_name]);
let our_output = ip_rs_exec_cmd(&["-d", "address", "show", dummy_name]);

pretty_assertions::assert_eq!(expected_output, our_output);
with_dummy_iface(|ns| {
ns.assert_eq_output(&["-d", "address", "show", DUMMY_NAME]);
});
}

#[test]
fn test_address_show_json() {
let dummy_name = "atest-dummy3";

with_dummy_iface(dummy_name, || {
let expected_output =
exec_cmd(&["ip", "-j", "address", "show", dummy_name]);
let our_output = ip_rs_exec_cmd(&["-j", "address", "show", dummy_name]);

pretty_assertions::assert_eq!(expected_output, our_output);
with_dummy_iface(|ns| {
ns.assert_eq_output(&["-j", "address", "show", DUMMY_NAME]);
});
}

#[test]
fn test_address_detailed_show_json() {
let dummy_name = "atest-dummy4";

with_dummy_iface(dummy_name, || {
let expected_output =
exec_cmd(&["ip", "-d", "-j", "address", "show", dummy_name]);
let our_output =
ip_rs_exec_cmd(&["-d", "-j", "address", "show", dummy_name]);

pretty_assertions::assert_eq!(expected_output, our_output);
with_dummy_iface(|ns| {
ns.assert_eq_output(&["-d", "-j", "address", "show", DUMMY_NAME]);
});
}

#[test]
fn test_address_alias_a_s() {
assert_alias_output(&["address", "show", "lo"], &["a", "s", "lo"]);
with_netns(|ns| {
ns.assert_alias_output(&["address", "show", "lo"], &["a", "s", "lo"]);
});
}

#[test]
fn test_address_alias_addr_show() {
assert_alias_output(&["address", "show", "lo"], &["addr", "show", "lo"]);
with_netns(|ns| {
ns.assert_alias_output(
&["address", "show", "lo"],
&["addr", "show", "lo"],
);
});
}

#[test]
fn test_address_alias_address_s() {
assert_alias_output(&["address", "show", "lo"], &["address", "s", "lo"]);
with_netns(|ns| {
ns.assert_alias_output(
&["address", "show", "lo"],
&["address", "s", "lo"],
);
});
}

#[test]
fn test_address_alias_add_ls() {
assert_alias_output(&["address", "show", "lo"], &["add", "ls", "lo"]);
}

fn with_dummy_iface<T>(dummy_name: &str, test: T)
where
T: FnOnce() + std::panic::UnwindSafe,
{
exec_cmd(&["ip", "link", "add", dummy_name, "type", "dummy"]);
exec_cmd(&["ip", "link", "set", dummy_name, "up"]);

exec_cmd(&["ip", "addr", "add", "192.168.1.1/24", "dev", dummy_name]);
exec_cmd(&["ip", "addr", "add", "192.168.1.2/24", "dev", dummy_name]);
exec_cmd(&["ip", "addr", "add", "ff::ab:cd/64", "dev", dummy_name]);
exec_cmd(&[
"ip",
"addr",
"add",
"2001:db8:beef::1/64",
"dev",
dummy_name,
"valid_lft",
"21384",
"preferred_lft",
"21384",
"scope",
"global",
"mngtmpaddr",
"proto",
"kernel_ra",
]);
exec_cmd(&[
"ip",
"addr",
"add",
"2001:db8:beef::2/64",
"dev",
dummy_name,
"valid_lft",
"21381",
"preferred_lft",
"21381",
"scope",
"global",
"home",
"proto",
"kernel_ra",
]);

// Wait 2 seconds for interface to be up and addresses to be assigned
std::thread::sleep(std::time::Duration::from_secs(2));

let result = std::panic::catch_unwind(|| {
test();
with_netns(|ns| {
ns.assert_alias_output(
&["address", "show", "lo"],
&["add", "ls", "lo"],
);
});

// clean up
exec_cmd(&["ip", "link", "del", dummy_name]);
assert!(result.is_ok())
}
70 changes: 35 additions & 35 deletions src/ip/link/ifaces/vxlan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,107 +179,107 @@ impl From<&[InfoVxlan]> for CliLinkInfoDataVxlan {

impl std::fmt::Display for CliLinkInfoDataVxlan {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "id {} ", self.id)?;
write!(f, "id {}", self.id)?;
if let Some(v) = self.group {
write!(f, "group {v} ")?;
write!(f, " group {v}")?;
}
if let Some(v) = self.group6 {
write!(f, "group6 {v} ")?;
write!(f, " group6 {v}")?;
}
if let Some(v) = self.local {
write!(f, "local {v} ")?;
write!(f, " local {v}")?;
}
if let Some(v) = self.local6 {
write!(f, "local6 {v} ")?;
write!(f, " local6 {v}")?;
}
if let Some(v) = &self.link_name {
write!(f, "dev {v} ")?;
write!(f, " dev {v}")?;
} else if let Some(v) = self.link {
write!(f, "dev if{v} ")?;
write!(f, " dev if{v}")?;
}
if let Some((low, high)) = self.port_range {
write!(f, "srcport {low} {high} ")?;
write!(f, " srcport {low} {high}")?;
}
if self.port > 0 {
write!(f, "dstport {} ", self.port)?;
write!(f, " dstport {}", self.port)?;
}
if self.ttl == 0 {
if self.ttl_inherit {
write!(f, "ttl inherit ")?;
write!(f, " ttl inherit")?;
} else {
write!(f, "ttl auto ")?;
write!(f, " ttl auto")?;
}
} else {
write!(f, "ttl {} ", self.ttl)?;
write!(f, " ttl {}", self.ttl)?;
}
if self.tos > 0 {
write!(f, "tos {} ", self.tos)?;
write!(f, " tos {}", self.tos)?;
}
if self.label > 0 {
write!(f, "label 0x{:x} ", self.label)?;
write!(f, " label 0x{:x}", self.label)?;
}
if !self.learning {
write!(f, "nolearning ")?;
write!(f, " nolearning")?;
}
if let Some(v) = self.df.as_ref()
&& v != "unset"
{
write!(f, "df {v} ")?;
write!(f, " df {v}")?;
}
write!(f, "ageing {} ", self.ageing)?;
write!(f, " ageing {}", self.ageing)?;
if self.limit > 0 {
write!(f, "limit {} ", self.limit)?;
write!(f, " limit {}", self.limit)?;
}
if self.proxy {
write!(f, "proxy ")?;
write!(f, " proxy")?;
}
if self.rsc {
write!(f, "rsc ")?;
write!(f, " rsc")?;
}
if self.l2miss {
write!(f, "l2miss ")?;
write!(f, " l2miss")?;
}
if self.l3miss {
write!(f, "l3miss ")?;
write!(f, " l3miss")?;
}
if self.collect_metadata {
write!(f, "collect_md ")?;
write!(f, " collect_md")?;
}
if !self.udp_csum {
write!(f, "noudpcsum ")?;
write!(f, " noudpcsum")?;
}
if self.udp_zero_csum6_tx {
write!(f, "udp6zerocsumtx ")?;
write!(f, " udp6zerocsumtx")?;
}
if self.udp_zero_csum6_rx {
write!(f, "udp6zerocsumrx ")?;
write!(f, " udp6zerocsumrx")?;
}
if self.remcsum_tx {
write!(f, "remcsumtx ")?;
write!(f, " remcsumtx")?;
}
if self.remcsum_rx {
write!(f, "remcsumrx ")?;
write!(f, " remcsumrx")?;
}
if self.gbp {
write!(f, "gbp ")?;
write!(f, " gbp")?;
}
if self.gpe {
write!(f, "gpe ")?;
write!(f, " gpe")?;
}
if self.remcsum_no_partial {
write!(f, "remcsum_nopartial ")?;
write!(f, " remcsum_nopartial")?;
}
if self.vnifilter {
write!(f, "vnifilter ")?;
write!(f, " vnifilter")?;
}
if !self.localbypass {
write!(f, "nolocalbypass ")?;
write!(f, " nolocalbypass")?;
}
if self.label_policy > 0 {
write!(f, "label_policy {} ", self.label_policy)?;
write!(f, " label_policy {}", self.label_policy)?;
}
if self.reserved_bits > 0 {
write!(f, "reserved_bits 0x{:x}", self.reserved_bits)?;
write!(f, " reserved_bits 0x{:x}", self.reserved_bits)?;
}
Ok(())
}
Expand Down
12 changes: 10 additions & 2 deletions src/ip/link/show.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT

use std::{collections::HashMap, os::fd::AsRawFd};
use std::{collections::HashMap, io::ErrorKind, os::fd::AsRawFd};

use futures_util::stream::{StreamExt, TryStreamExt};
use iproute_rs::{
Expand Down Expand Up @@ -331,7 +331,15 @@ async fn resolve_netns_names(
for netns in netnses {
let netns = netns?;
let name = netns.file_name().into_string().unwrap_or_default();
let file = std::fs::File::open(netns.path())?;
let file_res = std::fs::File::open(netns.path());
// Skip netnses that are not found (might be deleted)
if file_res
.as_ref()
.is_err_and(|e| e.kind() == ErrorKind::NotFound)
{
continue;
}
let file = file_res?;

if let Some(id) =
get_netns_id_from_fd(&mut handle, file.as_raw_fd() as u32).await
Expand Down
Loading
Loading