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}
@@ -218,12 +217,117 @@ impl VmState {
218217}
219218
220219impl VmConfig {
220+ fn config_passt ( & self , workdir : & VmWorkDir , netcfg : & PasstNetworking ) -> Result < ProcessConfig > {
221+ let PasstNetworking {
222+ passt_exec,
223+ interface,
224+ address,
225+ netmask,
226+ gateway,
227+ dns,
228+ map_host_loopback,
229+ map_guest_addr,
230+ no_map_gw,
231+ ipv4_only,
232+ } = netcfg;
233+
234+ let passt_socket = workdir. passt_socket ( ) ;
235+ if passt_socket. exists ( ) {
236+ fs_err:: remove_file ( & passt_socket) . context ( "Failed to remove passt socket" ) ?;
237+ }
238+ let passt_exec = if passt_exec. is_empty ( ) {
239+ "passt"
240+ } else {
241+ passt_exec
242+ } ;
243+
244+ let passt_log = workdir. passt_log ( ) ;
245+
246+ let mut passt_cmd = Command :: new ( passt_exec) ;
247+ passt_cmd. arg ( "--socket" ) . arg ( & passt_socket) ;
248+ passt_cmd. arg ( "--log-file" ) . arg ( & passt_log) ;
249+
250+ if !interface. is_empty ( ) {
251+ passt_cmd. arg ( "--interface" ) . arg ( interface) ;
252+ }
253+ if !address. is_empty ( ) {
254+ passt_cmd. arg ( "--address" ) . arg ( address) ;
255+ }
256+ if !netmask. is_empty ( ) {
257+ passt_cmd. arg ( "--netmask" ) . arg ( netmask) ;
258+ }
259+ if !gateway. is_empty ( ) {
260+ passt_cmd. arg ( "--gateway" ) . arg ( gateway) ;
261+ }
262+ for dns in dns {
263+ passt_cmd. arg ( "--dns" ) . arg ( dns) ;
264+ }
265+ if !map_host_loopback. is_empty ( ) {
266+ passt_cmd. arg ( "--map-host-loopback" ) . arg ( map_host_loopback) ;
267+ }
268+ if !map_guest_addr. is_empty ( ) {
269+ passt_cmd. arg ( "--map-guest-addr" ) . arg ( map_guest_addr) ;
270+ }
271+ if * no_map_gw {
272+ passt_cmd. arg ( "--no-map-gw" ) ;
273+ }
274+ if * ipv4_only {
275+ passt_cmd. arg ( "--ipv4-only" ) ;
276+ }
277+ // Group port mappings by protocol
278+ let mut tcp_ports = Vec :: new ( ) ;
279+ let mut udp_ports = Vec :: new ( ) ;
280+
281+ for pm in & self . manifest . port_map {
282+ let port_spec = format ! ( "{}/{}:{}" , pm. address, pm. from, pm. to) ;
283+ match pm. protocol {
284+ Protocol :: Tcp => tcp_ports. push ( port_spec) ,
285+ Protocol :: Udp => udp_ports. push ( port_spec) ,
286+ }
287+ }
288+ // Add TCP port forwarding if any
289+ if !tcp_ports. is_empty ( ) {
290+ passt_cmd. arg ( "--tcp-ports" ) . arg ( tcp_ports. join ( "," ) ) ;
291+ }
292+ // Add UDP port forwarding if any
293+ if !udp_ports. is_empty ( ) {
294+ passt_cmd. arg ( "--udp-ports" ) . arg ( udp_ports. join ( "," ) ) ;
295+ }
296+ passt_cmd. arg ( "-f" ) . arg ( "-1" ) ;
297+
298+ let args = passt_cmd
299+ . get_args ( )
300+ . map ( |arg| arg. to_string_lossy ( ) . to_string ( ) )
301+ . collect :: < Vec < _ > > ( ) ;
302+ let stdout_path = workdir. passt_stdout ( ) ;
303+ let stderr_path = workdir. passt_stderr ( ) ;
304+ let note = ProcessAnnotation {
305+ kind : "passt" . to_string ( ) ,
306+ live_for : Some ( self . manifest . id . clone ( ) ) ,
307+ } ;
308+ let note = serde_json:: to_string ( & note) ?;
309+ let process_config = ProcessConfig {
310+ id : format ! ( "passt-{}" , self . manifest. id) ,
311+ args,
312+ name : format ! ( "passt-{}" , self . manifest. name) ,
313+ command : passt_exec. to_string ( ) ,
314+ env : Default :: default ( ) ,
315+ cwd : workdir. to_string_lossy ( ) . to_string ( ) ,
316+ stdout : stdout_path. to_string_lossy ( ) . to_string ( ) ,
317+ stderr : stderr_path. to_string_lossy ( ) . to_string ( ) ,
318+ pidfile : Default :: default ( ) ,
319+ cid : None ,
320+ note,
321+ } ;
322+ Ok ( process_config)
323+ }
324+
221325 pub fn config_qemu (
222326 & self ,
223327 workdir : impl AsRef < Path > ,
224328 cfg : & CvmConfig ,
225329 gpus : & GpuConfig ,
226- ) -> Result < ProcessConfig > {
330+ ) -> Result < Vec < ProcessConfig > > {
227331 let workdir = VmWorkDir :: new ( workdir) ;
228332 let serial_file = workdir. serial_file ( ) ;
229333 let serial_pty = workdir. serial_pty ( ) ;
@@ -302,12 +406,13 @@ impl VmConfig {
302406 }
303407 }
304408 }
409+ let mut processes = vec ! [ ] ;
305410 command
306411 . arg ( "-drive" )
307412 . arg ( format ! ( "file={},if=none,id=hd1" , hda_path. display( ) ) )
308413 . arg ( "-device" )
309414 . arg ( "virtio-blk-pci,drive=hd1" ) ;
310- let netdev = match & self . networking {
415+ let netdev = match & cfg . networking {
311416 Networking :: User ( netcfg) => {
312417 let mut netdev = format ! (
313418 "user,id=net0,net={},dhcpstart={},restrict={}" ,
@@ -326,6 +431,16 @@ impl VmConfig {
326431 }
327432 netdev
328433 }
434+ Networking :: Passt ( netcfg) => {
435+ processes. push (
436+ self . config_passt ( & workdir, netcfg)
437+ . context ( "Failed to configure passt" ) ?,
438+ ) ;
439+ format ! (
440+ "stream,id=net0,server=off,addr.type=unix,addr.path={}" ,
441+ workdir. passt_socket( ) . display( )
442+ )
443+ }
329444 Networking :: Custom ( netcfg) => netcfg. netdev . clone ( ) ,
330445 } ;
331446 command. arg ( "-netdev" ) . arg ( netdev) ;
@@ -536,7 +651,10 @@ impl VmConfig {
536651 }
537652
538653 let command = cmd_args. remove ( 0 ) ;
539- let note = "{}" . to_string ( ) ;
654+ let note = ProcessAnnotation {
655+ kind : "cvm" . to_string ( ) ,
656+ live_for : None ,
657+ } ;
540658 let note = serde_json:: to_string ( & note) ?;
541659 let process_config = ProcessConfig {
542660 id : self . manifest . id . clone ( ) ,
@@ -551,8 +669,9 @@ impl VmConfig {
551669 cid : Some ( self . cid ) ,
552670 note,
553671 } ;
672+ processes. push ( process_config) ;
554673
555- Ok ( process_config )
674+ Ok ( processes )
556675 }
557676}
558677
@@ -728,6 +847,22 @@ impl VmWorkDir {
728847 self . workdir . join ( "qmp.sock" )
729848 }
730849
850+ pub fn passt_socket ( & self ) -> PathBuf {
851+ self . workdir . join ( "passt.sock" )
852+ }
853+
854+ pub fn passt_stdout ( & self ) -> PathBuf {
855+ self . workdir . join ( "passt.stdout" )
856+ }
857+
858+ pub fn passt_stderr ( & self ) -> PathBuf {
859+ self . workdir . join ( "passt.stderr" )
860+ }
861+
862+ pub fn passt_log ( & self ) -> PathBuf {
863+ self . workdir . join ( "passt.log" )
864+ }
865+
731866 pub fn path ( & self ) -> & Path {
732867 & self . workdir
733868 }
0 commit comments