linux bridge: Handle group-fwd-mask conflict with group-forward-mask

The `group-forward-mask` is alias of `group-fwd-mask` for backwards
compatibility.

User should get InvalidArgument error when these two options are
conflicting. For other valid use cases, they all unified into
`group-fwd-mast` for applying and verifying.

Unit test cases included.

Signed-off-by: Gris Ge <fge@redhat.com>
This commit is contained in:
Gris Ge 2023-01-12 14:07:14 +08:00 committed by Fernando Fernández Mancera
parent c2e69269f9
commit e079f1d9e7
2 changed files with 126 additions and 1 deletions

View File

@ -101,6 +101,11 @@ impl LinuxBridgeInterface {
}
pub(crate) fn sanitize(&mut self) -> Result<(), NmstateError> {
if let Some(opts) =
self.bridge.as_mut().and_then(|b| b.options.as_mut())
{
opts.sanitize_group_fwd_mask(&self.base)?;
}
self.sort_ports();
self.sanitize_stp_opts()?;
self.use_upper_case_of_mac_address();
@ -437,13 +442,14 @@ pub struct LinuxBridgeOptions {
default,
deserialize_with = "crate::deserializer::option_u16_or_string"
)]
/// Alias of [LinuxBridgeOptions.group_fwd_mask], not preferred, please
/// use [LinuxBridgeOptions.group_fwd_mask] instead.
pub group_forward_mask: Option<u16>,
#[serde(
skip_serializing_if = "Option::is_none",
default,
deserialize_with = "crate::deserializer::option_u16_or_string"
)]
/// Alias of [LinuxBridgeOptions.group_fwd_mask]
pub group_fwd_mask: Option<u16>,
#[serde(
skip_serializing_if = "Option::is_none",
@ -541,6 +547,41 @@ impl LinuxBridgeOptions {
pub fn new() -> Self {
Self::default()
}
pub(crate) fn sanitize_group_fwd_mask(
&mut self,
base_iface: &BaseInterface,
) -> Result<(), NmstateError> {
match (self.group_forward_mask, self.group_fwd_mask) {
(Some(v1), Some(v2)) => {
if v1 != v2 {
return Err(NmstateError::new(
ErrorKind::InvalidArgument,
format!(
"Linux bridge {} has different \
group_forward_mask: {v1}, group_fwd_mask: {v2}, \
these two property is the same, hence conflicting",
base_iface.name.as_str()
),
));
} else {
self.group_fwd_mask = Some(v1);
self.group_forward_mask = None;
}
}
(Some(v), None) => {
self.group_fwd_mask = Some(v);
self.group_forward_mask = None;
}
(None, Some(v)) => {
self.group_fwd_mask = Some(v);
self.group_forward_mask = None;
}
_ => (),
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]

View File

@ -635,3 +635,87 @@ fn test_bridge_vlan_filter_no_trunk_tags_with_trunk_mode() {
assert_eq!(e.kind(), ErrorKind::InvalidArgument);
}
}
#[test]
fn test_bridge_validate_diff_group_forward_mask_and_group_fwd_mask() {
let mut desired: LinuxBridgeInterface = serde_yaml::from_str(
r#"
name: br0
type: linux-bridge
state: up
bridge:
options:
group-forward-mask: 1
group-fwd-mask: 2
"#,
)
.unwrap();
let result = desired.sanitize();
assert!(result.is_err());
if let Err(e) = result {
assert_eq!(e.kind(), ErrorKind::InvalidArgument);
assert!(e
.msg()
.contains("Linux bridge br0 has different group_forward_mask:"));
}
}
#[test]
fn test_bridge_sanitize_group_forward_mask_and_group_fwd_mask() {
let mut desired_both: LinuxBridgeInterface = serde_yaml::from_str(
r#"
name: br0
type: linux-bridge
state: up
bridge:
options:
group-forward-mask: 1
group-fwd-mask: 1
"#,
)
.unwrap();
desired_both.sanitize().unwrap();
let mut desired_old: LinuxBridgeInterface = serde_yaml::from_str(
r#"
name: br0
type: linux-bridge
state: up
bridge:
options:
group-forward-mask: 1
"#,
)
.unwrap();
desired_old.sanitize().unwrap();
let mut desired_new: LinuxBridgeInterface = serde_yaml::from_str(
r#"
name: br0
type: linux-bridge
state: up
bridge:
options:
group-fwd-mask: 1
"#,
)
.unwrap();
desired_new.sanitize().unwrap();
let expected: LinuxBridgeInterface = serde_yaml::from_str(
r#"
name: br0
type: linux-bridge
state: up
bridge:
options:
group-fwd-mask: 1
"#,
)
.unwrap();
assert_eq!(desired_both, expected);
assert_eq!(desired_old, expected);
assert_eq!(desired_new, expected);
}