33use crate :: cmdline:: { check_required_args, check_unknown_args, parse_args} ;
44
55use 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::{
1212use anyhow:: { anyhow, Context , Result } ;
1313use 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" ) ]
1638extern "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 ) ]
301341pub 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.
332400impl 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