qemu_command_builder/
netdev.rs

1use std::net::{Ipv4Addr, Ipv6Addr};
2use std::path::PathBuf;
3
4use crate::chardev::CharDev;
5use crate::common::OnOff;
6use crate::to_command::ToArg;
7use crate::to_command::ToCommand;
8use bon::Builder;
9use ipnet::{Ipv4Net, Ipv6Net};
10
11#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
12pub struct SMB {
13    dir: PathBuf,
14    smbserver: Option<String>,
15}
16
17#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Default)]
18pub enum TcpUdp {
19    #[default]
20    Tcp,
21    Udp,
22}
23
24#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
25pub enum ScriptOrNot {
26    Script(PathBuf),
27    None,
28}
29
30impl ToCommand for ScriptOrNot {
31    fn to_command(&self) -> Vec<String> {
32        match self {
33            ScriptOrNot::Script(path) => {
34                vec![path.display().to_string()]
35            }
36            ScriptOrNot::None => {
37                vec!["no".to_string()]
38            }
39        }
40    }
41}
42#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
43pub struct HostForward {
44    protocol: Option<TcpUdp>,
45    hostaddr: Option<String>,
46    hostport: u16,
47    guestaddr: Option<String>,
48    guestport: u16,
49}
50
51#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
52pub enum GuestForwardTarget {
53    Device(CharDev),
54    Cmd((String, Vec<String>)),
55}
56#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
57pub struct GuestForward {
58    server: String,
59    port: u16,
60    target: GuestForwardTarget,
61}
62#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
63pub struct User {
64    id: String,
65    ipv4: Option<OnOff>,
66    net: Option<Ipv4Net>,
67    host: Option<Ipv4Addr>,
68    ipv6: Option<OnOff>,
69    ipv6_net: Option<Ipv6Net>,
70    ipv6_host: Option<Ipv6Addr>,
71    restrict: Option<OnOff>,
72    hostname: Option<String>,
73    dhcpstart: Option<Ipv4Addr>,
74    dns: Option<Ipv4Addr>,
75    ipv6_dns: Option<Ipv6Addr>,
76    dnssearch: Option<Vec<String>>,
77    domainname: Option<String>,
78    tftp: Option<PathBuf>,
79    tftp_server_name: Option<String>,
80    bootfile: Option<PathBuf>,
81    smb: Option<SMB>,
82    hostfwd: Option<Vec<HostForward>>,
83    guestfwd: Option<Vec<GuestForward>>,
84}
85
86impl ToCommand for User {
87    fn to_command(&self) -> Vec<String> {
88        let mut args = vec!["user".to_string(), format!("id={}", self.id.to_string())];
89
90        if let Some(ipv4) = &self.ipv4 {
91            args.push(format!("ipv4={}", ipv4.to_arg()));
92        }
93        if let Some(net) = &self.net {
94            args.push(format!("net={}", net));
95        }
96        if let Some(host) = &self.host {
97            args.push(format!("host={}", host));
98        }
99        if let Some(ipv6) = &self.ipv6 {
100            args.push(format!("ipv6={}", ipv6.to_arg()));
101        }
102        if let Some(ipv6_net) = &self.ipv6_net {
103            args.push(format!("ipv6-net={}", ipv6_net));
104        }
105        if let Some(ipv6_host) = &self.ipv6_host {
106            args.push(format!("ipv6-host={}", ipv6_host));
107        }
108        if let Some(restrict) = &self.restrict {
109            args.push(format!("restrict={}", restrict.to_arg()));
110        }
111        if let Some(hostname) = &self.hostname {
112            args.push(format!("hostname={}", hostname));
113        }
114        if let Some(dhcpstart) = &self.dhcpstart {
115            args.push(format!("dhcpstart={}", dhcpstart));
116        }
117        if let Some(dns) = &self.dns {
118            args.push(format!("dns={}", dns));
119        }
120        if let Some(ipv6_dns) = &self.ipv6_dns {
121            args.push(format!("ipv6-dns={}", ipv6_dns));
122        }
123        if let Some(dnssearch) = &self.dnssearch {
124            args.push(format!("dnssearch={}", dnssearch.join(",")));
125        }
126        if let Some(domainname) = &self.domainname {
127            args.push(format!("domainname={}", domainname));
128        }
129        if let Some(tftp) = &self.tftp {
130            args.push(format!("tftp={}", tftp.display()));
131        }
132        if let Some(tftp_server_name) = &self.tftp_server_name {
133            args.push(format!("tftp-server-name={}", tftp_server_name));
134        }
135        if let Some(bootfile) = &self.bootfile {
136            args.push(format!("bootfile={}", bootfile.display()));
137        }
138        if let Some(smb) = &self.smb {
139            args.push(format!("smb={}", smb.dir.display()));
140            if let Some(smbserver) = &smb.smbserver {
141                args.push(format!("smbserver={}", smbserver));
142            }
143        }
144        if let Some(hostfwds) = &self.hostfwd {
145            for hostfwd in hostfwds {
146                let mut subargs = vec![];
147                if let Some(proto) = &hostfwd.protocol {
148                    match proto {
149                        TcpUdp::Tcp => {
150                            subargs.push("tcp".to_string());
151                        }
152                        TcpUdp::Udp => {
153                            subargs.push("udp".to_string());
154                        }
155                    }
156                }
157                if let Some(hostaddr) = &hostfwd.hostaddr {
158                    subargs.push(hostaddr.to_string());
159                }
160                subargs.push(format!("{}-", hostfwd.hostport));
161                if let Some(guestaddr) = &hostfwd.guestaddr {
162                    subargs.push(guestaddr.to_string());
163                }
164                subargs.push(format!("{}", hostfwd.guestport));
165                args.push(subargs.join(";"));
166            }
167        }
168        if let Some(guestfwds) = &self.guestfwd {
169            for guestfwd in guestfwds {
170                let mut subargs = vec!["tcp".to_string()];
171
172                subargs.push(guestfwd.server.to_string());
173                subargs.push(format!("{}", guestfwd.port));
174
175                match &guestfwd.target {
176                    GuestForwardTarget::Device(dev) => {
177                        subargs.push(format!("device={}", dev.to_command().join(" ")));
178                    }
179                    GuestForwardTarget::Cmd((cmd, args)) => {
180                        subargs.push(format!("cmd:{} {}", cmd, args.join(" ")));
181                    }
182                }
183                args.push(subargs.join(":"));
184            }
185        }
186        vec![args.join(",")]
187    }
188}
189
190#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
191pub struct Tap {
192    id: String,
193    fd: Option<String>,
194    fds: Option<Vec<String>>,
195    ifname: Option<String>,
196    script: Option<ScriptOrNot>,
197    downscript: Option<ScriptOrNot>,
198    br: Option<String>,
199    helper: Option<String>,
200    sndbuf: Option<usize>,
201    vnet_hdr: Option<OnOff>,
202    vhost: Option<OnOff>,
203    vhostfd: Option<String>,
204    vhostforce: Option<OnOff>,
205    queues: Option<usize>,
206    poll_us: Option<usize>,
207}
208
209impl ToCommand for Tap {
210    fn to_command(&self) -> Vec<String> {
211        let mut args = vec!["tap".to_string(), format!("id={}", self.id.to_string())];
212
213        if let Some(fd) = &self.fd {
214            args.push(format!("fd={}", fd));
215        }
216        if let Some(fds) = &self.fds {
217            args.push(format!("fds={}", fds.join(":")));
218        }
219        if let Some(ifname) = &self.ifname {
220            args.push(format!("ifname={}", ifname));
221        }
222        if let Some(script) = &self.script {
223            args.push(format!("script={}", script.to_command().join("")));
224        }
225        if let Some(downscript) = &self.downscript {
226            args.push(format!("downscript={}", downscript.to_command().join("")));
227        }
228        if let Some(br) = &self.br {
229            args.push(format!("br={}", br));
230        }
231        if let Some(helper) = &self.helper {
232            args.push(format!("helper={}", helper));
233        }
234        if let Some(sndbuf) = self.sndbuf {
235            args.push(format!("sndbuf={}", sndbuf));
236        }
237        if let Some(vnet_hdr) = &self.vnet_hdr {
238            args.push(format!("vnet_hdr={}", vnet_hdr.to_arg()));
239        }
240        if let Some(vhost) = &self.vhost {
241            args.push(format!("vhost={}", vhost.to_arg()));
242        }
243        if let Some(vhostfd) = &self.vhostfd {
244            args.push(format!("vhostfd={}", vhostfd));
245        }
246        if let Some(vhostforce) = &self.vhostforce {
247            args.push(format!("vhostforce={}", vhostforce.to_arg()));
248        }
249        if let Some(queues) = self.queues {
250            args.push(format!("queues={}", queues));
251        }
252        if let Some(poll_us) = self.poll_us {
253            args.push(format!("poll_us={}", poll_us));
254        }
255
256        args
257    }
258}
259#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
260pub struct Bridge {
261    id: String,
262    bridge: Option<String>,
263    helper: Option<String>,
264}
265
266impl ToCommand for Bridge {
267    fn to_command(&self) -> Vec<String> {
268        let mut cmd = vec!["bridge".to_string(), format!("id={}", self.id)];
269
270        if let Some(br) = &self.bridge {
271            cmd.push(format!("bridge={}", br));
272        }
273        if let Some(helper) = &self.helper {
274            cmd.push(format!("helper={}", helper));
275        }
276        cmd
277    }
278}
279
280#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
281pub struct HostAndPort {
282    host: String,
283    port: u16,
284}
285#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
286pub struct HostAndMaybePort {
287    host: String,
288    port: Option<u16>,
289}
290#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
291pub struct SocketRegular {
292    id: String,
293    fd: Option<String>,
294    listen: Option<HostAndMaybePort>,
295    connection: Option<HostAndPort>,
296}
297
298impl ToCommand for SocketRegular {
299    fn to_command(&self) -> Vec<String> {
300        let mut cmd = vec!["socket".to_string(), format!("id={}", self.id)];
301
302        if let Some(fd) = &self.fd {
303            cmd.push(format!("fd={}", fd));
304        }
305        if let Some(listen) = &self.listen {
306            if let Some(port) = &listen.port {
307                cmd.push(format!("listen={}:{}", listen.host, port));
308            } else {
309                cmd.push(format!("listen={}", listen.host));
310            }
311            if let Some(connection) = &self.connection {
312                cmd.push(format!("{}:{}", connection.host, connection.port));
313            }
314        }
315
316        vec![cmd.join(",")]
317    }
318}
319#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
320pub struct SocketMulticast {
321    id: String,
322    fd: Option<String>,
323    mcast: Option<HostAndPort>,
324    localaddr: Option<String>,
325}
326
327impl ToCommand for SocketMulticast {
328    fn to_command(&self) -> Vec<String> {
329        let mut cmd = vec!["socket".to_string(), format!("id={}", self.id)];
330
331        if let Some(fd) = &self.fd {
332            cmd.push(format!("fd={}", fd));
333        }
334        if let Some(mcast) = &self.mcast {
335            cmd.push(format!("mcast={}:{}", mcast.host, mcast.port));
336        }
337        if let Some(localaddr) = &self.localaddr {
338            cmd.push(format!("localaddr={}", localaddr));
339        }
340        vec![cmd.join(",")]
341    }
342}
343#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
344pub struct SocketUdpTunnel {
345    id: String,
346    fd: Option<String>,
347    udp: Option<HostAndPort>,
348    localaddr: Option<HostAndPort>,
349}
350
351impl ToCommand for SocketUdpTunnel {
352    fn to_command(&self) -> Vec<String> {
353        let mut cmd = vec!["socket".to_string(), format!("id={}", self.id)];
354
355        if let Some(fd) = &self.fd {
356            cmd.push(format!("fd={}", fd));
357        }
358        if let Some(udp) = &self.udp {
359            cmd.push(format!("udp={}:{}", udp.host, udp.port));
360        }
361        if let Some(localaddr) = &self.localaddr {
362            cmd.push(format!("localaddr={}:{}", localaddr.host, localaddr.port));
363        }
364        vec![cmd.join(",")]
365    }
366}
367
368#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
369pub enum Socket {
370    SocketRegular(SocketRegular),
371    Multicast(SocketMulticast),
372    UDPTunnel(SocketUdpTunnel),
373}
374
375impl ToCommand for Socket {
376    fn to_command(&self) -> Vec<String> {
377        match self {
378            Socket::SocketRegular(s) => s.to_command(),
379            Socket::Multicast(s) => s.to_command(),
380            Socket::UDPTunnel(s) => s.to_command(),
381        }
382    }
383}
384#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
385pub struct StreamOverTcp {
386    id: String,
387    server: Option<OnOff>,
388    addr_host: String,
389    addr_port: u16,
390    to: Option<u16>,
391    numeric: Option<OnOff>,
392    keep_alive: Option<OnOff>,
393    mptcp: Option<OnOff>,
394    addr_ipv4: Option<OnOff>,
395    addr_ipv6: Option<OnOff>,
396    reconnect_ms: Option<usize>,
397}
398
399impl ToCommand for StreamOverTcp {
400    fn to_command(&self) -> Vec<String> {
401        let mut cmd = vec!["stream".to_string(), format!("id={}", self.id)];
402
403        if let Some(server) = &self.server {
404            cmd.push(format!("server={}", server.to_arg()));
405        }
406        cmd.push("add.type=inet".to_string());
407        cmd.push(format!("addr.host={}", self.addr_host));
408        cmd.push(format!("addr.port={}", self.addr_port));
409        if let Some(to) = &self.to {
410            cmd.push(format!("to={}", to));
411        }
412        if let Some(numeric) = &self.numeric {
413            cmd.push(format!("numeric={}", numeric.to_arg()));
414        }
415        if let Some(keep_alive) = &self.keep_alive {
416            cmd.push(format!("keep-alive={}", keep_alive.to_arg()));
417        }
418        if let Some(mptcp) = &self.mptcp {
419            cmd.push(format!("mptcp={}", mptcp.to_arg()));
420        }
421        if let Some(ipv4) = &self.addr_ipv4 {
422            cmd.push(format!("addr.ipv4={}", ipv4.to_arg()));
423        }
424        if let Some(ipv6) = &self.addr_ipv6 {
425            cmd.push(format!("addr.ipv6={}", ipv6.to_arg()));
426        }
427        if let Some(reconnect_ms) = self.reconnect_ms {
428            cmd.push(format!("reconnect-ms={}", reconnect_ms));
429        }
430        vec![cmd.join(",")]
431    }
432}
433#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
434pub struct StreamOverUds {
435    id: String,
436    server: Option<OnOff>,
437    addr_path: String,
438    abstract_arg: Option<OnOff>,
439    tight: Option<OnOff>,
440    reconnect_ms: Option<usize>,
441}
442
443impl ToCommand for StreamOverUds {
444    fn to_command(&self) -> Vec<String> {
445        let mut cmd = vec!["stream".to_string(), format!("id={}", self.id)];
446
447        if let Some(server) = &self.server {
448            cmd.push(format!("server={}", server.to_arg()));
449        }
450        cmd.push("add.type=unix".to_string());
451        cmd.push(format!("addr.path={}", self.addr_path));
452        if let Some(abstract_arg) = &self.abstract_arg {
453            cmd.push(format!("abstract={}", abstract_arg.to_arg()));
454        }
455        if let Some(tight) = &self.tight {
456            cmd.push(format!("tight={}", tight.to_arg()));
457        }
458        if let Some(reconnect_ms) = self.reconnect_ms {
459            cmd.push(format!("reconnect-ms={}", reconnect_ms));
460        }
461        vec![cmd.join(",")]
462    }
463}
464#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
465pub struct StreamOverFd {
466    id: String,
467    server: Option<OnOff>,
468    addr_str: String,
469    reconnect_ms: Option<usize>,
470}
471
472impl ToCommand for StreamOverFd {
473    fn to_command(&self) -> Vec<String> {
474        let mut cmd = vec!["stream".to_string(), format!("id={}", self.id)];
475
476        if let Some(server) = &self.server {
477            cmd.push(format!("server={}", server.to_arg()));
478        }
479        cmd.push("add.type=fd".to_string());
480        cmd.push(format!("addr.str={}", self.addr_str));
481        if let Some(reconnect_ms) = self.reconnect_ms {
482            cmd.push(format!("reconnect-ms={}", reconnect_ms));
483        }
484        vec![cmd.join(",")]
485    }
486}
487#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
488pub enum Stream {
489    StreamOverTcp(StreamOverTcp),
490    StreamOverUds(StreamOverUds),
491    StreamOverFd(StreamOverFd),
492}
493
494impl ToCommand for Stream {
495    fn to_command(&self) -> Vec<String> {
496        match self {
497            Stream::StreamOverTcp(s) => s.to_command(),
498            Stream::StreamOverUds(s) => s.to_command(),
499            Stream::StreamOverFd(s) => s.to_command(),
500        }
501    }
502}
503#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
504pub struct DgramMulticast {
505    id: String,
506    remote_host: String,
507    remote_port: u16,
508    local_host: Option<String>,
509}
510
511impl ToCommand for DgramMulticast {
512    fn to_command(&self) -> Vec<String> {
513        let mut args = vec![
514            "dgram".to_string(),
515            format!("id={}", self.id.to_string()),
516            "remote.type=inet".to_string(),
517            format!("remote.host={}", self.remote_host),
518            format!("remote.port={}", self.remote_port),
519        ];
520
521        if let Some(local_host) = &self.local_host {
522            args.push("local.type=inet".to_string());
523            args.push(format!("local.host={}", local_host));
524        }
525        args
526    }
527}
528#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
529pub struct DgramMulticastUdpFd {
530    id: String,
531    remote_host: String,
532    remote_port: u16,
533    local_str: Option<String>,
534}
535
536impl ToCommand for DgramMulticastUdpFd {
537    fn to_command(&self) -> Vec<String> {
538        let mut args = vec![
539            "dgram".to_string(),
540            format!("id={}", self.id.to_string()),
541            "remote.type=inet".to_string(),
542            format!("remote.host={}", self.remote_host),
543            format!("remote.port={}", self.remote_port),
544        ];
545
546        if let Some(local_str) = &self.local_str {
547            args.push("local.type=fd".to_string());
548            args.push(format!("local.str={}", local_str));
549        }
550        args
551    }
552}
553#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
554pub struct DgramSocket {
555    id: String,
556    local_host: String,
557    local_port: usize,
558    remote_host: Option<String>,
559    remote_port: Option<u16>,
560}
561
562impl ToCommand for DgramSocket {
563    fn to_command(&self) -> Vec<String> {
564        let mut args = vec![
565            "dgram".to_string(),
566            format!("id={}", self.id.to_string()),
567            "local.type=inet".to_string(),
568            format!("local.host={}", self.local_host),
569            format!("local.port={}", self.local_port),
570        ];
571
572        if let Some(remote_host) = &self.remote_host {
573            args.push("remote.type=inet".to_string());
574            args.push(format!("remote.host={}", remote_host));
575        }
576        if let Some(remote_port) = &self.remote_port {
577            args.push(format!("remote.port={}", remote_port));
578        }
579        args
580    }
581}
582
583#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
584pub struct DgramUds {
585    id: String,
586    local_path: PathBuf,
587    remote_path: Option<PathBuf>,
588}
589
590impl ToCommand for DgramUds {
591    fn to_command(&self) -> Vec<String> {
592        let mut args = vec![
593            "dgram".to_string(),
594            format!("id={}", self.id.to_string()),
595            "local.type=unix".to_string(),
596            format!("local.path={}", self.local_path.display()),
597        ];
598        if let Some(remote) = &self.remote_path {
599            args.push("remote.type=unix".to_string());
600            args.push(format!("remote.path={}", remote.display()));
601        }
602        args
603    }
604}
605#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
606pub struct DgramFd {
607    id: String,
608    local_str: String,
609}
610
611impl ToCommand for DgramFd {
612    fn to_command(&self) -> Vec<String> {
613        vec![
614            "dgram".to_string(),
615            format!("id={}", self.id.to_string()),
616            "local.type=fd".to_string(),
617            format!("local.str={}", self.local_str),
618        ]
619    }
620}
621#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
622pub enum Dgram {
623    DgramMulticast(DgramMulticast),
624    DgramMulticastUdpFd(DgramMulticastUdpFd),
625    DgramSocket(DgramSocket),
626    DgramUds(DgramUds),
627    DgramFd(DgramFd),
628}
629
630impl ToCommand for Dgram {
631    fn to_command(&self) -> Vec<String> {
632        match self {
633            Dgram::DgramMulticast(args) => args.to_command(),
634            Dgram::DgramMulticastUdpFd(args) => args.to_command(),
635            Dgram::DgramSocket(args) => args.to_command(),
636            Dgram::DgramUds(args) => args.to_command(),
637            Dgram::DgramFd(args) => args.to_command(),
638        }
639    }
640}
641#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
642pub struct Vde {
643    id: String,
644    sock: Option<PathBuf>,
645    port: Option<u16>,
646    group: Option<String>,
647    mode: Option<String>,
648}
649
650impl ToCommand for Vde {
651    fn to_command(&self) -> Vec<String> {
652        let mut args = vec!["vde".to_string(), format!("id={}", self.id.to_string())];
653
654        if let Some(sock) = &self.sock {
655            args.push(format!("sock={}", sock.display()));
656        }
657        if let Some(port) = self.port {
658            args.push(format!("port={}", port));
659        }
660        if let Some(group) = &self.group {
661            args.push(format!("group={}", group));
662        }
663        if let Some(mode) = &self.mode {
664            args.push(format!("mode={}", mode));
665        }
666        args
667    }
668}
669#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
670pub struct NetMap {
671    id: String,
672    ifname: String,
673    devname: Option<String>,
674}
675
676impl ToCommand for NetMap {
677    fn to_command(&self) -> Vec<String> {
678        let mut args = vec!["netmap".to_string(), format!("id={}", self.id.to_string())];
679        args.push(format!("ifname={}", self.ifname));
680        if let Some(devname) = &self.devname {
681            args.push(format!("devname={}", devname));
682        }
683        args
684    }
685}
686#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
687pub enum NativeSkb {
688    Native,
689    Skb,
690}
691
692impl ToArg for NativeSkb {
693    fn to_arg(&self) -> &str {
694        match self {
695            NativeSkb::Native => "native",
696            NativeSkb::Skb => "skb",
697        }
698    }
699}
700#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
701pub struct AfXdp {
702    id: String,
703    ifname: String,
704    mode: Option<NativeSkb>,
705    force_copy: Option<OnOff>,
706    queues: Option<usize>,
707    start_queue: Option<usize>,
708    inhibit: Option<OnOff>,
709    sock_fds: Option<Vec<String>>,
710}
711
712impl ToCommand for AfXdp {
713    fn to_command(&self) -> Vec<String> {
714        let mut args = vec![
715            "af-xdp".to_string(),
716            format!("id={}", self.id.to_string()),
717            format!("ifname={}", self.ifname),
718        ];
719
720        if let Some(mode) = &self.mode {
721            args.push(format!("mode={}", mode.to_arg()));
722        }
723        if let Some(force_copy) = &self.force_copy {
724            args.push(format!("force-copy={}", force_copy.to_arg()));
725        }
726        if let Some(queues) = self.queues {
727            args.push(format!("queues={}", queues));
728        }
729        if let Some(start_queue) = self.start_queue {
730            args.push(format!("start-queue={}", start_queue));
731        }
732        if let Some(inhibit) = &self.inhibit {
733            args.push(format!("inhibit={}", inhibit.to_arg()));
734        }
735        if let Some(sock_fds) = &self.sock_fds {
736            args.push(format!("sock-fds={}", sock_fds.join(":")));
737        }
738        args
739    }
740}
741#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
742pub struct VhostUser {
743    id: String,
744    chardev: String,
745    vhostforce: Option<OnOff>,
746}
747
748impl ToCommand for VhostUser {
749    fn to_command(&self) -> Vec<String> {
750        let mut args = vec![
751            "vhost-user".to_string(),
752            format!("id={}", self.id.to_string()),
753            format!("chardev={}", self.chardev),
754        ];
755
756        if let Some(vhostforce) = &self.vhostforce {
757            args.push(format!("vhostforce={}", vhostforce.to_arg()));
758        }
759        args
760    }
761}
762#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
763pub struct VhostVdpa {
764    id: String,
765    vhostdev: Option<PathBuf>,
766    vhostfd: Option<String>,
767}
768
769impl ToCommand for VhostVdpa {
770    fn to_command(&self) -> Vec<String> {
771        let mut args = vec![
772            "vhost-vdpa".to_string(),
773            format!("id={}", self.id.to_string()),
774        ];
775        if let Some(vhostdev) = &self.vhostdev {
776            args.push(format!("vhostdev={}", vhostdev.to_str().unwrap()));
777        }
778        if let Some(vhostfd) = &self.vhostfd {
779            args.push(format!("vhostfd={}", vhostfd));
780        }
781        args
782    }
783}
784#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
785pub struct VmnetHost {
786    id: String,
787    isolated: Option<OnOff>,
788    net_uuid: Option<String>,
789    start_address: Option<String>,
790    end_address: Option<String>,
791    subnet_mask: Option<String>,
792}
793
794impl ToCommand for VmnetHost {
795    fn to_command(&self) -> Vec<String> {
796        let mut args = vec![
797            "vmnet-host".to_string(),
798            format!("id={}", self.id.to_string()),
799        ];
800
801        if let Some(isolated) = &self.isolated {
802            args.push(format!("isolated={}", isolated.to_arg()));
803        }
804        if let Some(net_uuid) = &self.net_uuid {
805            args.push(format!("net_uuid={}", net_uuid));
806        }
807        if let Some(start_address) = &self.start_address {
808            args.push(format!("start-address={}", start_address));
809        }
810        if let Some(end_address) = &self.end_address {
811            args.push(format!("end-address={}", end_address));
812        }
813        if let Some(subnet_mask) = &self.subnet_mask {
814            args.push(format!("subnet-mask={}", subnet_mask));
815        }
816        args
817    }
818}
819
820#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
821pub struct VmnetShared {
822    id: String,
823    isolated: Option<OnOff>,
824    nat66_prefix: Option<String>,
825    start_address: Option<String>,
826    end_address: Option<String>,
827    subnet_mask: Option<String>,
828}
829
830impl ToCommand for VmnetShared {
831    fn to_command(&self) -> Vec<String> {
832        let mut args = vec![
833            "vmnet-shared".to_string(),
834            format!("id={}", self.id.to_string()),
835        ];
836
837        if let Some(isolated) = &self.isolated {
838            args.push(format!("isolated={}", isolated.to_arg()));
839        }
840        if let Some(nat66_prefix) = &self.nat66_prefix {
841            args.push(format!("nat66-prefix={}", nat66_prefix));
842        }
843        if let Some(start_address) = &self.start_address {
844            args.push(format!("start-address={}", start_address));
845        }
846        if let Some(end_address) = &self.end_address {
847            args.push(format!("end-address={}", end_address));
848        }
849        if let Some(subnet_mask) = &self.subnet_mask {
850            args.push(format!("subnet-mask={}", subnet_mask));
851        }
852        args
853    }
854}
855#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
856pub struct VmnetBridged {
857    id: String,
858    ifname: String,
859    isolated: Option<OnOff>,
860}
861
862impl ToCommand for VmnetBridged {
863    fn to_command(&self) -> Vec<String> {
864        let mut args = vec![
865            "vmnet-bridged".to_string(),
866            format!("id={}", self.id.to_string()),
867            format!("ifname={}", self.ifname),
868        ];
869
870        if let Some(isolated) = &self.isolated {
871            args.push(format!("isolated={}", isolated.to_arg()));
872        }
873        args
874    }
875}
876#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
877pub struct Hubport {
878    id: String,
879    hubid: usize,
880    netdev: Option<String>,
881}
882
883impl ToCommand for Hubport {
884    fn to_command(&self) -> Vec<String> {
885        let mut args = vec![
886            "hubport".to_string(),
887            format!("id={}", self.id.to_string()),
888            format!("hubid={}", self.hubid),
889        ];
890
891        if let Some(netdev) = &self.netdev {
892            args.push(format!("netdev={}", netdev));
893        }
894        args
895    }
896}
897#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
898pub enum NetDev {
899    User(User),
900    // TODO L2tpv3,
901    Tap(Tap),
902    Bridge(Bridge),
903    Socket(Socket),
904    Stream(Stream),
905    Dgram(Dgram),
906    Vde(Vde),
907    Netmap(NetMap),
908    AfXdp(AfXdp),
909    VhostUser(VhostUser),
910    VhostVdpa(VhostVdpa),
911    VmnetHost(VmnetHost),
912    VmnetShared(VmnetShared),
913    VmnetBridged(VmnetBridged),
914    Hubport(Hubport),
915}
916
917impl ToCommand for NetDev {
918    fn to_command(&self) -> Vec<String> {
919        let mut cmd = vec![];
920
921        cmd.push("-netdev".to_string());
922
923        let mut args: Vec<String> = vec![];
924
925        match self {
926            NetDev::User(user) => {
927                args.append(&mut user.to_command());
928            }
929            //NetDev::L2tpv3 => {}
930            NetDev::Tap(tap) => {
931                args.append(&mut tap.to_command());
932            }
933            NetDev::Bridge(bridge) => {
934                args.append(&mut bridge.to_command());
935            }
936            NetDev::Socket(socket) => {
937                args.append(&mut socket.to_command());
938            }
939            NetDev::Stream(stream) => {
940                args.append(&mut stream.to_command());
941            }
942            NetDev::Dgram(dgram) => {
943                args.append(&mut dgram.to_command());
944            }
945            NetDev::Vde(vde) => {
946                args.append(&mut vde.to_command());
947            }
948            NetDev::Netmap(netmap) => {
949                args.append(&mut netmap.to_command());
950            }
951            NetDev::AfXdp(af_xdp) => {
952                args.append(&mut af_xdp.to_command());
953            }
954            NetDev::VhostUser(vhost_user) => {
955                args.append(&mut vhost_user.to_command());
956            }
957            NetDev::VhostVdpa(vhost_vdpa) => {
958                args.append(&mut vhost_vdpa.to_command());
959            }
960            NetDev::VmnetHost(vmnet_host) => {
961                args.append(&mut vmnet_host.to_command());
962            }
963            NetDev::VmnetShared(vmnet_shared) => {
964                args.append(&mut vmnet_shared.to_command());
965            }
966            NetDev::VmnetBridged(vmnet_bridged) => {
967                args.append(&mut vmnet_bridged.to_command());
968            }
969            NetDev::Hubport(hubport) => {
970                args.append(&mut hubport.to_command());
971            }
972        }
973        cmd.push(args.join(","));
974        cmd
975    }
976}