Skip to content

Commit b5fccbf

Browse files
committed
virtio: add new unixgram argument
Adds the new `unixgram` argument. This allows the user to create an independent unixgram-based virtio-net device rather than forcing the user to use gvproxy. Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
1 parent b78153a commit b5fccbf

2 files changed

Lines changed: 135 additions & 23 deletions

File tree

src/cmdline.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,8 @@ mod tests {
380380
"virtio-gpu,width=800,height=600",
381381
"--device",
382382
"virtio-input,keyboard",
383+
"--device",
384+
"virtio-net,unixgram=/Users/user/net.sock,mac=00:00:00:00:00:00,offloading=true,vfkitMagic=true",
383385
"--restful-uri",
384386
"tcp://localhost:49573",
385387
"--gui",
@@ -389,6 +391,23 @@ mod tests {
389391

390392
let mut args = Args::try_parse_from(cmdline).unwrap();
391393

394+
let net = args
395+
.devices
396+
.pop()
397+
.expect("expected 11th virtio device config");
398+
if let VirtioDeviceConfig::Net(net) = net {
399+
if let SocketConfig::UnixGram(path, offloading, send_vfkit_magic) = net.socket {
400+
assert_eq!(path, PathBuf::from_str("/Users/user/net.sock").unwrap());
401+
assert_eq!(offloading, true);
402+
assert_eq!(send_vfkit_magic, true);
403+
} else {
404+
panic!("expected virtio-net device to use the unixgram argument");
405+
}
406+
assert_eq!(net.mac_address, MacAddress::new([0, 0, 0, 0, 0, 0]));
407+
} else {
408+
panic!("expected virtio-net device as 11th device config argument");
409+
}
410+
392411
let input = args
393412
.devices
394413
.pop()
@@ -441,10 +460,11 @@ mod tests {
441460
.pop()
442461
.expect("expected 6th virtio device config");
443462
if let VirtioDeviceConfig::Net(net) = net {
444-
assert_eq!(
445-
net.unix_socket_path,
446-
PathBuf::from_str("/Users/user/net.sock").unwrap()
447-
);
463+
if let SocketConfig::UnixSocketPath(path) = net.socket {
464+
assert_eq!(path, PathBuf::from_str("/Users/user/net.sock").unwrap());
465+
} else {
466+
panic!("expected virtio-net device to use the unixSocketPath argument");
467+
}
448468
assert_eq!(net.mac_address, MacAddress::new([0, 0, 0, 0, 0, 0]));
449469
} else {
450470
panic!("expected virtio-net device as 6th device config argument");

src/virtio.rs

Lines changed: 111 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::cmdline::{check_required_args, check_unknown_args, parse_args};
44

55
use std::{
6-
ffi::{c_char, CString},
6+
ffi::{c_char, c_int, CString},
77
os::unix::ffi::OsStrExt,
88
path::{Path, PathBuf},
99
str::FromStr,
@@ -12,6 +12,28 @@ use std::{
1212
use anyhow::{anyhow, Context, Result};
1313
use mac_address::MacAddress;
1414

15+
/* Taken from uapi/linux/virtio_net.h */
16+
const NET_FEATURE_CSUM: u32 = 1 << 0;
17+
const NET_FEATURE_GUEST_CSUM: u32 = 1 << 1;
18+
const NET_FEATURE_GUEST_TSO4: u32 = 1 << 7;
19+
const NET_FEATURE_GUEST_TSO6: u32 = 1 << 8;
20+
const NET_FEATURE_GUEST_UFO: u32 = 1 << 10;
21+
const NET_FEATURE_HOST_TSO4: u32 = 1 << 11;
22+
const NET_FEATURE_HOST_TSO6: u32 = 1 << 12;
23+
const NET_FEATURE_HOST_UFO: u32 = 1 << 14;
24+
/*
25+
* These are the flags enabled by default on each virtio-net instance
26+
* before the introduction of "krun_add_net_*". They are now used in
27+
* the legacy API ("krun_set_passt_fd" and "krun_set_gvproxy_path")
28+
* for compatiblity reasons.
29+
*/
30+
const NET_COMPAT_FEATURES: u32 = NET_FEATURE_CSUM
31+
| NET_FEATURE_GUEST_CSUM
32+
| NET_FEATURE_GUEST_TSO4
33+
| NET_FEATURE_GUEST_UFO
34+
| NET_FEATURE_HOST_TSO4
35+
| NET_FEATURE_HOST_UFO;
36+
1537
#[link(name = "krun-efi")]
1638
extern "C" {
1739
fn krun_add_disk2(
@@ -26,6 +48,14 @@ extern "C" {
2648
fn krun_set_gvproxy_path(ctx_id: u32, c_path: *const c_char) -> i32;
2749
fn krun_set_net_mac(ctx_id: u32, c_mac: *const u8) -> i32;
2850
fn krun_set_console_output(ctx_id: u32, c_filepath: *const c_char) -> i32;
51+
fn krun_add_net_unixgram(
52+
ctx_id: u32,
53+
c_path: *const c_char,
54+
fd: c_int,
55+
c_mac: *const u8,
56+
features: u32,
57+
flags: u32,
58+
) -> i32;
2959
}
3060

3161
#[repr(u32)]
@@ -296,11 +326,21 @@ impl FromStr for VsockAction {
296326
}
297327
}
298328

329+
#[derive(Clone, Debug, PartialEq, Eq)]
330+
pub enum SocketConfig {
331+
/// Legacy socket config for creating virtio-net device using gvproxy in
332+
/// vfkit mode.
333+
UnixSocketPath(PathBuf),
334+
/// Socket config for creating an independent virtio-net device with a
335+
/// unixgram-based backend.
336+
UnixGram(PathBuf, bool, bool),
337+
}
338+
299339
/// Configuration of a virtio-net device.
300-
#[derive(Clone, Debug, Default, PartialEq)]
340+
#[derive(Clone, Debug, PartialEq)]
301341
pub struct NetConfig {
302-
/// Path to underlying gvproxy socket.
303-
pub unix_socket_path: PathBuf,
342+
/// Socket configuration
343+
pub socket: SocketConfig,
304344

305345
/// Network MAC address.
306346
pub mac_address: MacAddress,
@@ -310,17 +350,45 @@ impl FromStr for NetConfig {
310350
type Err = anyhow::Error;
311351

312352
fn from_str(s: &str) -> Result<Self, Self::Err> {
313-
let mut net_config = Self::default();
314353
let mut args = parse_args(s.to_string())?;
315-
check_required_args(&args, "virtio-net", &["unixSocketPath", "mac"])?;
316354

317-
let unix_socket_path = args.remove("unixSocketPath").unwrap();
318-
net_config.unix_socket_path = PathBuf::from_str(unix_socket_path.as_str())
319-
.context("unixSocketPath argument not a valid path")?;
355+
let socket = if args.contains_key("unixSocketPath") {
356+
check_required_args(&args, "virtio-net", &["mac"])?;
357+
let path = args.remove("unixSocketPath").unwrap();
358+
359+
SocketConfig::UnixSocketPath(
360+
PathBuf::from_str(path.as_str())
361+
.context("unixSocketPath argument is not a valid path")?,
362+
)
363+
} else if args.contains_key("unixgram") {
364+
check_required_args(&args, "virtio-net", &["mac", "offloading"])?;
365+
let path = args.remove("unixgram").unwrap();
366+
let offloading = args.remove("offloading").unwrap();
367+
let send_vfkit_magic = if args.contains_key("vfkitMagic") {
368+
args.remove("vfkitMagic").unwrap().parse::<bool>()?
369+
} else {
370+
false
371+
};
372+
373+
SocketConfig::UnixGram(
374+
PathBuf::from_str(path.as_str())
375+
.context("unixSocketPath argument is not a valid path")?,
376+
offloading.parse::<bool>()?,
377+
send_vfkit_magic,
378+
)
379+
} else {
380+
return Err(anyhow!(
381+
"virtio-net device is missing a socket path argument"
382+
));
383+
};
320384

321385
let mac = args.remove("mac").unwrap();
322-
net_config.mac_address = MacAddress::from_str(mac.as_str())
323-
.context("unable to parse mac address from argument")?;
386+
387+
let net_config = NetConfig {
388+
socket,
389+
mac_address: MacAddress::from_str(mac.as_str())
390+
.context("unable to parse mac address from argument")?,
391+
};
324392

325393
check_unknown_args(args, "virtio-net")?;
326394

@@ -331,15 +399,39 @@ impl FromStr for NetConfig {
331399
/// Set the gvproxy's path and network MAC address.
332400
impl KrunContextSet for NetConfig {
333401
unsafe fn krun_ctx_set(&self, id: u32) -> Result<(), anyhow::Error> {
334-
let path_cstr = path_to_cstring(&self.unix_socket_path)?;
335-
let mac = self.mac_address.bytes();
336-
337-
if krun_set_gvproxy_path(id, path_cstr.as_ptr()) < 0 {
338-
return Err(anyhow!(format!(
339-
"unable to set gvproxy path {}",
340-
&self.unix_socket_path.display()
341-
)));
402+
match &self.socket {
403+
SocketConfig::UnixSocketPath(path) => {
404+
let path_cstr = path_to_cstring(path)?;
405+
if krun_set_gvproxy_path(id, path_cstr.as_ptr()) < 0 {
406+
return Err(anyhow!(format!(
407+
"unable to set gvproxy path {}",
408+
path_cstr.into_string().unwrap(),
409+
)));
410+
}
411+
}
412+
SocketConfig::UnixGram(path, offloading, send_vfkit_magic) => {
413+
let path_cstr = path_to_cstring(path)?;
414+
let features = if *offloading { NET_COMPAT_FEATURES } else { 0 };
415+
416+
if krun_add_net_unixgram(
417+
id,
418+
path_cstr.as_ptr(),
419+
-1,
420+
self.mac_address.bytes().as_ptr(),
421+
features,
422+
// Send the VFKIT magic after establishing the connection,
423+
// as required by gvproxy in vfkit mode.
424+
*send_vfkit_magic as u32,
425+
) < 0
426+
{
427+
return Err(anyhow!(format!(
428+
"unable to add unixgram {}",
429+
path_cstr.into_string().unwrap(),
430+
)));
431+
}
432+
}
342433
}
434+
let mac = self.mac_address.bytes();
343435

344436
if krun_set_net_mac(id, mac.as_ptr()) < 0 {
345437
return Err(anyhow!(format!(

0 commit comments

Comments
 (0)