use std::collections::HashSet;
use serde::{Deserialize, Deserializer, Serialize};
use crate::{
BaseInterface, BondInterface, DummyInterface, ErrorKind, EthernetInterface,
HsrInterface, InfiniBandInterface, IpsecInterface, LinuxBridgeInterface,
LoopbackInterface, MacSecInterface, MacVlanInterface, MacVtapInterface,
NmstateError, OvsBridgeInterface, OvsInterface, VlanInterface,
VrfInterface, VxlanInterface, XfrmInterface,
};
use crate::state::merge_json_value;
#[derive(
Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
)]
#[non_exhaustive]
#[serde(rename_all = "kebab-case")]
pub enum InterfaceType {
Bond,
LinuxBridge,
Dummy,
Ethernet,
Hsr,
Loopback,
MacVlan,
MacVtap,
OvsBridge,
OvsInterface,
Veth,
Vlan,
Vrf,
Vxlan,
#[serde(rename = "infiniband")]
InfiniBand,
Tun,
#[serde(rename = "macsec")]
MacSec,
Ipsec,
Xfrm,
Unknown,
#[serde(untagged)]
Other(String),
}
impl Default for InterfaceType {
fn default() -> Self {
Self::Unknown
}
}
impl std::fmt::Display for InterfaceType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
InterfaceType::Bond => "bond",
InterfaceType::LinuxBridge => "linux-bridge",
InterfaceType::Dummy => "dummy",
InterfaceType::Ethernet => "ethernet",
InterfaceType::Hsr => "hsr",
InterfaceType::Loopback => "loopback",
InterfaceType::MacVlan => "mac-vlan",
InterfaceType::MacVtap => "mac-vtap",
InterfaceType::OvsBridge => "ovs-bridge",
InterfaceType::OvsInterface => "ovs-interface",
InterfaceType::Veth => "veth",
InterfaceType::Vlan => "vlan",
InterfaceType::Vrf => "vrf",
InterfaceType::Vxlan => "vxlan",
InterfaceType::InfiniBand => "infiniband",
InterfaceType::Unknown => "unknown",
InterfaceType::Tun => "tun",
InterfaceType::MacSec => "macsec",
InterfaceType::Ipsec => "ipsec",
InterfaceType::Xfrm => "xfrm",
InterfaceType::Other(ref s) => s,
}
)
}
}
impl InterfaceType {
const USERSPACE_IFACE_TYPES: [Self; 2] = [Self::OvsBridge, Self::Ipsec];
const CONTROLLER_IFACES_TYPES: [Self; 4] =
[Self::Bond, Self::LinuxBridge, Self::OvsBridge, Self::Vrf];
pub(crate) fn is_userspace(&self) -> bool {
self.is_other() || Self::USERSPACE_IFACE_TYPES.contains(self)
}
pub(crate) fn is_other(&self) -> bool {
matches!(self, Self::Other(_))
}
pub(crate) fn is_controller(&self) -> bool {
Self::CONTROLLER_IFACES_TYPES.contains(self)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[non_exhaustive]
pub enum InterfaceState {
Up,
Down,
Absent,
Unknown,
Ignore,
}
impl Default for InterfaceState {
fn default() -> Self {
Self::Up
}
}
impl From<&str> for InterfaceState {
fn from(s: &str) -> Self {
match s {
"up" => Self::Up,
"down" => Self::Down,
"absent" => Self::Absent,
"ignore" => Self::Ignore,
_ => Self::Unknown,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Default)]
#[non_exhaustive]
pub struct UnknownInterface {
#[serde(flatten)]
pub base: BaseInterface,
#[serde(flatten)]
pub(crate) other: serde_json::Value,
}
impl UnknownInterface {
pub fn new() -> Self {
Self::default()
}
}
impl<'de> Deserialize<'de> for UnknownInterface {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let mut ret = UnknownInterface::default();
let mut v = serde_json::Map::deserialize(deserializer)?;
let mut base_value = serde_json::map::Map::new();
if let Some(n) = v.remove("name") {
base_value.insert("name".to_string(), n);
}
if let Some(s) = v.remove("state") {
base_value.insert("state".to_string(), s);
}
ret.base = BaseInterface::deserialize(
serde_json::value::Value::Object(base_value),
)
.map_err(serde::de::Error::custom)?;
ret.other = serde_json::Value::Object(v);
Ok(ret)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "kebab-case", untagged)]
#[non_exhaustive]
pub enum Interface {
Bond(BondInterface),
Dummy(DummyInterface),
Ethernet(EthernetInterface),
Hsr(HsrInterface),
LinuxBridge(LinuxBridgeInterface),
OvsBridge(OvsBridgeInterface),
OvsInterface(OvsInterface),
Unknown(UnknownInterface),
Vlan(VlanInterface),
Vxlan(VxlanInterface),
MacVlan(MacVlanInterface),
MacVtap(MacVtapInterface),
Vrf(VrfInterface),
InfiniBand(InfiniBandInterface),
Loopback(LoopbackInterface),
MacSec(MacSecInterface),
Ipsec(IpsecInterface),
Xfrm(XfrmInterface),
}
impl<'de> Deserialize<'de> for Interface {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let mut v = serde_json::Value::deserialize(deserializer)?;
if matches!(
Option::deserialize(&v["state"])
.map_err(serde::de::Error::custom)?,
Some(InterfaceState::Absent)
) {
let mut new_value = serde_json::map::Map::new();
if let Some(n) = v.get("name") {
new_value.insert("name".to_string(), n.clone());
}
if let Some(t) = v.get("type") {
new_value.insert("type".to_string(), t.clone());
}
if let Some(s) = v.get("state") {
new_value.insert("state".to_string(), s.clone());
}
v = serde_json::value::Value::Object(new_value);
}
match Option::deserialize(&v["type"])
.map_err(serde::de::Error::custom)?
{
Some(InterfaceType::Ethernet) => {
let inner = EthernetInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Ethernet(inner))
}
Some(InterfaceType::LinuxBridge) => {
let inner = LinuxBridgeInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::LinuxBridge(inner))
}
Some(InterfaceType::Bond) => {
let inner = BondInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Bond(inner))
}
Some(InterfaceType::Veth) => {
let inner = EthernetInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Ethernet(inner))
}
Some(InterfaceType::Vlan) => {
let inner = VlanInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Vlan(inner))
}
Some(InterfaceType::Vxlan) => {
let inner = VxlanInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Vxlan(inner))
}
Some(InterfaceType::Dummy) => {
let inner = DummyInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Dummy(inner))
}
Some(InterfaceType::OvsInterface) => {
let inner = OvsInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::OvsInterface(inner))
}
Some(InterfaceType::OvsBridge) => {
let inner = OvsBridgeInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::OvsBridge(inner))
}
Some(InterfaceType::MacVlan) => {
let inner = MacVlanInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::MacVlan(inner))
}
Some(InterfaceType::MacVtap) => {
let inner = MacVtapInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::MacVtap(inner))
}
Some(InterfaceType::Vrf) => {
let inner = VrfInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Vrf(inner))
}
Some(InterfaceType::Hsr) => {
let inner = HsrInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Hsr(inner))
}
Some(InterfaceType::InfiniBand) => {
let inner = InfiniBandInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::InfiniBand(inner))
}
Some(InterfaceType::Loopback) => {
let inner = LoopbackInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Loopback(inner))
}
Some(InterfaceType::MacSec) => {
let inner = MacSecInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::MacSec(inner))
}
Some(InterfaceType::Ipsec) => {
let inner = IpsecInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Ipsec(inner))
}
Some(InterfaceType::Xfrm) => {
let inner = XfrmInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Xfrm(inner))
}
Some(iface_type) => {
log::warn!("Unsupported interface type {}", iface_type);
let inner = UnknownInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Unknown(inner))
}
None => {
let inner = UnknownInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Unknown(inner))
}
}
}
}
impl Interface {
pub fn name(&self) -> &str {
self.base_iface().name.as_str()
}
pub(crate) fn is_userspace(&self) -> bool {
self.base_iface().iface_type.is_userspace()
}
pub(crate) fn is_controller(&self) -> bool {
self.base_iface().iface_type.is_controller()
}
pub fn iface_type(&self) -> InterfaceType {
self.base_iface().iface_type.clone()
}
pub(crate) fn clone_name_type_only(&self) -> Self {
match self {
Self::LinuxBridge(iface) => {
let mut new_iface = LinuxBridgeInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::LinuxBridge(new_iface)
}
Self::Ethernet(iface) => {
let mut new_iface = EthernetInterface::new();
new_iface.base = iface.base.clone_name_type_only();
new_iface.base.iface_type = InterfaceType::Ethernet;
Self::Ethernet(new_iface)
}
Self::Vlan(iface) => {
let mut new_iface = VlanInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::Vlan(new_iface)
}
Self::Vxlan(iface) => {
let mut new_iface = VxlanInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::Vxlan(new_iface)
}
Self::Dummy(iface) => {
let mut new_iface = DummyInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::Dummy(new_iface)
}
Self::OvsInterface(iface) => {
let mut new_iface = OvsInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::OvsInterface(new_iface)
}
Self::OvsBridge(iface) => {
let mut new_iface = OvsBridgeInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::OvsBridge(new_iface)
}
Self::Bond(iface) => {
let mut new_iface = BondInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::Bond(new_iface)
}
Self::MacVlan(iface) => {
let mut new_iface = MacVlanInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::MacVlan(new_iface)
}
Self::MacVtap(iface) => {
let mut new_iface = MacVtapInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::MacVtap(new_iface)
}
Self::Vrf(iface) => {
let mut new_iface = VrfInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::Vrf(new_iface)
}
Self::Hsr(iface) => {
let mut new_iface = HsrInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::Hsr(new_iface)
}
Self::InfiniBand(iface) => {
let new_iface = InfiniBandInterface {
base: iface.base.clone_name_type_only(),
..Default::default()
};
Self::InfiniBand(new_iface)
}
Self::Loopback(iface) => {
let mut new_iface = LoopbackInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::Loopback(new_iface)
}
Self::MacSec(iface) => {
let mut new_iface = MacSecInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::MacSec(new_iface)
}
Self::Ipsec(iface) => {
let mut new_iface = IpsecInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::Ipsec(new_iface)
}
Self::Xfrm(iface) => {
let mut new_iface = XfrmInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::Xfrm(new_iface)
}
Self::Unknown(iface) => {
let mut new_iface = UnknownInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::Unknown(new_iface)
}
}
}
pub fn is_up(&self) -> bool {
self.base_iface().state == InterfaceState::Up
}
pub fn is_absent(&self) -> bool {
self.base_iface().state == InterfaceState::Absent
}
pub fn is_down(&self) -> bool {
self.base_iface().state == InterfaceState::Down
}
pub fn is_ignore(&self) -> bool {
self.base_iface().state == InterfaceState::Ignore
}
pub(crate) fn is_up_exist_config(&self) -> bool {
self.is_up()
&& match serde_json::to_value(self) {
Ok(v) => {
if let Some(obj) = v.as_object() {
obj.len() == 3
} else {
log::error!(
"BUG: is_up_exist_connection() got \
unexpected(not object) serde_json::to_value() \
return {}",
v
);
false
}
}
Err(e) => {
log::error!(
"BUG: is_up_exist_connection() got unexpected \
serde_json::to_value() failure {}",
e
);
false
}
}
}
pub fn is_virtual(&self) -> bool {
!matches!(
self,
Self::Ethernet(_)
| Self::Unknown(_)
| Self::InfiniBand(_)
| Self::Loopback(_)
)
}
pub fn need_controller(&self) -> bool {
matches!(self, Self::OvsInterface(_))
}
pub fn base_iface(&self) -> &BaseInterface {
match self {
Self::LinuxBridge(iface) => &iface.base,
Self::Bond(iface) => &iface.base,
Self::Ethernet(iface) => &iface.base,
Self::Hsr(iface) => &iface.base,
Self::Vlan(iface) => &iface.base,
Self::Vxlan(iface) => &iface.base,
Self::Dummy(iface) => &iface.base,
Self::OvsBridge(iface) => &iface.base,
Self::OvsInterface(iface) => &iface.base,
Self::MacVlan(iface) => &iface.base,
Self::MacVtap(iface) => &iface.base,
Self::Vrf(iface) => &iface.base,
Self::InfiniBand(iface) => &iface.base,
Self::Loopback(iface) => &iface.base,
Self::MacSec(iface) => &iface.base,
Self::Ipsec(iface) => &iface.base,
Self::Xfrm(iface) => &iface.base,
Self::Unknown(iface) => &iface.base,
}
}
pub fn base_iface_mut(&mut self) -> &mut BaseInterface {
match self {
Self::LinuxBridge(iface) => &mut iface.base,
Self::Bond(iface) => &mut iface.base,
Self::Ethernet(iface) => &mut iface.base,
Self::Hsr(iface) => &mut iface.base,
Self::Vlan(iface) => &mut iface.base,
Self::Vxlan(iface) => &mut iface.base,
Self::Dummy(iface) => &mut iface.base,
Self::OvsInterface(iface) => &mut iface.base,
Self::OvsBridge(iface) => &mut iface.base,
Self::MacVlan(iface) => &mut iface.base,
Self::MacVtap(iface) => &mut iface.base,
Self::Vrf(iface) => &mut iface.base,
Self::InfiniBand(iface) => &mut iface.base,
Self::Loopback(iface) => &mut iface.base,
Self::MacSec(iface) => &mut iface.base,
Self::Ipsec(iface) => &mut iface.base,
Self::Xfrm(iface) => &mut iface.base,
Self::Unknown(iface) => &mut iface.base,
}
}
pub fn ports(&self) -> Option<Vec<&str>> {
if self.is_absent() {
match self {
Self::LinuxBridge(_) => Some(Vec::new()),
Self::OvsBridge(_) => Some(Vec::new()),
Self::Bond(_) => Some(Vec::new()),
Self::Vrf(_) => Some(Vec::new()),
_ => None,
}
} else {
match self {
Self::LinuxBridge(iface) => iface.ports(),
Self::OvsBridge(iface) => iface.ports(),
Self::Bond(iface) => iface.ports(),
Self::Vrf(iface) => iface.ports(),
_ => None,
}
}
}
pub(crate) fn sanitize(
&mut self,
is_desired: bool,
) -> Result<(), NmstateError> {
self.base_iface_mut().sanitize(is_desired)?;
match self {
Interface::Ethernet(iface) => iface.sanitize()?,
Interface::Hsr(iface) => iface.sanitize(is_desired)?,
Interface::LinuxBridge(iface) => iface.sanitize(is_desired)?,
Interface::OvsInterface(iface) => iface.sanitize(is_desired)?,
Interface::OvsBridge(iface) => iface.sanitize(is_desired)?,
Interface::Vrf(iface) => iface.sanitize(is_desired)?,
Interface::Bond(iface) => iface.sanitize()?,
Interface::MacVlan(iface) => iface.sanitize(is_desired)?,
Interface::MacVtap(iface) => iface.sanitize(is_desired)?,
Interface::Loopback(iface) => iface.sanitize(is_desired)?,
Interface::MacSec(iface) => iface.sanitize(is_desired)?,
Interface::Ipsec(iface) => iface.sanitize(is_desired),
_ => (),
}
Ok(())
}
pub(crate) fn parent(&self) -> Option<&str> {
match self {
Interface::Vlan(vlan) => vlan.parent(),
Interface::Vxlan(vxlan) => vxlan.parent(),
Interface::OvsInterface(ovs) => ovs.parent(),
Interface::MacVlan(vlan) => vlan.parent(),
Interface::MacVtap(vtap) => vtap.parent(),
Interface::InfiniBand(ib) => ib.parent(),
Interface::MacSec(macsec) => macsec.parent(),
_ => None,
}
}
pub(crate) fn remove_port(&mut self, port_name: &str) {
if let Interface::LinuxBridge(br_iface) = self {
br_iface.remove_port(port_name);
} else if let Interface::OvsBridge(br_iface) = self {
br_iface.remove_port(port_name);
} else if let Interface::Bond(iface) = self {
iface.remove_port(port_name);
}
}
pub(crate) fn change_port_name(
&mut self,
org_port_name: &str,
new_port_name: String,
) {
if let Interface::LinuxBridge(iface) = self {
iface.change_port_name(org_port_name, new_port_name);
} else if let Interface::OvsBridge(iface) = self {
iface.change_port_name(org_port_name, new_port_name);
} else if let Interface::Bond(iface) = self {
iface.change_port_name(org_port_name, new_port_name);
}
}
}
#[allow(clippy::derivable_impls)]
impl Default for Interface {
fn default() -> Self {
Interface::Unknown(UnknownInterface::default())
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub(crate) struct MergedInterface {
pub(crate) for_verify: Option<Interface>,
pub(crate) for_apply: Option<Interface>,
pub(crate) merged: Interface,
pub(crate) desired: Option<Interface>,
pub(crate) current: Option<Interface>,
}
impl MergedInterface {
pub(crate) fn new(
desired: Option<Interface>,
current: Option<Interface>,
) -> Result<Self, NmstateError> {
let mut ret = Self {
for_verify: desired.clone(),
for_apply: desired.clone(),
merged: {
match (desired.as_ref(), current.as_ref()) {
(Some(d), Some(c)) => merge_desire_with_current(d, c)?,
(Some(d), None) => d.clone(),
(None, Some(c)) => c.clone(),
(None, None) => {
return Err(NmstateError::new(
ErrorKind::Bug,
"BUG: MergedInterface got both desired \
and current set to None"
.to_string(),
));
}
}
},
desired,
current,
};
ret.pre_inter_ifaces_process();
Ok(ret)
}
pub(crate) fn is_desired(&self) -> bool {
self.desired.is_some()
}
pub(crate) fn is_changed(&self) -> bool {
self.for_apply.is_some()
}
fn pre_inter_ifaces_process(&mut self) {
if self.merged.is_up() && self.is_desired() {
self.special_merge();
self.create_ovs_iface_for_empty_ports();
}
}
pub(crate) fn post_inter_ifaces_process(
&mut self,
) -> Result<(), NmstateError> {
self.preserve_current_controller_info();
self.post_inter_ifaces_process_base_iface()?;
self.post_inter_ifaces_process_sriov()?;
self.post_inter_ifaces_process_vrf()?;
self.post_inter_ifaces_process_bond()?;
if let Some(apply_iface) = self.for_apply.as_mut() {
apply_iface.sanitize(true)?;
}
Ok(())
}
fn special_merge(&mut self) {
if let (Some(desired), Some(current)) =
(self.desired.as_ref(), self.current.as_ref())
{
self.merged
.base_iface_mut()
.special_merge(desired.base_iface(), current.base_iface());
if let Interface::Bond(bond_iface) = &mut self.merged {
if let (
Interface::Bond(des_bond_iface),
Interface::Bond(cur_bond_iface),
) = (desired, current)
{
bond_iface.special_merge(des_bond_iface, cur_bond_iface);
}
} else if let Interface::LinuxBridge(br_iface) = &mut self.merged {
if let (
Interface::LinuxBridge(des_br_iface),
Interface::LinuxBridge(cur_br_iface),
) = (desired, current)
{
br_iface.special_merge(des_br_iface, cur_br_iface);
}
} else if let Interface::OvsBridge(br_iface) = &mut self.merged {
if let (
Interface::OvsBridge(des_br_iface),
Interface::OvsBridge(cur_br_iface),
) = (desired, current)
{
br_iface.special_merge(des_br_iface, cur_br_iface);
}
}
}
}
pub(crate) fn set_copy_from_mac(&mut self, mac: String) {
if let Some(apply_iface) =
self.for_apply.as_mut().map(|i| i.base_iface_mut())
{
apply_iface.copy_mac_from = None;
apply_iface.mac_address = Some(mac.to_string());
}
if let Some(verify_iface) =
self.for_verify.as_mut().map(|i| i.base_iface_mut())
{
verify_iface.copy_mac_from = None;
verify_iface.mac_address = Some(mac);
}
}
pub(crate) fn get_changed_ports(&self) -> Option<(Vec<&str>, Vec<&str>)> {
let desired_iface = self.desired.as_ref()?;
if desired_iface.is_absent() {
if let Some(ports) = self.current.as_ref().and_then(|c| c.ports()) {
return Some((Vec::new(), ports));
} else {
return None;
}
}
let desired_port_names = match desired_iface.ports() {
Some(p) => HashSet::from_iter(p.iter().cloned()),
None => {
if let Some(cur_iface) = self.current.as_ref() {
if cur_iface.is_ignore() {
match cur_iface.ports().map(|ports| {
HashSet::<&str>::from_iter(ports.iter().cloned())
}) {
Some(p) => p,
None => return None,
}
} else {
return None;
}
} else {
return None;
}
}
};
let current_port_names = self
.current
.as_ref()
.and_then(|cur_iface| {
if cur_iface.is_ignore() {
None
} else {
cur_iface.ports()
}
})
.map(|ports| HashSet::<&str>::from_iter(ports.iter().cloned()))
.unwrap_or_default();
let mut chg_attached_ports: Vec<&str> = desired_port_names
.difference(¤t_port_names)
.cloned()
.collect();
let chg_detached_ports: Vec<&str> = current_port_names
.difference(&desired_port_names)
.cloned()
.collect();
if let (
Interface::LinuxBridge(des_br_iface),
Some(Interface::LinuxBridge(cur_br_iface)),
) = (desired_iface, self.current.as_ref())
{
for port_name in des_br_iface.get_config_changed_ports(cur_br_iface)
{
if !chg_attached_ports.contains(&port_name) {
chg_attached_ports.push(port_name);
}
}
}
else if let (
Interface::Bond(des_bond_iface),
Some(Interface::Bond(cur_bond_iface)),
) = (desired_iface, self.current.as_ref())
{
for port_name in
des_bond_iface.get_config_changed_ports(cur_bond_iface)
{
if !chg_attached_ports.contains(&port_name) {
chg_attached_ports.push(port_name);
}
}
}
Some((chg_attached_ports, chg_detached_ports))
}
pub(crate) fn mark_as_changed(&mut self) {
if self.desired.is_none() {
if let Some(cur_iface) = self.current.as_ref() {
let iface = cur_iface.clone_name_type_only();
self.for_apply = Some(iface);
self.preserve_current_controller_info();
}
}
}
pub(crate) fn mark_as_absent(&mut self) {
self.mark_as_changed();
self.merged.base_iface_mut().state = InterfaceState::Absent;
if let Some(apply_iface) = self.for_apply.as_mut() {
apply_iface.base_iface_mut().state = InterfaceState::Absent;
}
}
pub(crate) fn apply_ctrller_change(
&mut self,
ctrl_name: String,
ctrl_type: Option<InterfaceType>,
ctrl_state: InterfaceState,
) -> Result<(), NmstateError> {
if self.merged.need_controller() && ctrl_name.is_empty() {
if let Some(org_ctrl) = self
.current
.as_ref()
.and_then(|c| c.base_iface().controller.as_ref())
{
if Some(true) == self.for_apply.as_ref().map(|i| i.is_up()) {
return Err(NmstateError::new(
ErrorKind::InvalidArgument,
format!(
"Interface {} cannot live without controller, \
but it is detached from original controller \
{org_ctrl}, cannot apply desired `state:up`",
self.merged.name()
),
));
}
}
}
if !self.is_desired() {
self.mark_as_changed();
if ctrl_state == InterfaceState::Up {
self.merged.base_iface_mut().state = InterfaceState::Up;
if let Some(apply_iface) = self.for_apply.as_mut() {
apply_iface.base_iface_mut().state = InterfaceState::Up;
}
}
log::info!(
"Include interface {} to edit as its controller required so",
self.merged.name()
);
}
let apply_iface = if let Some(i) = self.for_apply.as_mut() {
i
} else {
return Err(NmstateError::new(
ErrorKind::Bug,
format!(
"Reached unreachable code: apply_ctrller_change() \
self.for_apply still None: {self:?}"
),
));
};
if self.merged.need_controller() && ctrl_name.is_empty() {
if let Some(org_ctrl) = self
.current
.as_ref()
.and_then(|c| c.base_iface().controller.as_ref())
{
log::info!(
"Interface {} cannot live without controller, \
marking as absent as it has been detached from its \
original controller {org_ctrl}",
self.merged.name(),
);
}
self.merged.base_iface_mut().state = InterfaceState::Absent;
apply_iface.base_iface_mut().state = InterfaceState::Absent;
if let Some(verify_iface) = self.for_verify.as_mut() {
verify_iface.base_iface_mut().state = InterfaceState::Absent;
}
} else {
apply_iface.base_iface_mut().controller = Some(ctrl_name.clone());
apply_iface
.base_iface_mut()
.controller_type
.clone_from(&ctrl_type);
self.merged.base_iface_mut().controller = Some(ctrl_name);
self.merged.base_iface_mut().controller_type = ctrl_type;
if !self.merged.base_iface().can_have_ip() {
self.merged.base_iface_mut().ipv4 = None;
self.merged.base_iface_mut().ipv6 = None;
}
}
Ok(())
}
fn preserve_current_controller_info(&mut self) {
if let Some(apply_iface) = self.for_apply.as_mut() {
if apply_iface.base_iface().controller.is_none() {
if let Some(cur_iface) = self.current.as_ref() {
if cur_iface.base_iface().controller.as_ref().is_some() {
apply_iface
.base_iface_mut()
.controller
.clone_from(&cur_iface.base_iface().controller);
apply_iface
.base_iface_mut()
.controller_type
.clone_from(
&cur_iface.base_iface().controller_type,
);
}
}
}
}
}
}
fn merge_desire_with_current(
desired: &Interface,
current: &Interface,
) -> Result<Interface, NmstateError> {
let mut desired_value = serde_json::to_value(desired)?;
let current_value = serde_json::to_value(current)?;
merge_json_value(&mut desired_value, ¤t_value);
let iface: Interface = serde_json::from_value(desired_value)?;
Ok(iface)
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
Serialize,
Deserialize,
)]
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
#[non_exhaustive]
pub enum InterfaceIdentifier {
Name,
MacAddress,
}
impl Default for InterfaceIdentifier {
fn default() -> Self {
Self::Name
}
}
impl InterfaceIdentifier {
pub fn is_default(&self) -> bool {
self == &InterfaceIdentifier::default()
}
}