11//! QEMU related code
22use crate :: {
33 app:: Manifest ,
4- config:: { CvmConfig , GatewayConfig , Networking } ,
4+ config:: { CvmConfig , GatewayConfig , Networking , PasstNetworking , ProcessAnnotation , Protocol } ,
55} ;
66use std:: { collections:: HashMap , os:: unix:: fs:: PermissionsExt } ;
77use std:: {
@@ -54,7 +54,6 @@ pub struct VmConfig {
5454 pub manifest : Manifest ,
5555 pub image : Image ,
5656 pub cid : u32 ,
57- pub networking : Networking ,
5857 pub workdir : PathBuf ,
5958 pub gateway_enabled : bool ,
6059}
@@ -220,12 +219,117 @@ impl VmState {
220219}
221220
222221impl VmConfig {
222+ fn config_passt ( & self , workdir : & VmWorkDir , netcfg : & PasstNetworking ) -> Result < ProcessConfig > {
223+ let PasstNetworking {
224+ passt_exec,
225+ interface,
226+ address,
227+ netmask,
228+ gateway,
229+ dns,
230+ map_host_loopback,
231+ map_guest_addr,
232+ no_map_gw,
233+ ipv4_only,
234+ } = netcfg;
235+
236+ let passt_socket = workdir. passt_socket ( ) ;
237+ if passt_socket. exists ( ) {
238+ fs_err:: remove_file ( & passt_socket) . context ( "Failed to remove passt socket" ) ?;
239+ }
240+ let passt_exec = if passt_exec. is_empty ( ) {
241+ "passt"
242+ } else {
243+ passt_exec
244+ } ;
245+
246+ let passt_log = workdir. passt_log ( ) ;
247+
248+ let mut passt_cmd = Command :: new ( passt_exec) ;
249+ passt_cmd. arg ( "--socket" ) . arg ( & passt_socket) ;
250+ passt_cmd. arg ( "--log-file" ) . arg ( & passt_log) ;
251+
252+ if !interface. is_empty ( ) {
253+ passt_cmd. arg ( "--interface" ) . arg ( interface) ;
254+ }
255+ if !address. is_empty ( ) {
256+ passt_cmd. arg ( "--address" ) . arg ( address) ;
257+ }
258+ if !netmask. is_empty ( ) {
259+ passt_cmd. arg ( "--netmask" ) . arg ( netmask) ;
260+ }
261+ if !gateway. is_empty ( ) {
262+ passt_cmd. arg ( "--gateway" ) . arg ( gateway) ;
263+ }
264+ for dns in dns {
265+ passt_cmd. arg ( "--dns" ) . arg ( dns) ;
266+ }
267+ if !map_host_loopback. is_empty ( ) {
268+ passt_cmd. arg ( "--map-host-loopback" ) . arg ( map_host_loopback) ;
269+ }
270+ if !map_guest_addr. is_empty ( ) {
271+ passt_cmd. arg ( "--map-guest-addr" ) . arg ( map_guest_addr) ;
272+ }
273+ if * no_map_gw {
274+ passt_cmd. arg ( "--no-map-gw" ) ;
275+ }
276+ if * ipv4_only {
277+ passt_cmd. arg ( "--ipv4-only" ) ;
278+ }
279+ // Group port mappings by protocol
280+ let mut tcp_ports = Vec :: new ( ) ;
281+ let mut udp_ports = Vec :: new ( ) ;
282+
283+ for pm in & self . manifest . port_map {
284+ let port_spec = format ! ( "{}/{}:{}" , pm. address, pm. from, pm. to) ;
285+ match pm. protocol {
286+ Protocol :: Tcp => tcp_ports. push ( port_spec) ,
287+ Protocol :: Udp => udp_ports. push ( port_spec) ,
288+ }
289+ }
290+ // Add TCP port forwarding if any
291+ if !tcp_ports. is_empty ( ) {
292+ passt_cmd. arg ( "--tcp-ports" ) . arg ( tcp_ports. join ( "," ) ) ;
293+ }
294+ // Add UDP port forwarding if any
295+ if !udp_ports. is_empty ( ) {
296+ passt_cmd. arg ( "--udp-ports" ) . arg ( udp_ports. join ( "," ) ) ;
297+ }
298+ passt_cmd. arg ( "-f" ) . arg ( "-1" ) ;
299+
300+ let args = passt_cmd
301+ . get_args ( )
302+ . map ( |arg| arg. to_string_lossy ( ) . to_string ( ) )
303+ . collect :: < Vec < _ > > ( ) ;
304+ let stdout_path = workdir. passt_stdout ( ) ;
305+ let stderr_path = workdir. passt_stderr ( ) ;
306+ let note = ProcessAnnotation {
307+ kind : "passt" . to_string ( ) ,
308+ live_for : Some ( self . manifest . id . clone ( ) ) ,
309+ } ;
310+ let note = serde_json:: to_string ( & note) ?;
311+ let process_config = ProcessConfig {
312+ id : format ! ( "passt-{}" , self . manifest. id) ,
313+ args,
314+ name : format ! ( "passt-{}" , self . manifest. name) ,
315+ command : passt_exec. to_string ( ) ,
316+ env : Default :: default ( ) ,
317+ cwd : workdir. to_string_lossy ( ) . to_string ( ) ,
318+ stdout : stdout_path. to_string_lossy ( ) . to_string ( ) ,
319+ stderr : stderr_path. to_string_lossy ( ) . to_string ( ) ,
320+ pidfile : Default :: default ( ) ,
321+ cid : None ,
322+ note,
323+ } ;
324+ Ok ( process_config)
325+ }
326+
223327 pub fn config_qemu (
224328 & self ,
225329 workdir : impl AsRef < Path > ,
226330 cfg : & CvmConfig ,
227331 gpus : & GpuConfig ,
228- ) -> Result < ProcessConfig > {
332+ ) -> Result < Vec < ProcessConfig > > {
229333 let workdir = VmWorkDir :: new ( workdir) ;
230334 let serial_file = workdir. serial_file ( ) ;
231335 let serial_pty = workdir. serial_pty ( ) ;
@@ -304,12 +408,13 @@ impl VmConfig {
304408 }
305409 }
306410 }
411+ let mut processes = vec ! [ ] ;
307412 command
308413 . arg ( "-drive" )
309414 . arg ( format ! ( "file={},if=none,id=hd1" , hda_path. display( ) ) )
310415 . arg ( "-device" )
311416 . arg ( "virtio-blk-pci,drive=hd1" ) ;
312- let netdev = match & self . networking {
417+ let netdev = match & cfg . networking {
313418 Networking :: User ( netcfg) => {
314419 let mut netdev = format ! (
315420 "user,id=net0,net={},dhcpstart={},restrict={}" ,
@@ -328,6 +433,16 @@ impl VmConfig {
328433 }
329434 netdev
330435 }
436+ Networking :: Passt ( netcfg) => {
437+ processes. push (
438+ self . config_passt ( & workdir, netcfg)
439+ . context ( "Failed to configure passt" ) ?,
440+ ) ;
441+ format ! (
442+ "stream,id=net0,server=off,addr.type=unix,addr.path={}" ,
443+ workdir. passt_socket( ) . display( )
444+ )
445+ }
331446 Networking :: Custom ( netcfg) => netcfg. netdev . clone ( ) ,
332447 } ;
333448 command. arg ( "-netdev" ) . arg ( netdev) ;
@@ -538,7 +653,10 @@ impl VmConfig {
538653 }
539654
540655 let command = cmd_args. remove ( 0 ) ;
541- let note = "{}" . to_string ( ) ;
656+ let note = ProcessAnnotation {
657+ kind : "cvm" . to_string ( ) ,
658+ live_for : None ,
659+ } ;
542660 let note = serde_json:: to_string ( & note) ?;
543661 let process_config = ProcessConfig {
544662 id : self . manifest . id . clone ( ) ,
@@ -553,8 +671,9 @@ impl VmConfig {
553671 cid : Some ( self . cid ) ,
554672 note,
555673 } ;
674+ processes. push ( process_config) ;
556675
557- Ok ( process_config )
676+ Ok ( processes )
558677 }
559678}
560679
@@ -730,6 +849,22 @@ impl VmWorkDir {
730849 self . workdir . join ( "qmp.sock" )
731850 }
732851
852+ pub fn passt_socket ( & self ) -> PathBuf {
853+ self . workdir . join ( "passt.sock" )
854+ }
855+
856+ pub fn passt_stdout ( & self ) -> PathBuf {
857+ self . workdir . join ( "passt.stdout" )
858+ }
859+
860+ pub fn passt_stderr ( & self ) -> PathBuf {
861+ self . workdir . join ( "passt.stderr" )
862+ }
863+
864+ pub fn passt_log ( & self ) -> PathBuf {
865+ self . workdir . join ( "passt.log" )
866+ }
867+
733868 pub fn path ( & self ) -> & Path {
734869 & self . workdir
735870 }
0 commit comments