Skip to content

Commit a962e9d

Browse files
authored
Merge branch 'master' into feat/ucode
2 parents e806b8d + 02bab4f commit a962e9d

File tree

3 files changed

+120
-84
lines changed

3 files changed

+120
-84
lines changed

src/main.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ async fn main() -> Result<(), String> {
5555
.expect("could not configure network devices");
5656

5757
info!("Configuring sriov...");
58-
let num_of_vfs: u32 = 6;
59-
configure_sriov(num_of_vfs)
60-
.await
61-
.expect("could not configure sriov");
58+
const VFS_NUM: u32 = 6;
59+
if let Err(e) = configure_sriov(VFS_NUM).await {
60+
warn!("failed to configure sriov: {}", e.to_string())
61+
}
6262

6363
let vmm = vm::Manager::new(String::from("cloud-hypervisor"));
6464

src/network.rs

Lines changed: 115 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
use std::io;
2+
13
use crate::dhcpv6::*;
24
use futures::stream::TryStreamExt;
35
use log::{info, warn};
46
use rtnetlink::new_connection;
5-
use tokio::fs::OpenOptions;
6-
use tokio::io::AsyncWriteExt;
7-
use tokio::time::{self, Duration};
7+
use tokio::fs::{read_link, OpenOptions};
8+
use tokio::io::{AsyncReadExt, AsyncWriteExt};
9+
use tokio::time::{self, sleep, Duration};
810

911
use pnet::datalink::{self, Channel::Ethernet, Config};
1012
use pnet::packet::ethernet::EthernetPacket;
@@ -140,24 +142,126 @@ fn format_mac(bytes: Vec<u8>) -> String {
140142
}
141143

142144
pub async fn configure_sriov(num_vfs: u32) -> Result<(), String> {
143-
let file_path = format!("/sys/class/net/{}/device/sriov_numvfs", INTERFACE_NAME);
144-
145-
let result = OpenOptions::new().write(true).open(&file_path).await;
145+
let base_path = format!("/sys/class/net/{}/device", INTERFACE_NAME);
146146

147-
let mut file = match result {
148-
Ok(file) => file,
149-
Err(e) => return Err(format!("Failed to open the file: {}", e)),
150-
};
147+
let file_path = format!("{}/sriov_numvfs", base_path);
148+
let mut file = OpenOptions::new()
149+
.write(true)
150+
.open(&file_path)
151+
.await
152+
.map_err(|e| e.to_string())?;
151153

152154
let value = format!("{}\n", num_vfs);
153155
if let Err(e) = file.write_all(value.as_bytes()).await {
154156
return Err(format!("Failed to write to the file: {}", e));
155157
}
158+
info!("Created {} sriov virtual functions", num_vfs);
159+
160+
let device_path = read_link(base_path).await.map_err(|e| e.to_string())?;
161+
let pci_address = device_path
162+
.file_name()
163+
.ok_or("No PCI address found".to_string())?;
164+
let pci_address = pci_address.to_str().ok_or("No PCI address found")?;
165+
166+
info!("Found PCI address of {}: {}", INTERFACE_NAME, pci_address);
167+
168+
let sriov_offset = get_device_information(pci_address, "sriov_offset")
169+
.await
170+
.map_err(|e| e.to_string())?;
171+
172+
let sriov_offset = match sriov_offset.parse::<u32>() {
173+
Ok(n) => n,
174+
Err(e) => return Err(e.to_string()),
175+
};
176+
177+
let pci_address_parts: Vec<&str> = pci_address.split(&[':', '.'][..]).collect();
178+
if pci_address_parts.len() != 4 {
179+
return Err(format!("invalid pci address format: {}", pci_address));
180+
}
181+
182+
let virtual_funcs: Vec<String> = (0..num_vfs)
183+
.map(|x| x + sriov_offset)
184+
.map(|x| format!("{}.{}", pci_address_parts[0..3].join(":"), x))
185+
.collect();
186+
187+
const RETRIES: i32 = 3;
188+
for (index, vf) in virtual_funcs.iter().enumerate() {
189+
for i in 1..RETRIES {
190+
info!("try to unbind device {}: {:?}/{}", vf, i, RETRIES);
191+
if let Err(e) = unbind_device(vf).await {
192+
warn!("failed to unbind device {}: {}", vf, e.to_string());
193+
sleep(Duration::from_secs(2)).await;
194+
} else {
195+
info!("successfull unbound device {}", vf);
196+
197+
if let Err(e) = bind_device(index, vf).await {
198+
warn!("failed to bind devices: {}", e.to_string())
199+
}
200+
break;
201+
}
202+
}
203+
}
156204

157-
info!("Successfully wrote to the file.");
158205
Ok(())
159206
}
160207

208+
async fn unbind_device(pci: &str) -> Result<(), io::Error> {
209+
let unbind_path = format!("/sys/bus/pci/devices/{}/driver/unbind", pci);
210+
let mut file = OpenOptions::new().write(true).open(&unbind_path).await?;
211+
212+
file.write_all(pci.as_bytes()).await?;
213+
info!("unbound device: {}", pci);
214+
Ok(())
215+
}
216+
217+
async fn bind_device(index: usize, pci_address: &str) -> Result<(), io::Error> {
218+
info!("try to bind device to vfio: {}", pci_address);
219+
if index == 0 {
220+
vfio_new_id(pci_address).await
221+
} else {
222+
vfio_bind(pci_address).await
223+
}
224+
}
225+
226+
async fn vfio_new_id(pci_address: &str) -> Result<(), io::Error> {
227+
let vendor = get_device_information(pci_address, "vendor").await?;
228+
let vendor = vendor[2..].to_string();
229+
230+
let device = get_device_information(pci_address, "device").await?;
231+
let device = device[2..].to_string();
232+
233+
let mut file = OpenOptions::new()
234+
.write(true)
235+
.open("/sys/bus/pci/drivers/vfio-pci/new_id")
236+
.await?;
237+
238+
let content = format!("{} {}", vendor, device);
239+
file.write_all(content.as_bytes()).await?;
240+
info!("bound devices ({}) to vfio-pci", pci_address);
241+
Ok(())
242+
}
243+
244+
async fn vfio_bind(pci_address: &str) -> Result<(), io::Error> {
245+
let mut file = OpenOptions::new()
246+
.write(true)
247+
.open("/sys/bus/pci/drivers/vfio-pci/bind")
248+
.await?;
249+
250+
file.write_all(pci_address.as_bytes()).await?;
251+
info!("bound devices ({}) to vfio-pci", pci_address);
252+
Ok(())
253+
}
254+
255+
async fn get_device_information(pci: &str, field: &str) -> Result<String, io::Error> {
256+
let path = format!("/sys/bus/pci/devices/{}/{}", pci, field);
257+
let mut file = OpenOptions::new().read(true).open(&path).await?;
258+
259+
let mut dst = String::new();
260+
file.read_to_string(&mut dst).await?;
261+
262+
Ok(dst.trim().to_string())
263+
}
264+
161265
// Print all packets to the console for debugging purposes
162266
async fn _capture_packets(interface_name: String) {
163267
let interfaces = datalink::interfaces();

src/vm/mod.rs

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use log::info;
22
use serde_json::json;
3-
use std::io::{BufRead, BufReader, Write};
4-
use std::time::Duration;
3+
use std::io::{BufRead, BufReader};
54
use std::{
65
collections::HashMap,
76
num::TryFromIntError,
@@ -12,7 +11,6 @@ use std::{
1211
thread::sleep,
1312
time,
1413
};
15-
use std::{fs, io};
1614
use uuid::Uuid;
1715
use vmm::vm_config;
1816

@@ -246,8 +244,6 @@ impl Manager {
246244
let mut socket = UnixStream::connect(id.to_string()).map_err(Error::SocketFailure)?;
247245

248246
if let Some(pci) = pci {
249-
self.prepare_device(&pci).map_err(Error::SocketFailure)?;
250-
251247
// Check if the path exists
252248
let path = PathBuf::from(format!("/sys/bus/pci/devices/{}/", pci));
253249
info!("check if path exists {}", path.display());
@@ -256,9 +252,6 @@ impl Manager {
256252
return Err(Error::NotFound);
257253
}
258254

259-
info!("wait");
260-
sleep(Duration::from_secs(2));
261-
262255
info!("add device");
263256
let device_config = json!(vm_config::DeviceConfig {
264257
path,
@@ -335,67 +328,6 @@ impl Manager {
335328
Ok(())
336329
}
337330

338-
fn get_vendor(&self, mac: &str) -> Option<String> {
339-
let path = format!("/sys/bus/pci/devices/{}/vendor", mac);
340-
if let Ok(vendor) = fs::read_to_string(path) {
341-
return Some(vendor[2..].trim().to_string());
342-
} else {
343-
None
344-
}
345-
}
346-
347-
fn get_device(&self, mac: &str) -> Option<String> {
348-
let path: String = format!("/sys/bus/pci/devices/{}/device", mac);
349-
if let Ok(device) = fs::read_to_string(path) {
350-
return Some(device[2..].trim().to_string());
351-
} else {
352-
None
353-
}
354-
}
355-
356-
// TODO: move to prepare sriov
357-
fn prepare_device(&self, pci: &str) -> Result<(), io::Error> {
358-
// unbind
359-
// Check if the path exists
360-
let path = format!("/sys/bus/pci/devices/{}/driver/unbind", pci);
361-
let path = Path::new(&path);
362-
if !path.exists() {
363-
info!("UNBIND: The path {} does not exist.", path.display());
364-
} else {
365-
let content = pci.to_string();
366-
info!("try to unbind {}", pci);
367-
let mut file = fs::OpenOptions::new().write(true).open(path)?;
368-
369-
// Write the content to the file
370-
file.write_all(content.as_bytes())?;
371-
info!("unbound");
372-
}
373-
374-
// bind
375-
// Check if the path exists
376-
let path = Path::new("/sys/bus/pci/drivers/vfio-pci/new_id");
377-
if !path.exists() {
378-
info!("BIND:The path {} does not exist.", path.display());
379-
} else {
380-
let vendor = self.get_vendor(pci).unwrap_or_default();
381-
let device = self.get_device(pci).unwrap_or_default();
382-
info!("{} - {}", vendor, device);
383-
384-
let content = format!("{} {}", vendor, device);
385-
386-
let mut file = fs::OpenOptions::new().write(true).open(path)?;
387-
388-
// Write the content to the file
389-
if let Err(e) = file.write_all(content.as_bytes()) {
390-
info!("error {:?}", e);
391-
} else {
392-
info!("bound vfio-pci");
393-
}
394-
}
395-
396-
Ok(())
397-
}
398-
399331
pub fn get_vm(&self, id: Uuid) -> Result<String, Error> {
400332
let vms = self.vms.lock().unwrap();
401333
if !vms.contains_key(&id) {

0 commit comments

Comments
 (0)