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