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
48 changes: 48 additions & 0 deletions src/link/af_spec/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,30 @@ impl From<BridgeFlag> for u16 {
}
}

impl std::fmt::Display for BridgeFlag {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Controller => f.write_str("master"),
Self::LowerDev => f.write_str("self"),
Self::Other(d) => write!(f, "{d}"),
}
}
}

impl std::str::FromStr for BridgeFlag {
type Err = DecodeError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"master" => Ok(Self::Controller),
"self" => Ok(Self::LowerDev),
_ => s.parse::<u16>().map(Self::from).map_err(|_| {
DecodeError::from(format!("unknown bridge flag: {s}"))
}),
}
}
}
Comment thread
cathay4t marked this conversation as resolved.

impl BridgeFlag {
pub const LENGTH: usize = 2;
}
Expand Down Expand Up @@ -259,6 +283,30 @@ impl From<BridgeMode> for u16 {
}
}

impl std::fmt::Display for BridgeMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Veb => f.write_str("veb"),
Self::Vepa => f.write_str("vepa"),
Self::Other(d) => write!(f, "{d}"),
}
}
}

impl std::str::FromStr for BridgeMode {
type Err = DecodeError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"veb" => Ok(Self::Veb),
"vepa" => Ok(Self::Vepa),
_ => s.parse::<u16>().map(Self::from).map_err(|_| {
DecodeError::from(format!("unknown bridge mode: {s}"))
}),
}
}
}
Comment thread
cathay4t marked this conversation as resolved.

impl BridgeMode {
pub const LENGTH: usize = 2;
}
Expand Down
56 changes: 56 additions & 0 deletions src/link/link_info/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,32 @@ impl From<BridgeStpState> for u32 {
}
}

impl std::fmt::Display for BridgeStpState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Disabled => f.write_str("no"),
Self::KernelStp => f.write_str("kernel_stp"),
Self::UserStp => f.write_str("user_stp"),
Self::Other(d) => write!(f, "{d}"),
}
}
}

impl std::str::FromStr for BridgeStpState {
type Err = DecodeError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"no" => Ok(Self::Disabled),
"kernel_stp" => Ok(Self::KernelStp),
"user_stp" => Ok(Self::UserStp),
_ => s.parse::<u32>().map(Self::from).map_err(|_| {
DecodeError::from(format!("unknown bridge STP state: {s}"))
}),
}
}
}
Comment thread
cathay4t marked this conversation as resolved.

const MDB_RTR_TYPE_DISABLED: u8 = 0;
const MDB_RTR_TYPE_TEMP_QUERY: u8 = 1;
const MDB_RTR_TYPE_PERM: u8 = 2;
Expand Down Expand Up @@ -787,3 +813,33 @@ impl From<BridgeMulticastRouterType> for u8 {
}
}
}

impl std::fmt::Display for BridgeMulticastRouterType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Disabled => f.write_str("disabled"),
Self::TempQuery => f.write_str("auto"),
Self::Permanent => f.write_str("permanent"),
Self::Temp => f.write_str("temp"),
Self::Other(d) => write!(f, "{d}"),
}
}
}

impl std::str::FromStr for BridgeMulticastRouterType {
type Err = DecodeError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"disabled" => Ok(Self::Disabled),
"auto" | "temp_query" => Ok(Self::TempQuery),
"permanent" => Ok(Self::Permanent),
"temp" => Ok(Self::Temp),
_ => s.parse::<u8>().map(Self::from).map_err(|_| {
DecodeError::from(format!(
"unknown bridge multicast router type: {s}"
))
}),
}
}
}
Comment thread
cathay4t marked this conversation as resolved.
30 changes: 30 additions & 0 deletions src/link/link_info/bridge_port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,3 +564,33 @@ impl From<BridgePortState> for u8 {
}
}
}

impl std::fmt::Display for BridgePortState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Disabled => f.write_str("disabled"),
Self::Listening => f.write_str("listening"),
Self::Learning => f.write_str("learning"),
Self::Forwarding => f.write_str("forwarding"),
Self::Blocking => f.write_str("blocking"),
Self::Other(d) => write!(f, "{d}"),
}
}
}

