use log::{error, warn};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{
state::get_json_value_difference, BaseInterface, BondInterface,
DummyInterface, ErrorKind, EthernetInterface, InfiniBandInterface,
LinuxBridgeInterface, MacVlanInterface, MacVtapInterface, NmstateError,
OvsBridgeInterface, OvsInterface, VlanInterface, VrfInterface,
VxlanInterface,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum InterfaceType {
Bond,
LinuxBridge,
Dummy,
Ethernet,
Loopback,
MacVlan,
MacVtap,
OvsBridge,
OvsInterface,
Veth,
Vlan,
Vrf,
Vxlan,
InfiniBand,
Unknown,
Other(String),
}
impl Default for InterfaceType {
fn default() -> Self {
Self::Unknown
}
}
impl From<&str> for InterfaceType {
fn from(s: &str) -> Self {
match s {
"bond" => InterfaceType::Bond,
"linux-bridge" => InterfaceType::LinuxBridge,
"dummy" => InterfaceType::Dummy,
"ethernet" => InterfaceType::Ethernet,
"loopback" => InterfaceType::Loopback,
"mac-vlan" => InterfaceType::MacVlan,
"mac-vtap" => InterfaceType::MacVtap,
"ovs-bridge" => InterfaceType::OvsBridge,
"ovs-interface" => InterfaceType::OvsInterface,
"veth" => InterfaceType::Veth,
"vlan" => InterfaceType::Vlan,
"vrf" => InterfaceType::Vrf,
"vxlan" => InterfaceType::Vxlan,
"infiniband" => InterfaceType::InfiniBand,
"unknown" => InterfaceType::Unknown,
_ => InterfaceType::Other(s.to_string()),
}
}
}
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::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::Other(ref s) => s,
}
)
}
}
impl Serialize for InterfaceType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(format!("{}", self).as_str())
}
}
impl<'de> Deserialize<'de> for InterfaceType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let v = serde_json::Value::deserialize(deserializer)?;
match v.as_str() {
Some(s) => Ok(InterfaceType::from(s)),
None => Ok(InterfaceType::Unknown),
}
}
}
impl InterfaceType {
const USERSPACE_IFACE_TYPES: [Self; 1] = [Self::OvsBridge];
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, 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::Unknown
}
}
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(skip_deserializing, flatten)]
pub base: BaseInterface,
#[serde(flatten)]
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 v = serde_json::Value::deserialize(deserializer)?;
let mut base_value = serde_json::map::Map::new();
if let Some(n) = v.get("name") {
base_value.insert("name".to_string(), n.clone());
}
if let Some(s) = v.get("state") {
base_value.insert("state".to_string(), s.clone());
}
ret.base = BaseInterface::deserialize(
serde_json::value::Value::Object(base_value),
)
.map_err(serde::de::Error::custom)?;
ret.other = 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),
LinuxBridge(LinuxBridgeInterface),
OvsBridge(OvsBridgeInterface),
OvsInterface(OvsInterface),
Unknown(UnknownInterface),
Vlan(VlanInterface),
Vxlan(VxlanInterface),
MacVlan(MacVlanInterface),
MacVtap(MacVtapInterface),
Vrf(VrfInterface),
InfiniBand(InfiniBandInterface),
}
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::InfiniBand) => {
let inner = InfiniBandInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::InfiniBand(inner))
}
Some(iface_type) => {
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(crate) fn set_iface_type(&mut self, iface_type: InterfaceType) {
self.base_iface_mut().iface_type = iface_type;
}
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();
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::InfiniBand(iface) => {
let new_iface = InfiniBandInterface {
base: iface.base.clone_name_type_only(),
..Default::default()
};
Self::InfiniBand(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(_)
)
}
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::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::Unknown(iface) => &iface.base,
}
}
pub(crate) 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::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::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 fn update(&mut self, other: &Interface) {
self.base_iface_mut().update(other.base_iface());
if let Self::Unknown(_) = other {
return;
}
match self {
Self::LinuxBridge(iface) => {
if let Self::LinuxBridge(other_iface) = other {
iface.update_bridge(other_iface);
} else {
warn!(
"Don't know how to update iface {:?} with {:?}",
iface, other
);
}
}
Self::Bond(iface) => {
if let Self::Bond(other_iface) = other {
iface.update_bond(other_iface);
} else {
warn!(
"Don't know how to update iface {:?} with {:?}",
iface, other
);
}
}
Self::Ethernet(iface) => {
if let Self::Ethernet(other_iface) = other {
iface.update_ethernet(other_iface);
iface.update_veth(other_iface);
} else {
warn!(
"Don't know how to update iface {:?} with {:?}",
iface, other
);
}
}
Self::Vlan(iface) => {
if let Self::Vlan(other_iface) = other {
iface.update_vlan(other_iface);
} else {
warn!(
"Don't know how to update iface {:?} with {:?}",
iface, other
);
}
}
Self::Vxlan(iface) => {
if let Self::Vxlan(other_iface) = other {
iface.update_vxlan(other_iface);
} else {
warn!(
"Don't know how to update iface {:?} with {:?}",
iface, other
);
}
}
Self::OvsBridge(iface) => {
if let Self::OvsBridge(other_iface) = other {
iface.update_ovs_bridge(other_iface);
} else {
warn!(
"Don't know how to update iface {:?} with {:?}",
iface, other
);
}
}
Self::MacVlan(iface) => {
if let Self::MacVlan(other_iface) = other {
iface.update_mac_vlan(other_iface);
} else {
warn!(
"Don't know how to update iface {:?} with {:?}",
iface, other
);
}
}
Self::MacVtap(iface) => {
if let Self::MacVtap(other_iface) = other {
iface.update_mac_vtap(other_iface);
} else {
warn!(
"Don't know how to update iface {:?} with {:?}",
iface, other
);
}
}
Self::Vrf(iface) => {
if let Self::Vrf(other_iface) = other {
iface.update_vrf(other_iface);
} else {
warn!(
"Don't know how to update iface {:?} with {:?}",
iface, other
);
}
}
Self::InfiniBand(iface) => {
if let Self::InfiniBand(other_iface) = other {
iface.update_ib(other_iface);
} else {
warn!(
"Don't know how to update iface {:?} with {:?}",
iface, other
);
}
}
Self::Unknown(_) | Self::Dummy(_) | Self::OvsInterface(_) => (),
}
}
pub(crate) fn pre_verify_cleanup(&mut self) {
self.base_iface_mut().pre_verify_cleanup();
match self {
Self::LinuxBridge(ref mut iface) => {
iface.pre_verify_cleanup();
}
Self::Bond(ref mut iface) => {
iface.pre_verify_cleanup();
}
Self::Ethernet(ref mut iface) => {
iface.pre_verify_cleanup();
}
Self::OvsBridge(ref mut iface) => {
iface.pre_verify_cleanup();
}
Self::Vrf(ref mut iface) => {
iface.pre_verify_cleanup();
}
_ => (),
}
}
pub(crate) fn pre_edit_cleanup(&mut self) -> Result<(), NmstateError> {
self.base_iface_mut().pre_edit_cleanup()?;
if let Interface::Ethernet(iface) = self {
if iface.veth.is_some() {
iface.base.iface_type = InterfaceType::Veth;
}
}
if let Interface::OvsInterface(iface) = self {
iface.pre_edit_cleanup()?;
}
Ok(())
}
pub(crate) fn verify(&self, current: &Self) -> Result<(), NmstateError> {
let mut self_clone = self.clone();
let mut current_clone = current.clone();
if current_clone.base_iface().controller.is_some()
&& self_clone.base_iface().controller.is_none()
{
self_clone.base_iface_mut().controller =
current_clone.base_iface().controller.clone();
self_clone.base_iface_mut().controller_type =
current_clone.base_iface().controller_type.clone();
}
self_clone.pre_verify_cleanup();
current_clone.pre_verify_cleanup();
if self_clone.iface_type() == InterfaceType::Unknown {
current_clone.base_iface_mut().iface_type = InterfaceType::Unknown;
}
let self_value = serde_json::to_value(&self_clone)?;
let current_value = serde_json::to_value(¤t_clone)?;
if let Some((reference, desire, current)) = get_json_value_difference(
format!("{}.interface", self.name()),
&self_value,
¤t_value,
) {
if let (
serde_json::Value::Number(des),
serde_json::Value::Number(cur),
) = (desire, current)
{
if desire.as_u64().unwrap_or(0) as i128
- cur.as_u64().unwrap_or(0) as i128
== 1
&& LinuxBridgeInterface::is_interger_rounded_up(&reference)
{
let e = NmstateError::new(
ErrorKind::KernelIntegerRoundedError,
format!(
"Linux kernel configured with 250 HZ \
will round up/down the integer in linux \
bridge {} option '{}' from {:?} to {:?}.",
self.name(),
reference,
des,
cur
),
);
error!("{}", e);
return Err(e);
}
}
Err(NmstateError::new(
ErrorKind::VerificationError,
format!(
"Verification failure: {} desire '{}', current '{}'",
reference, desire, current
),
))
} else {
Ok(())
}
}
pub(crate) fn validate(
&self,
current: Option<&Self>,
) -> Result<(), NmstateError> {
match self {
Interface::LinuxBridge(iface) => iface.validate(),
Interface::Bond(iface) => iface.validate(current),
Interface::MacVlan(iface) => iface.validate(),
Interface::MacVtap(iface) => iface.validate(),
_ => Ok(()),
}
}
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 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(),
_ => None,
}
}
}
#[allow(clippy::derivable_impls)]
impl Default for Interface {
fn default() -> Self {
Interface::Unknown(UnknownInterface::default())
}
}