nmstate/ifaces/
mac_vtap.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use serde::{Deserialize, Serialize};
4
5use crate::{BaseInterface, ErrorKind, InterfaceType, NmstateError};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[non_exhaustive]
9/// Linux kernel MAC VTAP interface. The example output of [crate::NetworkState]
10/// with a mac vtap interface would be:
11/// ```yml
12/// ---
13/// interfaces:
14///   - name: mac0
15///     type: mac-vtap
16///     state: up
17///     mac-vtap:
18///       base-iface: eth1
19///       mode: passthru
20///       promiscuous: true
21/// ```
22pub struct MacVtapInterface {
23    #[serde(flatten)]
24    pub base: BaseInterface,
25    #[serde(skip_serializing_if = "Option::is_none", rename = "mac-vtap")]
26    /// Deserialize and serialize from/to `mac-vtap`.
27    pub mac_vtap: Option<MacVtapConfig>,
28}
29
30impl Default for MacVtapInterface {
31    fn default() -> Self {
32        Self {
33            base: BaseInterface {
34                iface_type: InterfaceType::MacVtap,
35                ..Default::default()
36            },
37            mac_vtap: None,
38        }
39    }
40}
41
42impl MacVtapInterface {
43    pub fn new() -> Self {
44        Self::default()
45    }
46
47    pub(crate) fn sanitize(
48        &self,
49        is_desired: bool,
50    ) -> Result<(), NmstateError> {
51        if is_desired {
52            if let Some(conf) = &self.mac_vtap {
53                if conf.accept_all_mac == Some(false)
54                    && conf.mode != MacVtapMode::Passthru
55                {
56                    let e = NmstateError::new(
57                        ErrorKind::InvalidArgument,
58                        "Disable accept-all-mac-addresses(promiscuous) is \
59                         only allowed on passthru mode"
60                            .to_string(),
61                    );
62                    log::error!("{e}");
63                    return Err(e);
64                }
65            }
66        }
67        Ok(())
68    }
69
70    pub(crate) fn parent(&self) -> Option<&str> {
71        self.mac_vtap.as_ref().map(|cfg| cfg.base_iface.as_str())
72    }
73
74    pub(crate) fn change_parent_name(&mut self, name: &str) {
75        if let Some(mac_vtap_conf) = self.mac_vtap.as_mut() {
76            mac_vtap_conf.base_iface = name.to_string();
77        }
78    }
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
82#[serde(rename_all = "kebab-case", deny_unknown_fields)]
83#[non_exhaustive]
84pub struct MacVtapConfig {
85    pub base_iface: String,
86    pub mode: MacVtapMode,
87    #[serde(
88        skip_serializing_if = "Option::is_none",
89        rename = "promiscuous",
90        alias = "accept-all-mac",
91        default,
92        deserialize_with = "crate::deserializer::option_bool_or_string"
93    )]
94    /// Serialize to `promiscuous`.
95    /// Deserialize from `promiscuous` or `accept-all-mac`.
96    pub accept_all_mac: Option<bool>,
97}
98
99#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
100#[serde(rename_all = "kebab-case")]
101#[non_exhaustive]
102#[derive(Default)]
103pub enum MacVtapMode {
104    /// Deserialize and serialize from/to `vepa`.
105    Vepa,
106    /// Deserialize and serialize from/to `bridge`.
107    Bridge,
108    /// Deserialize and serialize from/to `private`.
109    Private,
110    /// Deserialize and serialize from/to `passthru`.
111    Passthru,
112    /// Deserialize and serialize from/to `source`.
113    Source,
114    #[default]
115    Unknown,
116}
117
118impl From<MacVtapMode> for u32 {
119    fn from(v: MacVtapMode) -> u32 {
120        match v {
121            MacVtapMode::Unknown => 0,
122            MacVtapMode::Vepa => 1,
123            MacVtapMode::Bridge => 2,
124            MacVtapMode::Private => 3,
125            MacVtapMode::Passthru => 4,
126            MacVtapMode::Source => 5,
127        }
128    }
129}