impl std::str::FromStr for BridgePortState {
type Err = DecodeError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"disabled" => Ok(Self::Disabled),
"listening" => Ok(Self::Listening),
"learning" => Ok(Self::Learning),
"forwarding" => Ok(Self::Forwarding),
"blocking" => Ok(Self::Blocking),
_ => s.parse::<u8>().map(Self::from).map_err(|_| {
DecodeError::from(format!("unknown bridge port state: {s}"))
}),
}
}
}
Comment thread
cathay4t marked this conversation as resolved.
141 changes: 141 additions & 0 deletions src/link/tests/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1231,3 +1231,144 @@ fn test_bridge_netns_immutable() {

expected.emit(&mut buf);
}

#[test]
fn test_bridge_flag_display() {
assert_eq!("master", BridgeFlag::Controller.to_string());
assert_eq!("self", BridgeFlag::LowerDev.to_string());
assert_eq!("255", BridgeFlag::Other(255).to_string());
}

#[test]
fn test_bridge_flag_from_str() {
use std::str::FromStr;
assert_eq!(BridgeFlag::Controller, "master".parse().unwrap());
assert_eq!(BridgeFlag::LowerDev, "self".parse().unwrap());
assert_eq!(BridgeFlag::from(1), "1".parse().unwrap());
assert_eq!(BridgeFlag::from(2), "2".parse().unwrap());
assert_eq!(BridgeFlag::Other(99), "99".parse().unwrap());
assert!(BridgeFlag::from_str("bogus").is_err());
}

#[test]
fn test_bridge_mode_display() {
assert_eq!("veb", BridgeMode::Veb.to_string());
assert_eq!("vepa", BridgeMode::Vepa.to_string());
assert_eq!("255", BridgeMode::Other(255).to_string());
}

#[test]
fn test_bridge_mode_from_str() {
use std::str::FromStr;
assert_eq!(BridgeMode::Veb, "veb".parse().unwrap());
assert_eq!(BridgeMode::Vepa, "vepa".parse().unwrap());
assert_eq!(BridgeMode::from(0), "0".parse().unwrap());
assert_eq!(BridgeMode::from(1), "1".parse().unwrap());
assert_eq!(BridgeMode::Other(99), "99".parse().unwrap());
assert!(BridgeMode::from_str("bogus").is_err());
}

#[test]
fn test_bridge_stp_state_display() {
assert_eq!("no", BridgeStpState::Disabled.to_string());
assert_eq!("kernel_stp", BridgeStpState::KernelStp.to_string());
assert_eq!("user_stp", BridgeStpState::UserStp.to_string());
assert_eq!("255", BridgeStpState::Other(255).to_string());
}

#[test]
fn test_bridge_stp_state_from_str() {
use std::str::FromStr;
assert_eq!(BridgeStpState::Disabled, "no".parse().unwrap());
assert_eq!(BridgeStpState::KernelStp, "kernel_stp".parse().unwrap());
assert_eq!(BridgeStpState::UserStp, "user_stp".parse().unwrap());
assert_eq!(BridgeStpState::Disabled, "0".parse().unwrap());
assert_eq!(BridgeStpState::KernelStp, "1".parse().unwrap());
assert_eq!(BridgeStpState::UserStp, "2".parse().unwrap());
assert_eq!(BridgeStpState::Other(99), "99".parse().unwrap());
assert!(BridgeStpState::from_str("bogus").is_err());
}

#[test]
fn test_bridge_multicast_router_type_display() {
assert_eq!("disabled", BridgeMulticastRouterType::Disabled.to_string());
assert_eq!("auto", BridgeMulticastRouterType::TempQuery.to_string());
assert_eq!(
"permanent",
BridgeMulticastRouterType::Permanent.to_string()
);
assert_eq!("temp", BridgeMulticastRouterType::Temp.to_string());
assert_eq!("255", BridgeMulticastRouterType::Other(255).to_string());
}

