use serde::{Deserialize, Serialize};
use crate::{
BaseInterface, ErrorKind, Interface, InterfaceType, MergedInterface,
NmstateError,
};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct VrfInterface {
#[serde(flatten)]
pub base: BaseInterface,
#[serde(skip_serializing_if = "Option::is_none")]
pub vrf: Option<VrfConfig>,
}
impl Default for VrfInterface {
fn default() -> Self {
Self {
base: BaseInterface {
iface_type: InterfaceType::Vrf,
..Default::default()
},
vrf: None,
}
}
}
impl VrfInterface {
pub fn new() -> Self {
Self::default()
}
pub fn ports(&self) -> Option<Vec<&str>> {
self.vrf
.as_ref()
.and_then(|vrf_conf| vrf_conf.port.as_ref())
.map(|ports| ports.as_slice().iter().map(|p| p.as_str()).collect())
}
pub(crate) fn sanitize(
&mut self,
is_desired: bool,
) -> Result<(), NmstateError> {
if is_desired {
if let Some(mac) = self.base.mac_address.as_ref() {
log::warn!(
"Ignoring MAC address {mac} of VRF interface {} \
as it is a layer 3(IP) interface",
self.base.name.as_str()
);
}
}
self.base.mac_address = None;
if self.base.accept_all_mac_addresses == Some(false) {
self.base.accept_all_mac_addresses = None;
}
if let Some(ports) = self.vrf.as_mut().and_then(|c| c.port.as_mut()) {
ports.sort();
}
Ok(())
}
pub(crate) fn merge_table_id(
&mut self,
current: Option<&Interface>,
) -> Result<(), NmstateError> {
if self.vrf.as_ref().map(|v| v.table_id) == Some(0) {
if let Some(&Interface::Vrf(VrfInterface {
vrf:
Some(VrfConfig {
table_id: cur_table_id,
..
}),
..
})) = current
{
if let Some(vrf_conf) = self.vrf.as_mut() {
vrf_conf.table_id = cur_table_id;
}
} else {
let e = NmstateError::new(
ErrorKind::InvalidArgument,
format!(
"Route table ID undefined or 0 is not allowed for \
new VRF interface {}",
self.base.name
),
);
log::error!("{}", e);
return Err(e);
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[non_exhaustive]
#[serde(deny_unknown_fields)]
pub struct VrfConfig {
#[serde(alias = "ports")]
pub port: Option<Vec<String>>,
#[serde(
rename = "route-table-id",
default,
deserialize_with = "crate::deserializer::u32_or_string"
)]
pub table_id: u32,
}
impl MergedInterface {
pub(crate) fn post_inter_ifaces_process_vrf(
&mut self,
) -> Result<(), NmstateError> {
if let Some(Interface::Vrf(apply_iface)) = self.for_apply.as_mut() {
apply_iface.merge_table_id(self.current.as_ref())?;
}
if let Some(Interface::Vrf(verify_iface)) = self.for_verify.as_mut() {
verify_iface.merge_table_id(self.current.as_ref())?;
}
Ok(())
}
}