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,18 @@ impl FromStr for VsockAction {
296326 }
297327}
298328
329+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
330+ pub enum SocketConfig {
331+ /// Path to the gvproxy socket
332+ UnixSocketPath ( PathBuf ) ,
333+ UnixGram ( PathBuf , bool , bool ) ,
334+ }
335+
299336/// Configuration of a virtio-net device.
300- #[ derive( Clone , Debug , Default , PartialEq ) ]
337+ #[ derive( Clone , Debug , PartialEq ) ]
301338pub struct NetConfig {
302- /// Path to underlying gvproxy socket.
303- pub unix_socket_path : PathBuf ,
339+ /// Socket configuration
340+ pub socket : SocketConfig ,
304341
305342 /// Network MAC address.
306343 pub mac_address : MacAddress ,
@@ -310,17 +347,45 @@ impl FromStr for NetConfig {
310347 type Err = anyhow:: Error ;
311348
312349 fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
313- let mut net_config = Self :: default ( ) ;
314350 let mut args = parse_args ( s. to_string ( ) ) ?;
315- check_required_args ( & args, "virtio-net" , & [ "unixSocketPath" , "mac" ] ) ?;
316351
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" ) ?;
352+ let socket = if args. contains_key ( "unixSocketPath" ) {
353+ check_required_args ( & args, "virtio-net" , & [ "mac" ] ) ?;
354+ let path = args. remove ( "unixSocketPath" ) . unwrap ( ) ;
355+
356+ SocketConfig :: UnixSocketPath (
357+ PathBuf :: from_str ( path. as_str ( ) )
358+ . context ( "unixSocketPath argument is not a valid path" ) ?,
359+ )
360+ } else if args. contains_key ( "unixgram" ) {
361+ check_required_args ( & args, "virtio-net" , & [ "mac" , "offloading" ] ) ?;
362+ let path = args. remove ( "unixgram" ) . unwrap ( ) ;
363+ let offloading = args. remove ( "offloading" ) . unwrap ( ) ;
364+ let send_vfkit_magic = if args. contains_key ( "vfkitMagic" ) {
365+ args. remove ( "vfkitMagic" ) . unwrap ( ) . parse :: < bool > ( ) ?
366+ } else {
367+ false
368+ } ;
369+
370+ SocketConfig :: UnixGram (
371+ PathBuf :: from_str ( path. as_str ( ) )
372+ . context ( "unixSocketPath argument is not a valid path" ) ?,
373+ offloading. parse :: < bool > ( ) ?,
374+ send_vfkit_magic,
375+ )
376+ } else {
377+ return Err ( anyhow ! (
378+ "virtio-net device is missing a socket path argument"
379+ ) ) ;
380+ } ;
320381
321382 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" ) ?;
383+
384+ let net_config = NetConfig {
385+ socket,
386+ mac_address : MacAddress :: from_str ( mac. as_str ( ) )
387+ . context ( "unable to parse mac address from argument" ) ?,
388+ } ;
324389
325390 check_unknown_args ( args, "virtio-net" ) ?;
326391
@@ -331,15 +396,39 @@ impl FromStr for NetConfig {
331396/// Set the gvproxy's path and network MAC address.
332397impl KrunContextSet for NetConfig {
333398 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- ) ) ) ;
399+ match & self . socket {
400+ SocketConfig :: UnixSocketPath ( path) => {
401+ let path_cstr = path_to_cstring ( path) ?;
402+ if krun_set_gvproxy_path ( id, path_cstr. as_ptr ( ) ) < 0 {
403+ return Err ( anyhow ! ( format!(
404+ "unable to set gvproxy path {}" ,
405+ path_cstr. into_string( ) . unwrap( ) ,
406+ ) ) ) ;
407+ }
408+ }
409+ SocketConfig :: UnixGram ( path, offloading, send_vfkit_magic) => {
410+ let path_cstr = path_to_cstring ( path) ?;
411+ let features = if * offloading { NET_COMPAT_FEATURES } else { 0 } ;
412+
413+ if krun_add_net_unixgram (
414+ id,
415+ path_cstr. as_ptr ( ) ,
416+ -1 ,
417+ self . mac_address . bytes ( ) . as_ptr ( ) ,
418+ features,
419+ // Send the VFKIT magic after establishing the connection,
420+ // as required by gvproxy in vfkit mode.
421+ * send_vfkit_magic as u32 ,
422+ ) < 0
423+ {
424+ return Err ( anyhow ! ( format!(
425+ "unable to add unixgram {}" ,
426+ path_cstr. into_string( ) . unwrap( ) ,
427+ ) ) ) ;
428+ }
429+ }
342430 }
431+ let mac = self . mac_address . bytes ( ) ;
343432
344433 if krun_set_net_mac ( id, mac. as_ptr ( ) ) < 0 {
345434 return Err ( anyhow ! ( format!(
0 commit comments