#[test]
fn test_bridge_multicast_router_type_from_str() {
use std::str::FromStr;
assert_eq!(
BridgeMulticastRouterType::Disabled,
"disabled".parse().unwrap()
);
assert_eq!(
BridgeMulticastRouterType::TempQuery,
"auto".parse().unwrap()
);
assert_eq!(
BridgeMulticastRouterType::TempQuery,
"temp_query".parse().unwrap()
);
assert_eq!(
BridgeMulticastRouterType::Permanent,
"permanent".parse().unwrap()
);
assert_eq!(BridgeMulticastRouterType::Temp, "temp".parse().unwrap());
assert_eq!(BridgeMulticastRouterType::from(0), "0".parse().unwrap());
assert_eq!(BridgeMulticastRouterType::from(1), "1".parse().unwrap());
assert_eq!(BridgeMulticastRouterType::from(2), "2".parse().unwrap());
assert_eq!(BridgeMulticastRouterType::from(3), "3".parse().unwrap());
assert_eq!(BridgeMulticastRouterType::Other(99), "99".parse().unwrap());
assert!(BridgeMulticastRouterType::from_str("bogus").is_err());
}

#[test]
fn test_bridge_port_state_display() {
assert_eq!("disabled", BridgePortState::Disabled.to_string());
assert_eq!("listening", BridgePortState::Listening.to_string());
assert_eq!("learning", BridgePortState::Learning.to_string());
assert_eq!("forwarding", BridgePortState::Forwarding.to_string());
assert_eq!("blocking", BridgePortState::Blocking.to_string());
assert_eq!("255", BridgePortState::Other(255).to_string());
}

#[test]
fn test_bridge_port_state_from_str() {
use std::str::FromStr;
assert_eq!(BridgePortState::Disabled, "disabled".parse().unwrap());
assert_eq!(BridgePortState::Listening, "listening".parse().unwrap());
assert_eq!(BridgePortState::Learning, "learning".parse().unwrap());
assert_eq!(BridgePortState::Forwarding, "forwarding".parse().unwrap());
assert_eq!(BridgePortState::Blocking, "blocking".parse().unwrap());
assert_eq!(BridgePortState::from(0), "0".parse().unwrap());
assert_eq!(BridgePortState::from(1), "1".parse().unwrap());
assert_eq!(BridgePortState::from(2), "2".parse().unwrap());
assert_eq!(BridgePortState::from(3), "3".parse().unwrap());
assert_eq!(BridgePortState::from(4), "4".parse().unwrap());
assert_eq!(BridgePortState::Other(99), "99".parse().unwrap());
assert!(BridgePortState::from_str("bogus").is_err());
}

#[test]
fn test_vlan_protocol_display() {
assert_eq!("802.1q", VlanProtocol::Ieee8021Q.to_string());
assert_eq!("802.1ad", VlanProtocol::Ieee8021Ad.to_string());
}

#[test]
fn test_vlan_protocol_from_str() {
use std::str::FromStr;
assert_eq!(VlanProtocol::Ieee8021Q, "802.1q".parse().unwrap());
assert_eq!(VlanProtocol::Ieee8021Ad, "802.1ad".parse().unwrap());
assert_eq!(VlanProtocol::Ieee8021Q, "802.1Q".parse().unwrap());
assert_eq!(VlanProtocol::Ieee8021Ad, "802.1AD".parse().unwrap());
assert!(VlanProtocol::from_str("bogus").is_err());
assert!(VlanProtocol::from_str("802.1Qq").is_err());
}
16 changes: 16 additions & 0 deletions src/link/vlan_protocol.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT

use netlink_packet_core::DecodeError;

const ETH_P_8021Q: u16 = 0x8100;
const ETH_P_8021AD: u16 = 0x88A8;

Expand Down Expand Up @@ -51,3 +53,17 @@ impl std::fmt::Display for VlanProtocol {
)
}
}

impl std::str::FromStr for VlanProtocol {
type Err = DecodeError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.eq_ignore_ascii_case("802.1q") {
Ok(Self::Ieee8021Q)
} else if s.eq_ignore_ascii_case("802.1ad") {
Ok(Self::Ieee8021Ad)
} else {
Err(DecodeError::from(format!("unknown VLAN protocol: {s}")))
}
}
}
Comment thread
cathay4t marked this conversation as resolved.
Loading