1use serde::{Deserialize, Serialize};
4
5use crate::{
6 BaseInterface, ErrorKind, Interface, InterfaceType, Interfaces,
7 MergedInterfaces, 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.gen_conf_mode
196 && !veth_peers.contains(ð_iface.base.name.as_str())
197 {
198 return Err(NmstateError::new(
199 ErrorKind::InvalidArgument,
200 format!(
201 "Ethernet interface {} does not exists",
202 eth_iface.base.name.as_str()
203 ),
204 ));
205 }
206 }
207 }
208
209 let mut pending_deletions: Vec<String> = Vec::new();
210
211 for iface in self.iter().filter(|i| {
212 i.merged.iface_type() == InterfaceType::Ethernet
213 && i.is_desired()
214 && i.merged.is_up()
215 && i.current.is_some()
216 }) {
217 if let (
218 Some(Interface::Ethernet(des_eth_iface)),
219 Some(Interface::Ethernet(cur_eth_iface)),
220 ) = (iface.desired.as_ref(), iface.current.as_ref())
221 {
222 if let (Some(veth_conf), Some(cur_veth_conf)) =
223 (des_eth_iface.veth.as_ref(), cur_eth_iface.veth.as_ref())
224 {
225 if veth_conf.peer != cur_veth_conf.peer {
226 pending_deletions.push(cur_veth_conf.peer.to_string());
227 }
228 }
229 }
230 }
231
232 for iface in self.iter().filter(|i| {
233 i.merged.iface_type() == InterfaceType::Ethernet
234 && i.is_desired()
235 && i.merged.is_absent()
236 && i.current.is_some()
237 }) {
238 if let Some(Interface::Ethernet(cur_eth_iface)) =
239 iface.current.as_ref()
240 {
241 if let Some(veth_conf) = cur_eth_iface.veth.as_ref() {
242 pending_deletions.push(veth_conf.peer.to_string());
243 }
244 }
245 }
246
247 for del_peer in pending_deletions {
248 if let Some(iface) = self.kernel_ifaces.get_mut(&del_peer) {
249 iface.mark_as_absent();
250 }
251 }
252 Ok(())
253 }
254}
255
256impl Interfaces {
257 pub(crate) fn validate_change_veth_ignored_peer(
260 &self,
261 current: &Self,
262 ignored_ifaces: &[(String, InterfaceType)],
263 ) -> Result<(), NmstateError> {
264 let ignored_veth_ifaces: Vec<&String> = ignored_ifaces
265 .iter()
266 .filter_map(|(n, t)| {
267 if t == &InterfaceType::Ethernet {
268 Some(n)
269 } else {
270 None
271 }
272 })
273 .collect();
274
275 for iface in self.kernel_ifaces.values().filter(|i| {
276 if let Interface::Ethernet(i) = i {
277 i.veth.is_some()
278 } else {
279 false
280 }
281 }) {
282 if let (
283 Interface::Ethernet(des_iface),
284 Some(Interface::Ethernet(cur_iface)),
285 ) = (iface, current.get_iface(iface.name(), InterfaceType::Veth))
286 {
287 if let (Some(des_peer), cur_peer) = (
288 des_iface.veth.as_ref().map(|v| v.peer.as_str()),
289 cur_iface.veth.as_ref().map(|v| v.peer.as_str()),
290 ) {
291 let cur_peer = if let Some(c) = cur_peer {
292 c
293 } else {
294 let e = NmstateError::new(
296 ErrorKind::InvalidArgument,
297 format!(
298 "Veth interface {} is currently holding peer \
299 assigned to other namespace Please remove \
300 this veth pair before changing veth peer to \
301 {des_peer}",
302 iface.name(),
303 ),
304 );
305 log::error!("{e}");
306 return Err(e);
307 };
308
309 if des_peer != cur_peer
310 && ignored_veth_ifaces.contains(&&cur_peer.to_string())
311 {
312 let e = NmstateError::new(
313 ErrorKind::InvalidArgument,
314 format!(
315 "Veth interface {} is currently holding peer \
316 {} which is marked as ignored. Hence not \
317 allowing changing its peer to {}. Please \
318 remove this veth pair before changing veth \
319 peer",
320 iface.name(),
321 cur_peer,
322 des_peer
323 ),
324 );
325 log::error!("{e}");
326 return Err(e);
327 }
328 }
329 }
330 }
331 Ok(())
332 }
333
334 pub(crate) fn validate_new_veth_without_peer(
335 &self,
336 current: &Self,
337 ) -> Result<(), NmstateError> {
338 for iface in self.kernel_ifaces.values().filter(|i| {
339 i.is_up()
340 && i.iface_type() == InterfaceType::Veth
341 && !current.kernel_ifaces.contains_key(i.name())
342 }) {
343 if let Interface::Ethernet(eth_iface) = iface {
344 if eth_iface.veth.is_none() {
345 return Err(NmstateError::new(
346 ErrorKind::InvalidArgument,
347 format!(
348 "Veth interface {} does not exist, peer name is \
349 required for creating it",
350 iface.name()
351 ),
352 ));
353 }
354 }
355 }
356 Ok(())
357 }
358}