nmstate/query_apply/
sriov.rs1use std::collections::hash_map::Entry;
4
5use crate::{
6 BaseInterface, ErrorKind, EthernetConfig, EthernetInterface, Interface,
7 InterfaceType, Interfaces, NmstateError, SrIovConfig, SrIovVfConfig,
8};
9
10impl SrIovConfig {
11 pub(crate) fn sanitize_desired_for_verify(&mut self) {
14 if let Some(vfs) = self.vfs.as_mut() {
15 for vf in vfs.iter_mut() {
16 vf.iface_name = String::new();
17 }
18 if vfs.is_empty() {
19 self.vfs = None;
20 }
21 }
22 }
23
24 pub(crate) fn update(&mut self, other: Option<&SrIovConfig>) {
25 if let Some(other) = other {
26 if let Some(autoprobe) = other.drivers_autoprobe {
27 self.drivers_autoprobe = Some(autoprobe);
28 }
29 if let Some(total_vfs) = other.total_vfs {
30 self.total_vfs = Some(total_vfs);
31 }
32 if let Some(vfs) = other.vfs.as_ref() {
33 self.vfs = Some(vfs.clone());
34 }
35 }
36 }
37
38 pub(crate) fn verify_sriov(
45 &self,
46 pf_name: &str,
47 cur_ifaces: &Interfaces,
48 ) -> Result<(), NmstateError> {
49 let cur_pf_iface =
50 match cur_ifaces.get_iface(pf_name, InterfaceType::Ethernet) {
51 Some(Interface::Ethernet(i)) => i,
52 _ => {
53 return Err(NmstateError::new(
54 ErrorKind::SrIovVfNotFound,
55 format!("Failed to find PF interface {pf_name}"),
56 ));
57 }
58 };
59
60 if let Some(desired_autoprobe) = self.drivers_autoprobe {
61 if !desired_autoprobe {
62 return Ok(());
63 }
64 }
65
66 if let Some(cur_autoprobe) = cur_pf_iface
67 .ethernet
68 .as_ref()
69 .and_then(|eth_conf| eth_conf.sr_iov.as_ref())
70 .and_then(|sriov_conf| sriov_conf.drivers_autoprobe.as_ref())
71 {
72 if !cur_autoprobe {
73 return Ok(());
74 }
75 }
76
77 let vfs = if let Some(vfs) = cur_pf_iface
78 .ethernet
79 .as_ref()
80 .and_then(|eth_conf| eth_conf.sr_iov.as_ref())
81 .and_then(|sriov_conf| sriov_conf.vfs.as_ref())
82 {
83 vfs
84 } else {
85 return Ok(());
86 };
87 for vf in vfs {
88 if vf.iface_name.is_empty() {
89 return Err(NmstateError::new(
90 ErrorKind::SrIovVfNotFound,
91 format!(
92 "Failed to find VF {} interface name of PF {pf_name}",
93 vf.id
94 ),
95 ));
96 } else if cur_ifaces
97 .get_iface(vf.iface_name.as_str(), InterfaceType::Ethernet)
98 .is_none()
99 {
100 return Err(NmstateError::new(
101 ErrorKind::SrIovVfNotFound,
102 format!(
103 "Find VF {} interface name {} of PF {pf_name} is not \
104 exist yet",
105 vf.id, &vf.iface_name
106 ),
107 ));
108 }
109 }
110 Ok(())
111 }
112}
113
114impl Interfaces {
115 pub(crate) fn has_sriov_naming(&self) -> bool {
116 self.kernel_ifaces
117 .values()
118 .any(|i| i.name().starts_with(SrIovConfig::VF_NAMING_PREFIX))
119 }
120
121 pub(crate) fn use_pseudo_sriov_vf_name(&self, current: &mut Self) {
122 let mut new_vf_names: Vec<String> = Vec::new();
123
124 for (des_iface, des_sriov_count) in
125 self.kernel_ifaces.values().filter_map(|i| {
126 if let Interface::Ethernet(eth_iface) = i {
127 let sriov_count = eth_iface
128 .ethernet
129 .as_ref()
130 .and_then(|e| e.sr_iov.as_ref())
131 .and_then(|s| s.total_vfs)
132 .unwrap_or_default();
133 if sriov_count > 0 {
134 Some((eth_iface, sriov_count))
135 } else {
136 None
137 }
138 } else {
139 None
140 }
141 })
142 {
143 let cur_iface: &mut Interface = match current
144 .kernel_ifaces
145 .entry(des_iface.base.name.clone())
146 {
147 Entry::Occupied(o) => o.into_mut(),
148 Entry::Vacant(v) => {
149 v.insert(Interface::Ethernet(des_iface.clone()))
150 }
151 };
152
153 let des_sriov_conf = if let Some(c) =
154 des_iface.ethernet.as_ref().and_then(|e| e.sr_iov.as_ref())
155 {
156 c
157 } else {
158 continue;
159 };
160
161 let cur_iface = if let Interface::Ethernet(i) = cur_iface {
162 i
163 } else {
164 continue;
165 };
166
167 let cur_sriov_count = cur_iface
169 .ethernet
170 .as_ref()
171 .and_then(|e| e.sr_iov.as_ref())
172 .and_then(|s| s.total_vfs)
173 .unwrap_or_default();
174 if cur_sriov_count < des_sriov_count {
175 let cur_vfs = cur_iface
176 .ethernet
177 .get_or_insert(EthernetConfig {
178 sr_iov: Some(des_sriov_conf.clone()),
179 ..Default::default()
180 })
181 .sr_iov
182 .get_or_insert(SrIovConfig::default())
183 .vfs
184 .get_or_insert(Vec::new());
185 for vfid in cur_sriov_count..des_sriov_count {
186 let psudo_vf_name =
187 format!("{}v{vfid}", des_iface.base.name);
188 new_vf_names.push(psudo_vf_name.clone());
189 match cur_vfs.get_mut(vfid as usize) {
190 Some(vf) => {
191 vf.id = vfid;
192 if vf.iface_name.is_empty() {
193 vf.iface_name = psudo_vf_name;
194 }
195 }
196 None => {
197 cur_vfs.push(SrIovVfConfig {
198 id: vfid,
199 iface_name: psudo_vf_name,
200 ..Default::default()
201 });
202 }
203 }
204 }
205 }
206 }
207 for psudo_vf_name in new_vf_names {
208 current.push(Interface::Ethernet(Box::new(EthernetInterface {
209 base: BaseInterface {
210 name: psudo_vf_name,
211 iface_type: InterfaceType::Ethernet,
212 ..Default::default()
213 },
214 ..Default::default()
215 })));
216 }
217 }
218}