1use serde::{Deserialize, Serialize};
4
5use crate::{
6 BaseInterface, ErrorKind, Interface, InterfaceType, Interfaces,
7 MergedInterfaces, NetworkStateMode, NmstateError, SrIovConfig,
8};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
11#[non_exhaustive]
12pub struct EthernetInterface {
65 #[serde(flatten)]
66 pub base: BaseInterface,
67 #[serde(skip_serializing_if = "Option::is_none")]
68 pub ethernet: Option<EthernetConfig>,
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub veth: Option<VethConfig>,
73}
74
75impl Default for EthernetInterface {
76 fn default() -> Self {
77 let mut base = BaseInterface::new();
78 base.iface_type = InterfaceType::Ethernet;
79 Self {
80 base,
81 ethernet: None,
82 veth: None,
83 }
84 }
85}
86
87impl EthernetInterface {
88 pub(crate) fn sanitize(&mut self) -> Result<(), NmstateError> {
89 self.base.iface_type = InterfaceType::Ethernet;
91
92 if let Some(sriov_conf) =
93 self.ethernet.as_mut().and_then(|e| e.sr_iov.as_mut())
94 {
95 sriov_conf.sanitize()?
96 }
97
98 Ok(())
99 }
100
101 pub fn new() -> Self {
102 Self::default()
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
107#[serde(rename_all = "kebab-case")]
108#[non_exhaustive]
109pub enum EthernetDuplex {
110 Full,
112 Half,
114}
115
116impl std::fmt::Display for EthernetDuplex {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 write!(
119 f,
120 "{}",
121 match self {
122 Self::Full => "full",
123 Self::Half => "half",
124 }
125 )
126 }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
130#[serde(rename_all = "kebab-case", deny_unknown_fields)]
131#[non_exhaustive]
132pub struct EthernetConfig {
133 #[serde(skip_serializing_if = "Option::is_none")]
134 pub sr_iov: Option<SrIovConfig>,
137 #[serde(
138 skip_serializing_if = "Option::is_none",
139 rename = "auto-negotiation",
140 default,
141 deserialize_with = "crate::deserializer::option_bool_or_string"
142 )]
143 pub auto_neg: Option<bool>,
145 #[serde(
146 skip_serializing_if = "Option::is_none",
147 default,
148 deserialize_with = "crate::deserializer::option_u32_or_string"
149 )]
150 pub speed: Option<u32>,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub duplex: Option<EthernetDuplex>,
153}
154
155impl EthernetConfig {
156 pub fn new() -> Self {
157 Self::default()
158 }
159}
160
161#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
162#[non_exhaustive]
163pub struct VethConfig {
164 pub peer: String,
166}
167
168impl MergedInterfaces {
169 pub(crate) fn process_veth_peer_changes(
173 &mut self,
174 ) -> Result<(), NmstateError> {
175 let mut veth_peers: Vec<&str> = Vec::new();
176 for iface in self.iter().filter(|i| {
177 i.merged.iface_type() == InterfaceType::Ethernet && i.merged.is_up()
178 }) {
179 if let Interface::Ethernet(eth_iface) = &iface.merged {
180 if let Some(v) =
181 eth_iface.veth.as_ref().map(|v| v.peer.as_str())
182 {
183 veth_peers.push(v);
184 }
185 }
186 }
187 for iface in self.iter().filter(|i| {
188 i.merged.iface_type() == InterfaceType::Ethernet
189 && i.is_desired()
190 && i.current.is_none()
191 && i.merged.is_up()
192 }) {
193 if let Some(Interface::Ethernet(eth_iface)) = &iface.desired {
194 if eth_iface.veth.is_none()
195 && self.mode != NetworkStateMode::GenerateConfig
196 && !veth_peers.contains(ð_iface.base.name.as_str())
197 && !eth_iface.base.name.starts_with("sriov:")
200 {
201 return Err(NmstateError::new(
202 ErrorKind::InvalidArgument,
203 format!(
204 "Ethernet interface {} does not exists",
205 eth_iface.base.name.as_str()
206 ),
207 ));
208 }
209 }
210 }
211
212 let mut pending_deletions: Vec<String> = Vec::new();
213
214 for iface in self.iter().filter(|i| {
215 i.merged.iface_type() == InterfaceType::Ethernet
216 && i.is_desired()
217 && i.merged.is_up()
218 && i.current.is_some()
219 }) {
220 if let (
221 Some(Interface::Ethernet(des_eth_iface)),
222 Some(Interface::Ethernet(cur_eth_iface)),
223 ) = (iface.desired.as_ref(), iface.current.as_ref())
224 {
225 if let (Some(veth_conf), Some(cur_veth_conf)) =
226 (des_eth_iface.veth.as_ref(), cur_eth_iface.veth.as_ref())
227 {
228 if veth_conf.peer != cur_veth_conf.peer {
229 pending_deletions.push(cur_veth_conf.peer.to_string());
230 }
231 }
232 }
233 }
234
235 for iface in self.iter().filter(|i| {
236 i.merged.iface_type() == InterfaceType::Ethernet
237 && i.is_desired()
238 && i.merged.is_absent()
239 && i.current.is_some()
240 }) {
241 if let Some(Interface::Ethernet(cur_eth_iface)) =
242 iface.current.as_ref()
243 {
244 if let Some(veth_conf) = cur_eth_iface.veth.as_ref() {
245 pending_deletions.push(veth_conf.peer.to_string());
246 }
247 }
248 }
249
250 for del_peer in pending_deletions {
251 if let Some(iface) = self.kernel_ifaces.get_mut(&del_peer) {
252 iface.mark_as_absent();
253 }
254 }
255 Ok(())
256 }
257}
258
259impl Interfaces {
260 pub(crate) fn validate_change_veth_ignored_peer(
263 &self,
264 current: &Self,
265 ignored_ifaces: &[(String, InterfaceType)],
266 ) -> Result<(), NmstateError> {
267 let ignored_veth_ifaces: Vec<&String> = ignored_ifaces
268 .iter()
269 .filter_map(|(n, t)| {
270 if t == &InterfaceType::Ethernet {
271 Some(n)
272 } else {
273 None
274 }
275 })
276 .collect();
277
278 for iface in self.kernel_ifaces.values().filter(|i| {
279 if let Interface::Ethernet(i) = i {
280 i.veth.is_some()
281 } else {
282 false
283 }
284 }) {
285 if let (
286 Interface::Ethernet(des_iface),
287 Some(Interface::Ethernet(cur_iface)),
288 ) = (iface, current.get_iface(iface.name(), InterfaceType::Veth))
289 {
290 if let (Some(des_peer), cur_peer) = (
291 des_iface.veth.as_ref().map(|v| v.peer.as_str()),
292 cur_iface.veth.as_ref().map(|v| v.peer.as_str()),
293 ) {
294 let cur_peer = if let Some(c) = cur_peer {
295 c
296 } else {
297 let e = NmstateError::new(
299 ErrorKind::InvalidArgument,
300 format!(
301 "Veth interface {} is currently holding peer \
302 assigned to other namespace Please remove \
303 this veth pair before changing veth peer to \
304 {des_peer}",
305 iface.name(),
306 ),
307 );
308 log::error!("{e}");
309 return Err(e);
310 };
311
312 if des_peer != cur_peer
313 && ignored_veth_ifaces.contains(&&cur_peer.to_string())
314 {
315 let e = NmstateError::new(
316 ErrorKind::InvalidArgument,
317 format!(
318 "Veth interface {} is currently holding peer \
319 {} which is marked as ignored. Hence not \
320 allowing changing its peer to {}. Please \
321 remove this veth pair before changing veth \
322 peer",
323 iface.name(),
324 cur_peer,
325 des_peer
326 ),
327 );
328 log::error!("{e}");
329 return Err(e);
330 }
331 }
332 }
333 }
334 Ok(())
335 }
336
337 pub(crate) fn validate_new_veth_without_peer(
338 &self,
339 current: &Self,
340 ) -> Result<(), NmstateError> {
341 for iface in self.kernel_ifaces.values().filter(|i| {
342 i.is_up()
343 && i.iface_type() == InterfaceType::Veth
344 && !current.kernel_ifaces.contains_key(i.name())
345 }) {
346 if let Interface::Ethernet(eth_iface) = iface {
347 if eth_iface.veth.is_none() {
348 return Err(NmstateError::new(
349 ErrorKind::InvalidArgument,
350 format!(
351 "Veth interface {} does not exist, peer name is \
352 required for creating it",
353 iface.name()
354 ),
355 ));
356 }
357 }
358 }
359 Ok(())
360 }
361}