@@ -110,7 +110,8 @@ fn run_qemu_vm(config: &VmLaunchConfig) -> Result<(), String> {
110110 #[ cfg( target_os = "linux" ) ]
111111 check_kvm_access ( ) ?;
112112
113- write_guest_env_file ( & config. rootfs , & config. env ) ?;
113+ let guest_env = qemu_guest_env_vars ( config, host_dns_server ( ) ) ;
114+ write_guest_env_file ( & config. rootfs , & guest_env) ?;
114115
115116 let rootfs_str = config. rootfs . to_str ( ) . ok_or ( "rootfs path not UTF-8" ) ?;
116117 let sandbox_dir = config. rootfs . parent ( ) . unwrap_or ( & config. rootfs ) ;
@@ -296,6 +297,27 @@ fn write_guest_env_file(rootfs: &Path, env_vars: &[String]) -> Result<(), String
296297 Ok ( ( ) )
297298}
298299
300+ fn qemu_guest_env_vars ( config : & VmLaunchConfig , dns_server : Option < String > ) -> Vec < String > {
301+ let mut env_vars = config. env . clone ( ) ;
302+
303+ if let Some ( ip) = & config. guest_ip
304+ && let Some ( host_ip) = & config. host_ip
305+ {
306+ env_vars. push ( format ! ( "VM_NET_IP={ip}" ) ) ;
307+ env_vars. push ( format ! ( "VM_NET_GW={host_ip}" ) ) ;
308+ }
309+
310+ if let Some ( dns) = dns_server {
311+ env_vars. push ( format ! ( "VM_NET_DNS={dns}" ) ) ;
312+ }
313+
314+ if config. gpu_bdf . is_some ( ) {
315+ env_vars. push ( "GPU_ENABLED=true" . to_string ( ) ) ;
316+ }
317+
318+ env_vars
319+ }
320+
299321/// Escape a string for use inside bash double quotes.
300322fn shell_escape ( s : & str ) -> String {
301323 s. replace ( '\\' , "\\ \\ " )
@@ -320,16 +342,9 @@ fn build_kernel_cmdline(config: &VmLaunchConfig) -> String {
320342 && let Some ( host_ip) = & config. host_ip
321343 {
322344 parts. push ( format ! ( "ip={ip}::{host_ip}:255.255.255.252:sandbox::off" ) ) ;
323- parts. push ( format ! ( "VM_NET_IP={ip}" ) ) ;
324- parts. push ( format ! ( "VM_NET_GW={host_ip}" ) ) ;
325- }
326-
327- if let Some ( dns) = host_dns_server ( ) {
328- parts. push ( format ! ( "VM_NET_DNS={dns}" ) ) ;
329345 }
330346
331347 if config. gpu_bdf . is_some ( ) {
332- parts. push ( "GPU_ENABLED=true" . to_string ( ) ) ;
333348 parts. push ( "firmware_class.path=/lib/firmware" . to_string ( ) ) ;
334349 }
335350
@@ -1310,6 +1325,56 @@ fn path_to_cstring(path: &Path) -> Result<CString, String> {
13101325 CString :: new ( path) . map_err ( |e| format ! ( "invalid path string {path}: {e}" ) )
13111326}
13121327
1328+ #[ cfg( test) ]
1329+ mod tests {
1330+ use super :: * ;
1331+
1332+ fn qemu_config ( ) -> VmLaunchConfig {
1333+ VmLaunchConfig {
1334+ rootfs : PathBuf :: from ( "/rootfs" ) ,
1335+ vcpus : 2 ,
1336+ mem_mib : 2048 ,
1337+ exec_path : "/srv/openshell-vm-sandbox-init.sh" . to_string ( ) ,
1338+ args : Vec :: new ( ) ,
1339+ env : vec ! [ "OPENSHELL_ENDPOINT=http://10.0.128.1:8080" . to_string( ) ] ,
1340+ workdir : "/" . to_string ( ) ,
1341+ log_level : 0 ,
1342+ console_output : PathBuf :: from ( "/console.log" ) ,
1343+ backend : VmBackend :: Qemu ,
1344+ gpu_bdf : Some ( "0000:01:00.0" . to_string ( ) ) ,
1345+ tap_device : Some ( "vmtap-test" . to_string ( ) ) ,
1346+ guest_ip : Some ( "10.0.128.2" . to_string ( ) ) ,
1347+ host_ip : Some ( "10.0.128.1" . to_string ( ) ) ,
1348+ vsock_cid : Some ( 4 ) ,
1349+ guest_mac : Some ( "02:00:00:00:00:01" . to_string ( ) ) ,
1350+ gateway_port : Some ( 8080 ) ,
1351+ }
1352+ }
1353+
1354+ #[ test]
1355+ fn qemu_guest_env_vars_include_driver_runtime_metadata ( ) {
1356+ let env = qemu_guest_env_vars ( & qemu_config ( ) , Some ( "1.1.1.1" . to_string ( ) ) ) ;
1357+
1358+ assert ! ( env. contains( & "OPENSHELL_ENDPOINT=http://10.0.128.1:8080" . to_string( ) ) ) ;
1359+ assert ! ( env. contains( & "VM_NET_IP=10.0.128.2" . to_string( ) ) ) ;
1360+ assert ! ( env. contains( & "VM_NET_GW=10.0.128.1" . to_string( ) ) ) ;
1361+ assert ! ( env. contains( & "VM_NET_DNS=1.1.1.1" . to_string( ) ) ) ;
1362+ assert ! ( env. contains( & "GPU_ENABLED=true" . to_string( ) ) ) ;
1363+ }
1364+
1365+ #[ test]
1366+ fn kernel_cmdline_keeps_guest_init_metadata_out_of_proc_cmdline ( ) {
1367+ let cmdline = build_kernel_cmdline ( & qemu_config ( ) ) ;
1368+
1369+ assert ! ( cmdline. contains( "ip=10.0.128.2::10.0.128.1:255.255.255.252:sandbox::off" ) ) ;
1370+ assert ! ( cmdline. contains( "firmware_class.path=/lib/firmware" ) ) ;
1371+ assert ! ( !cmdline. contains( "VM_NET_IP=" ) ) ;
1372+ assert ! ( !cmdline. contains( "VM_NET_GW=" ) ) ;
1373+ assert ! ( !cmdline. contains( "VM_NET_DNS=" ) ) ;
1374+ assert ! ( !cmdline. contains( "GPU_ENABLED=" ) ) ;
1375+ }
1376+ }
1377+
13131378#[ cfg( target_os = "linux" ) ]
13141379fn check_kvm_access ( ) -> Result < ( ) , String > {
13151380 std:: fs:: OpenOptions :: new ( )
0 commit comments