diff --git a/.gitignore b/.gitignore index 3ef7047..b3acf36 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -SOURCES/nispor-1.1.0-vendor.tar.xz -SOURCES/nispor-1.1.0.tar.gz +SOURCES/nispor-1.1.1-vendor.tar.xz +SOURCES/nispor-1.1.1.tar.gz diff --git a/.nispor.metadata b/.nispor.metadata index 3834e48..49cf2a0 100644 --- a/.nispor.metadata +++ b/.nispor.metadata @@ -1,2 +1,2 @@ -f63116bfa3363bbd601fe416a6dc983c644c1714 SOURCES/nispor-1.1.0-vendor.tar.xz -3864383d02df3107f9772c5374659b7e255b1afb SOURCES/nispor-1.1.0.tar.gz +ab6b879911102b36b276d080de78967279016b02 SOURCES/nispor-1.1.1-vendor.tar.xz +c4bff5488cde6eaf881d510e463f6c3f0e13aae2 SOURCES/nispor-1.1.1.tar.gz diff --git a/SOURCES/0001-npc-Show-brief-network-state-when-no-argument.patch b/SOURCES/0001-npc-Show-brief-network-state-when-no-argument.patch deleted file mode 100644 index 1e42ebf..0000000 --- a/SOURCES/0001-npc-Show-brief-network-state-when-no-argument.patch +++ /dev/null @@ -1,375 +0,0 @@ -From 69cc9aaf259d4c55b74d7b75037992431136ba42 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Fri, 28 May 2021 18:18:13 +0800 -Subject: [PATCH 1/3] npc: Show brief network state when no argument - -When running `npc` without any argument, instead of dumping all -information, this patch changed to show brief network status. - -Added new sub command `iface` to `npc` for old behaviour: - - * `npc eth1` -- show eth1 interface info. - * `npc iface eth1` -- the same as `npc eth1`. - * `npc iface` -- show full information in yaml format. - * `npc` -- show brief network state. - * `npc --json` -- show brief network state in json format. - -Example on running `npc` without argument: - -``` -1: lo: state unknown mtu 65536 - mac 00:00:00:00:00:00 - ipv4 127.0.0.1/8 - ipv6 ::1/128 -2: eth1: state up mtu 1500 - mac 00:01:02:03:04:05 - ipv4 192.0.2.6/24 gw4 192.0.2.1 - ipv6 2001:db8::6/64 fe80::6/64 gw6 fe80::1 -``` - -This patch contains many memory copy done by `to_string()`, `clone()`, -`to_vec()`. We can improve it in future if that cause any problem. - -Signed-off-by: Gris Ge ---- - src/cli/npc.rs | 232 +++++++++++++++++++++++++++++++++++++--- - src/lib/ifaces/iface.rs | 17 +++ - 2 files changed, 237 insertions(+), 12 deletions(-) - -diff --git a/src/cli/npc.rs b/src/cli/npc.rs -index b7171bb..41ddbd8 100644 ---- a/src/cli/npc.rs -+++ b/src/cli/npc.rs -@@ -13,19 +13,188 @@ - // limitations under the License. - - use clap::{clap_app, crate_authors, crate_version}; --use nispor::{Iface, NetConf, NetState, NisporError, Route, RouteRule}; -+use nispor::{ -+ Iface, IfaceState, NetConf, NetState, NisporError, Route, RouteRule, -+}; - use serde_derive::Serialize; - use serde_json; - use serde_yaml; -+use std::collections::HashMap; - use std::fmt; - use std::io::{stderr, stdout, Write}; - use std::process; - --#[derive(Serialize)] -+const INDENT: &str = " "; -+ -+#[derive(Serialize, Debug)] - pub struct CliError { - pub msg: String, - } - -+#[derive(Serialize, Default)] -+struct CliIfaceBrief { -+ index: u32, -+ name: String, -+ state: IfaceState, -+ flags: Vec, -+ mac: String, -+ permanent_mac: String, -+ mtu: i64, -+ ipv4: Vec, -+ ipv6: Vec, -+ gw4: Vec, -+ gw6: Vec, -+} -+ -+impl CliIfaceBrief { -+ fn to_string(briefs: &[CliIfaceBrief]) -> String { -+ let mut ret = Vec::new(); -+ for brief in briefs { -+ ret.push(format!( -+ "{}: {}: <{}> state {} mtu {}", -+ brief.index, -+ brief.name, -+ brief.flags.join(","), -+ brief.state, -+ brief.mtu, -+ )); -+ if &brief.mac != "" { -+ ret.push(format!( -+ "{}mac {}{}", -+ INDENT, -+ brief.mac, -+ if &brief.permanent_mac != "" -+ && &brief.permanent_mac != &brief.mac -+ { -+ format!(" permanent_mac: {}", brief.permanent_mac) -+ } else { -+ "".into() -+ } -+ )); -+ } -+ if brief.ipv4.len() > 0 { -+ ret.push(format!( -+ "{}ipv4 {}{}", -+ INDENT, -+ brief.ipv4.join(" "), -+ if brief.gw4.len() > 0 { -+ format!(" gw4 {}", brief.gw4.join(" ")) -+ } else { -+ "".into() -+ }, -+ )); -+ } -+ if brief.ipv6.len() > 0 { -+ ret.push(format!( -+ "{}ipv6 {}{}", -+ INDENT, -+ brief.ipv6.join(" "), -+ if brief.gw6.len() > 0 { -+ format!(" gw6 {}", brief.gw6.join(" ")) -+ } else { -+ "".into() -+ } -+ )); -+ } -+ } -+ ret.join("\n") -+ } -+ -+ fn from_net_state(netstate: &NetState) -> Vec { -+ let mut ret = Vec::new(); -+ let mut iface_to_gw4: HashMap> = HashMap::new(); -+ let mut iface_to_gw6: HashMap> = HashMap::new(); -+ -+ for route in &netstate.routes { -+ if let Route { -+ dst: None, -+ gateway: Some(gw), -+ oif: Some(iface_name), -+ .. -+ } = route -+ { -+ if gw.contains(":") { -+ match iface_to_gw6.get_mut(iface_name) { -+ Some(gateways) => { -+ gateways.push(gw.to_string()); -+ } -+ None => { -+ iface_to_gw6.insert( -+ iface_name.to_string(), -+ vec![gw.to_string()], -+ ); -+ } -+ } -+ } else { -+ match iface_to_gw4.get_mut(iface_name) { -+ Some(gateways) => { -+ gateways.push(gw.to_string()); -+ } -+ None => { -+ iface_to_gw4.insert( -+ iface_name.to_string(), -+ vec![gw.to_string()], -+ ); -+ } -+ } -+ } -+ } -+ } -+ -+ for iface in netstate.ifaces.values() { -+ ret.push(CliIfaceBrief { -+ index: iface.index, -+ name: iface.name.clone(), -+ flags: (&iface.flags) -+ .into_iter() -+ .map(|flag| format!("{:?}", flag).to_uppercase()) -+ .collect(), -+ state: iface.state.clone(), -+ mac: iface.mac_address.clone(), -+ permanent_mac: iface.permanent_mac_address.clone(), -+ mtu: iface.mtu, -+ ipv4: match &iface.ipv4 { -+ Some(ip_info) => { -+ let mut addr_strs = Vec::new(); -+ for addr in &ip_info.addresses { -+ addr_strs.push(format!( -+ "{}/{}", -+ addr.address, addr.prefix_len -+ )); -+ } -+ addr_strs -+ } -+ None => Vec::new(), -+ }, -+ ipv6: match &iface.ipv6 { -+ Some(ip_info) => { -+ let mut addr_strs = Vec::new(); -+ for addr in &ip_info.addresses { -+ addr_strs.push(format!( -+ "{}/{}", -+ addr.address, addr.prefix_len -+ )); -+ } -+ addr_strs -+ } -+ None => Vec::new(), -+ }, -+ gw4: match &iface_to_gw4.get(&iface.name) { -+ Some(gws) => gws.to_vec(), -+ None => Vec::new(), -+ }, -+ gw6: match &iface_to_gw6.get(&iface.name) { -+ Some(gws) => gws.to_vec(), -+ None => Vec::new(), -+ }, -+ ..Default::default() -+ }) -+ } -+ ret.sort_by(|a, b| a.index.cmp(&b.index)); -+ ret -+ } -+} -+ - impl fmt::Display for CliError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.msg) -@@ -34,6 +203,7 @@ impl fmt::Display for CliError { - - enum CliResult { - Pass, -+ Brief(Vec), - Full(NetState), - Ifaces(Vec), - Routes(Vec), -@@ -42,6 +212,7 @@ enum CliResult { - NisporError(NisporError), - } - -+#[derive(PartialEq)] - enum CliOutputType { - Json, - Yaml, -@@ -53,6 +224,7 @@ macro_rules! npc_print { - CliResult::Pass => { - process::exit(0); - } -+ CliResult::Brief(_) => unreachable!(), - CliResult::Full(netstate) => { - writeln!(stdout(), "{}", $display_func(&netstate).unwrap()) - .ok(); -@@ -83,9 +255,24 @@ macro_rules! npc_print { - } - - fn print_result(result: &CliResult, output_type: CliOutputType) { -- match output_type { -- CliOutputType::Json => npc_print!(serde_json::to_string_pretty, result), -- CliOutputType::Yaml => npc_print!(serde_yaml::to_string, result), -+ if let CliResult::Brief(briefs) = result { -+ if output_type == CliOutputType::Json { -+ writeln!( -+ stdout(), -+ "{}", -+ serde_json::to_string_pretty(&briefs).unwrap() -+ ) -+ .ok(); -+ } else { -+ writeln!(stdout(), "{}", CliIfaceBrief::to_string(&briefs)).ok(); -+ } -+ } else { -+ match output_type { -+ CliOutputType::Json => { -+ npc_print!(serde_json::to_string_pretty, result) -+ } -+ CliOutputType::Yaml => npc_print!(serde_yaml::to_string, result), -+ } - } - } - -@@ -133,6 +320,11 @@ fn main() { - (about: "Nispor CLI") - (@arg ifname: [INTERFACE_NAME] "interface name") - (@arg json: -j --json "Show in json format") -+ (@subcommand iface => -+ (@arg json: -j --json "Show in json format") -+ (@arg ifname: [INTERFACE_NAME] "Show only specified interface") -+ (about: "Show interface") -+ ) - (@subcommand route => - (@arg json: -j --json "Show in json format") - (@arg dev: -d --dev [OIF] "Show only route entries with output to the specified interface") -@@ -162,13 +354,21 @@ fn main() { - } else { - let result = match NetState::retrieve() { - Ok(mut state) => { -- if let Some(ifname) = matches.value_of("ifname") { -- if let Some(iface) = state.ifaces.remove(ifname) { -- CliResult::Ifaces(vec![iface]) -+ if let Some(m) = matches.subcommand_matches("iface") { -+ output_format = parse_arg_output_format(m); -+ if let Some(ifname) = m.value_of("ifname") { -+ if let Some(iface) = state.ifaces.remove(ifname) { -+ CliResult::Ifaces(vec![iface]) -+ } else { -+ CliResult::CliError(CliError { -+ msg: format!( -+ "Interface '{}' not found", -+ ifname -+ ), -+ }) -+ } - } else { -- CliResult::CliError(CliError { -- msg: format!("Interface '{}' not found", ifname), -- }) -+ CliResult::Full(state) - } - } else if let Some(m) = matches.subcommand_matches("route") { - output_format = parse_arg_output_format(m); -@@ -176,9 +376,17 @@ fn main() { - } else if let Some(m) = matches.subcommand_matches("rule") { - output_format = parse_arg_output_format(m); - CliResult::RouteRules(state.rules) -+ } else if let Some(ifname) = matches.value_of("ifname") { -+ if let Some(iface) = state.ifaces.remove(ifname) { -+ CliResult::Ifaces(vec![iface]) -+ } else { -+ CliResult::CliError(CliError { -+ msg: format!("Interface '{}' not found", ifname), -+ }) -+ } - } else { - /* Show everything if no cmdline arg has been supplied */ -- CliResult::Full(state) -+ CliResult::Brief(CliIfaceBrief::from_net_state(&state)) - } - } - Err(e) => CliResult::NisporError(e), -diff --git a/src/lib/ifaces/iface.rs b/src/lib/ifaces/iface.rs -index ee71b0f..60afacd 100644 ---- a/src/lib/ifaces/iface.rs -+++ b/src/lib/ifaces/iface.rs -@@ -102,6 +102,23 @@ impl Default for IfaceState { - } - } - -+impl std::fmt::Display for IfaceState { -+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -+ write!( -+ f, -+ "{}", -+ match self { -+ Self::Up => "up", -+ Self::Dormant => "dormant", -+ Self::Down => "down", -+ Self::LowerLayerDown => "lower_layer_down", -+ Self::Other(s) => s.as_str(), -+ Self::Unknown => "unknown", -+ } -+ ) -+ } -+} -+ - #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] - #[serde(rename_all = "snake_case")] - pub enum IfaceFlags { --- -2.32.0 - diff --git a/SOURCES/0002-ethtool-feature-tx-lockless-is-not-changeable.patch b/SOURCES/0002-ethtool-feature-tx-lockless-is-not-changeable.patch deleted file mode 100644 index f86da69..0000000 --- a/SOURCES/0002-ethtool-feature-tx-lockless-is-not-changeable.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 235458b72fe54feb97349db4b139babc80821e58 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Fri, 4 Jun 2021 06:23:47 +0800 -Subject: [PATCH 2/3] ethtool feature: tx-lockless is not changeable - -Currently, the `tx-lockless` is shown as changeable, but it actually is -hard coded as not changeable by `NETIF_F_NEVER_CHANGE` in kernel. - -The kernel netlink use `ETHTOOL_A_FEATURES_NOCHANGE` for hard coded -non-changeable features, it take priority over `ETHTOOL_A_FEATURES_HW`. - -Integration test case included, but disable in CI as CI has no ethtool -netlink interface in kernel. - -Signed-off-by: Gris Ge ---- - src/lib/ifaces/ethtool.rs | 19 +++++++++- - src/lib/tests/dummy.rs | 74 +++++++++++++++++++++++++++++++++++++++ - 2 files changed, 92 insertions(+), 1 deletion(-) - -diff --git a/src/lib/ifaces/ethtool.rs b/src/lib/ifaces/ethtool.rs -index 7a5c08a..0697ad5 100644 ---- a/src/lib/ifaces/ethtool.rs -+++ b/src/lib/ifaces/ethtool.rs -@@ -313,6 +313,14 @@ async fn dump_feature_infos( - let mut fixed_features = HashMap::new(); - let mut changeable_features = HashMap::new(); - -+ for nla in &nlas { -+ if let FeatureAttr::NoChange(feature_bits) = nla { -+ for FeatureBit { name, .. } in feature_bits { -+ fixed_features.insert(name.to_string(), false); -+ } -+ } -+ } -+ - for nla in nlas { - if let FeatureAttr::Header(hdrs) = nla { - iface_name = get_iface_name_from_header(&hdrs); -@@ -324,7 +332,16 @@ async fn dump_feature_infos( - name, - value: true, - } => { -- changeable_features.insert(name, false); -+ // Dummy interface show `tx-lockless` is -+ // changeable, but FeatureAttr::NoChange() says -+ // otherwise. The kernel code -+ // `NETIF_F_NEVER_CHANGE` shows `tx-lockless` -+ // should never been changeable. -+ if fixed_features.contains_key(&name) { -+ fixed_features.insert(name, false); -+ } else { -+ changeable_features.insert(name, false); -+ } - } - FeatureBit { - index: _, -diff --git a/src/lib/tests/dummy.rs b/src/lib/tests/dummy.rs -index a0feed3..aab9ffd 100644 ---- a/src/lib/tests/dummy.rs -+++ b/src/lib/tests/dummy.rs -@@ -40,6 +40,66 @@ const EXPECTED_IFACE_STATE: &str = r#"--- - preferred_lft: forever - mac_address: "00:23:45:67:89:1a""#; - -+const EXPECTED_ETHTOOL_FEATURE: &str = r#"--- -+fixed: -+ esp-hw-offload: false -+ esp-tx-csum-hw-offload: false -+ fcoe-mtu: false -+ hw-tc-offload: false -+ l2-fwd-offload: false -+ loopback: false -+ macsec-hw-offload: false -+ netns-local: false -+ rx-all: false -+ rx-checksum: false -+ rx-fcs: false -+ rx-gro-hw: false -+ rx-hashing: false -+ rx-lro: false -+ rx-ntuple-filter: false -+ rx-udp_tunnel-port-offload: false -+ rx-vlan-filter: false -+ rx-vlan-hw-parse: false -+ rx-vlan-stag-filter: false -+ rx-vlan-stag-hw-parse: false -+ tls-hw-record: false -+ tls-hw-rx-offload: false -+ tls-hw-tx-offload: false -+ tx-checksum-fcoe-crc: false -+ tx-checksum-ipv4: false -+ tx-checksum-ipv6: false -+ tx-checksum-sctp: false -+ tx-esp-segmentation: false -+ tx-fcoe-segmentation: false -+ tx-gso-list: false -+ tx-gso-partial: false -+ tx-gso-robust: false -+ tx-lockless: true -+ tx-sctp-segmentation: false -+ tx-tunnel-remcsum-segmentation: false -+ tx-udp-segmentation: false -+ tx-vlan-hw-insert: false -+ tx-vlan-stag-hw-insert: false -+ vlan-challenged: false -+changeable: -+ highdma: true -+ rx-gro: true -+ rx-gro-list: false -+ tx-checksum-ip-generic: true -+ tx-generic-segmentation: true -+ tx-gre-csum-segmentation: true -+ tx-gre-segmentation: true -+ tx-ipxip4-segmentation: true -+ tx-ipxip6-segmentation: true -+ tx-nocache-copy: false -+ tx-scatter-gather-fraglist: true -+ tx-tcp-ecn-segmentation: true -+ tx-tcp-mangleid-segmentation: true -+ tx-tcp-segmentation: true -+ tx-tcp6-segmentation: true -+ tx-udp_tnl-csum-segmentation: true -+ tx-udp_tnl-segmentation: true"#; -+ - #[test] - fn test_get_iface_dummy_yaml() { - with_dummy_iface(|| { -@@ -54,6 +114,20 @@ fn test_get_iface_dummy_yaml() { - }); - } - -+#[test] -+#[ignore] // CI does not have ethtool_netlink kernel module yet -+fn test_get_iface_dummy_ethtool_feature() { -+ with_dummy_iface(|| { -+ let state = NetState::retrieve().unwrap(); -+ let iface = &state.ifaces[IFACE_NAME]; -+ assert_eq!( -+ serde_yaml::to_string(&iface.ethtool.as_ref().unwrap().features) -+ .unwrap(), -+ EXPECTED_ETHTOOL_FEATURE -+ ); -+ }); -+} -+ - fn with_dummy_iface(test: T) -> () - where - T: FnOnce() -> () + panic::UnwindSafe, --- -2.32.0 - diff --git a/SOURCES/0003-loopback-Fix-interface-type-of-loopback.patch b/SOURCES/0003-loopback-Fix-interface-type-of-loopback.patch deleted file mode 100644 index e0394a1..0000000 --- a/SOURCES/0003-loopback-Fix-interface-type-of-loopback.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 7ef2df7e8849f7f674c14190fb997fc3f0e7ba67 Mon Sep 17 00:00:00 2001 -From: Gris Ge -Date: Tue, 8 Jun 2021 16:59:31 +0800 -Subject: [PATCH 3/3] loopback: Fix interface type of loopback - -Using `IFF_LOOPBACK` interface flag to determine whether a interface is -loopback or not is incorrect as other type interface would also hold -this flag. - -Fixed to use `ARPHRD_LOOPBACK` from link_layer_type. - -Signed-off-by: Gris Ge ---- - src/lib/ifaces/iface.rs | 17 ++++++++--------- - 1 file changed, 8 insertions(+), 9 deletions(-) - -diff --git a/src/lib/ifaces/iface.rs b/src/lib/ifaces/iface.rs -index 60afacd..25ba558 100644 ---- a/src/lib/ifaces/iface.rs -+++ b/src/lib/ifaces/iface.rs -@@ -48,10 +48,10 @@ use crate::NisporError; - use netlink_packet_route::rtnl::link::nlas; - use netlink_packet_route::rtnl::LinkMessage; - use netlink_packet_route::rtnl::{ -- ARPHRD_ETHER, IFF_ALLMULTI, IFF_AUTOMEDIA, IFF_BROADCAST, IFF_DEBUG, -- IFF_DORMANT, IFF_LOOPBACK, IFF_LOWER_UP, IFF_MASTER, IFF_MULTICAST, -- IFF_NOARP, IFF_POINTOPOINT, IFF_PORTSEL, IFF_PROMISC, IFF_RUNNING, -- IFF_SLAVE, IFF_UP, -+ ARPHRD_ETHER, ARPHRD_LOOPBACK, IFF_ALLMULTI, IFF_AUTOMEDIA, IFF_BROADCAST, -+ IFF_DEBUG, IFF_DORMANT, IFF_LOOPBACK, IFF_LOWER_UP, IFF_MASTER, -+ IFF_MULTICAST, IFF_NOARP, IFF_POINTOPOINT, IFF_PORTSEL, IFF_PROMISC, -+ IFF_RUNNING, IFF_SLAVE, IFF_UP, - }; - use rtnetlink::new_connection; - -@@ -247,8 +247,10 @@ pub(crate) fn parse_nl_msg_to_iface( - name: name.clone(), - ..Default::default() - }; -- if nl_msg.header.link_layer_type == ARPHRD_ETHER { -- iface_state.iface_type = IfaceType::Ethernet -+ match nl_msg.header.link_layer_type { -+ ARPHRD_ETHER => iface_state.iface_type = IfaceType::Ethernet, -+ ARPHRD_LOOPBACK => iface_state.iface_type = IfaceType::Loopback, -+ _ => (), - } - iface_state.index = nl_msg.header.index; - let mut link: Option = None; -@@ -392,9 +394,6 @@ pub(crate) fn parse_nl_msg_to_iface( - _ => (), - } - } -- if (nl_msg.header.flags & IFF_LOOPBACK) > 0 { -- iface_state.iface_type = IfaceType::Loopback; -- } - iface_state.flags = _parse_iface_flags(nl_msg.header.flags); - Ok(Some(iface_state)) - } --- -2.32.0 - diff --git a/SPECS/nispor.spec b/SPECS/nispor.spec index e4197ab..598aa31 100644 --- a/SPECS/nispor.spec +++ b/SPECS/nispor.spec @@ -1,20 +1,100 @@ Name: nispor -Version: 1.1.0 -Release: 2%{?dist} +Version: 1.1.1 +Release: 1%{?dist} Summary: API for network status querying License: ASL 2.0 URL: https://github.com/nispor/nispor Source: https://github.com/nispor/nispor/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz Source1: %{name}-%{version}-vendor.tar.xz -Patch1: 0001-npc-Show-brief-network-state-when-no-argument.patch -Patch2: 0002-ethtool-feature-tx-lockless-is-not-changeable.patch -Patch3: 0003-loopback-Fix-interface-type-of-loopback.patch BuildRequires: pkg-config BuildRequires: python3-devel BuildRequires: rust-toolset BuildRequires: systemd-rpm-macros BuildRequires: systemd-devel +Provides: bundled(crate(aho-corasick)) = 0.7.15 +Provides: bundled(crate(ansi_term)) = 0.11.0 +Provides: bundled(crate(anyhow)) = 1.0.34 +Provides: bundled(crate(atty)) = 0.2.14 +Provides: bundled(crate(autocfg)) = 1.0.1 +Provides: bundled(crate(bitflags)) = 1.2.1 +Provides: bundled(crate(byteorder)) = 1.3.4 +Provides: bundled(crate(byteordered)) = 0.5.0 +Provides: bundled(crate(bytes)) = 0.5.6 +Provides: bundled(crate(bytes)) = 1.0.1 +Provides: bundled(crate(cc)) = 1.0.66 +Provides: bundled(crate(cfg-if)) = 1.0.0 +Provides: bundled(crate(clap)) = 2.33.3 +Provides: bundled(crate(ctor)) = 0.1.16 +Provides: bundled(crate(difference)) = 2.0.0 +Provides: bundled(crate(dtoa)) = 0.4.6 +Provides: bundled(crate(env_logger)) = 0.8.3 +Provides: bundled(crate(futures)) = 0.3.12 +Provides: bundled(crate(futures-channel)) = 0.3.12 +Provides: bundled(crate(futures-core)) = 0.3.12 +Provides: bundled(crate(futures-executor)) = 0.3.12 +Provides: bundled(crate(futures-io)) = 0.3.12 +Provides: bundled(crate(futures-macro)) = 0.3.12 +Provides: bundled(crate(futures-sink)) = 0.3.12 +Provides: bundled(crate(futures-task)) = 0.3.12 +Provides: bundled(crate(futures-util)) = 0.3.12 +Provides: bundled(crate(hermit-abi)) = 0.1.17 +Provides: bundled(crate(humantime)) = 2.1.0 +Provides: bundled(crate(itoa)) = 0.4.6 +Provides: bundled(crate(libc)) = 0.2.93 +Provides: bundled(crate(linked-hash-map)) = 0.5.3 +Provides: bundled(crate(log)) = 0.4.14 +Provides: bundled(crate(memchr)) = 2.3.4 +Provides: bundled(crate(mio)) = 0.7.7 +Provides: bundled(crate(miow)) = 0.3.6 +Provides: bundled(crate(netlink-packet-core)) = 0.2.4 +Provides: bundled(crate(netlink-packet-route)) = 0.7.0 +Provides: bundled(crate(netlink-packet-utils)) = 0.4.0 +Provides: bundled(crate(netlink-proto)) = 0.6.0 +Provides: bundled(crate(netlink-sys)) = 0.6.0 +Provides: bundled(crate(nix)) = 0.19.1 +Provides: bundled(crate(ntapi)) = 0.3.6 +Provides: bundled(crate(num_cpus)) = 1.13.0 +Provides: bundled(crate(once_cell)) = 1.4.1 +Provides: bundled(crate(output_vt100)) = 0.1.2 +Provides: bundled(crate(paste)) = 1.0.2 +Provides: bundled(crate(pin-project-lite)) = 0.1.12 +Provides: bundled(crate(pin-project-lite)) = 0.2.4 +Provides: bundled(crate(pin-utils)) = 0.1.0 +Provides: bundled(crate(pretty_assertions)) = 0.6.1 +Provides: bundled(crate(proc-macro2)) = 1.0.26 +Provides: bundled(crate(proc-macro-hack)) = 0.5.19 +Provides: bundled(crate(proc-macro-nested)) = 0.1.6 +Provides: bundled(crate(quote)) = 1.0.7 +Provides: bundled(crate(regex)) = 1.4.6 +Provides: bundled(crate(regex-syntax)) = 0.6.23 +Provides: bundled(crate(rtnetlink)) = 0.7.0 +Provides: bundled(crate(ryu)) = 1.0.5 +Provides: bundled(crate(serde)) = 1.0.117 +Provides: bundled(crate(serde_derive)) = 1.0.117 +Provides: bundled(crate(serde_json)) = 1.0.59 +Provides: bundled(crate(serde_yaml)) = 0.8.14 +Provides: bundled(crate(slab)) = 0.4.2 +Provides: bundled(crate(socket2)) = 0.3.19 +Provides: bundled(crate(strsim)) = 0.8.0 +Provides: bundled(crate(syn)) = 1.0.69 +Provides: bundled(crate(termcolor)) = 1.1.2 +Provides: bundled(crate(textwrap)) = 0.11.0 +Provides: bundled(crate(thiserror)) = 1.0.22 +Provides: bundled(crate(thiserror-impl)) = 1.0.22 +Provides: bundled(crate(tokio)) = 0.2.25 +Provides: bundled(crate(tokio)) = 1.1.1 +Provides: bundled(crate(tokio-macros)) = 1.0.0 +Provides: bundled(crate(tokio-util)) = 0.2.0 +Provides: bundled(crate(unicode-width)) = 0.1.8 +Provides: bundled(crate(unicode-xid)) = 0.2.1 +Provides: bundled(crate(vec_map)) = 0.8.2 +Provides: bundled(crate(winapi)) = 0.3.9 +Provides: bundled(crate(winapi-i686-pc-windows-gnu)) = 0.4.0 +Provides: bundled(crate(winapi-util)) = 0.1.5 +Provides: bundled(crate(winapi-x86_64-pc-windows-gnu)) = 0.4.0 +Provides: bundled(crate(yaml-rust)) = 0.4.4 + %description Unified interface for Linux network state querying. @@ -84,6 +164,12 @@ popd %{_libdir}/pkgconfig/nispor.pc %changelog +* Sat Jun 19 2021 Gris Ge - 1.1.1-1 +- Upgrade to 1.1.1. RHBZ#1942459 + +* Fri Jun 18 2021 Gris Ge - 1.1.0-3 +- Include SPEC information for bundled rust crates. RHBZ#1927789 + * Tue Jun 08 2021 Gris Ge - 1.1.0-2 - Fix cli output, loopback interface and ethtool features.