xref: /openbmc/qemu/net/passt.c (revision 854ee02b22220377f3fa3806adf7e0718c3a5c5a)
1*854ee02bSLaurent Vivier /*
2*854ee02bSLaurent Vivier  * passt network backend
3*854ee02bSLaurent Vivier  *
4*854ee02bSLaurent Vivier  * Copyright Red Hat
5*854ee02bSLaurent Vivier  *
6*854ee02bSLaurent Vivier  * SPDX-License-Identifier: GPL-2.0-or-later
7*854ee02bSLaurent Vivier  */
8*854ee02bSLaurent Vivier #include "qemu/osdep.h"
9*854ee02bSLaurent Vivier #include <glib/gstdio.h>
10*854ee02bSLaurent Vivier #include <gio/gio.h>
11*854ee02bSLaurent Vivier #include "net/net.h"
12*854ee02bSLaurent Vivier #include "clients.h"
13*854ee02bSLaurent Vivier #include "qapi/error.h"
14*854ee02bSLaurent Vivier #include "io/net-listener.h"
15*854ee02bSLaurent Vivier #include "stream_data.h"
16*854ee02bSLaurent Vivier 
17*854ee02bSLaurent Vivier typedef struct NetPasstState {
18*854ee02bSLaurent Vivier     NetStreamData data;
19*854ee02bSLaurent Vivier     GPtrArray *args;
20*854ee02bSLaurent Vivier     gchar *pidfile;
21*854ee02bSLaurent Vivier     pid_t pid;
22*854ee02bSLaurent Vivier } NetPasstState;
23*854ee02bSLaurent Vivier 
24*854ee02bSLaurent Vivier static int net_passt_stream_start(NetPasstState *s, Error **errp);
25*854ee02bSLaurent Vivier 
26*854ee02bSLaurent Vivier static void net_passt_cleanup(NetClientState *nc)
27*854ee02bSLaurent Vivier {
28*854ee02bSLaurent Vivier     NetPasstState *s = DO_UPCAST(NetPasstState, data.nc, nc);
29*854ee02bSLaurent Vivier 
30*854ee02bSLaurent Vivier     kill(s->pid, SIGTERM);
31*854ee02bSLaurent Vivier     g_remove(s->pidfile);
32*854ee02bSLaurent Vivier     g_free(s->pidfile);
33*854ee02bSLaurent Vivier     g_ptr_array_free(s->args, TRUE);
34*854ee02bSLaurent Vivier }
35*854ee02bSLaurent Vivier 
36*854ee02bSLaurent Vivier static ssize_t net_passt_receive(NetClientState *nc, const uint8_t *buf,
37*854ee02bSLaurent Vivier                                   size_t size)
38*854ee02bSLaurent Vivier {
39*854ee02bSLaurent Vivier     NetStreamData *d = DO_UPCAST(NetStreamData, nc, nc);
40*854ee02bSLaurent Vivier 
41*854ee02bSLaurent Vivier     return net_stream_data_receive(d, buf, size);
42*854ee02bSLaurent Vivier }
43*854ee02bSLaurent Vivier 
44*854ee02bSLaurent Vivier static gboolean net_passt_send(QIOChannel *ioc, GIOCondition condition,
45*854ee02bSLaurent Vivier                                 gpointer data)
46*854ee02bSLaurent Vivier {
47*854ee02bSLaurent Vivier     if (net_stream_data_send(ioc, condition, data) == G_SOURCE_REMOVE) {
48*854ee02bSLaurent Vivier         NetPasstState *s = DO_UPCAST(NetPasstState, data, data);
49*854ee02bSLaurent Vivier         Error *error;
50*854ee02bSLaurent Vivier 
51*854ee02bSLaurent Vivier         /* we need to restart passt */
52*854ee02bSLaurent Vivier         kill(s->pid, SIGTERM);
53*854ee02bSLaurent Vivier         if (net_passt_stream_start(s, &error) == -1) {
54*854ee02bSLaurent Vivier             error_report_err(error);
55*854ee02bSLaurent Vivier         }
56*854ee02bSLaurent Vivier 
57*854ee02bSLaurent Vivier         return G_SOURCE_REMOVE;
58*854ee02bSLaurent Vivier     }
59*854ee02bSLaurent Vivier 
60*854ee02bSLaurent Vivier     return G_SOURCE_CONTINUE;
61*854ee02bSLaurent Vivier }
62*854ee02bSLaurent Vivier 
63*854ee02bSLaurent Vivier static NetClientInfo net_passt_info = {
64*854ee02bSLaurent Vivier     .type = NET_CLIENT_DRIVER_PASST,
65*854ee02bSLaurent Vivier     .size = sizeof(NetPasstState),
66*854ee02bSLaurent Vivier     .receive = net_passt_receive,
67*854ee02bSLaurent Vivier     .cleanup = net_passt_cleanup,
68*854ee02bSLaurent Vivier };
69*854ee02bSLaurent Vivier 
70*854ee02bSLaurent Vivier static void net_passt_client_connected(QIOTask *task, gpointer opaque)
71*854ee02bSLaurent Vivier {
72*854ee02bSLaurent Vivier     NetPasstState *s = opaque;
73*854ee02bSLaurent Vivier 
74*854ee02bSLaurent Vivier     if (net_stream_data_client_connected(task, &s->data) == 0) {
75*854ee02bSLaurent Vivier         qemu_set_info_str(&s->data.nc, "stream,connected to pid %d", s->pid);
76*854ee02bSLaurent Vivier     }
77*854ee02bSLaurent Vivier }
78*854ee02bSLaurent Vivier 
79*854ee02bSLaurent Vivier static int net_passt_start_daemon(NetPasstState *s, int sock, Error **errp)
80*854ee02bSLaurent Vivier {
81*854ee02bSLaurent Vivier     g_autoptr(GSubprocess) daemon = NULL;
82*854ee02bSLaurent Vivier     g_autofree gchar *contents = NULL;
83*854ee02bSLaurent Vivier     g_autoptr(GError) error = NULL;
84*854ee02bSLaurent Vivier     GSubprocessLauncher *launcher;
85*854ee02bSLaurent Vivier 
86*854ee02bSLaurent Vivier     qemu_set_info_str(&s->data.nc, "launching passt");
87*854ee02bSLaurent Vivier 
88*854ee02bSLaurent Vivier     launcher = g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_NONE);
89*854ee02bSLaurent Vivier     g_subprocess_launcher_take_fd(launcher, sock, 3);
90*854ee02bSLaurent Vivier 
91*854ee02bSLaurent Vivier     daemon =  g_subprocess_launcher_spawnv(launcher,
92*854ee02bSLaurent Vivier                                            (const gchar *const *)s->args->pdata,
93*854ee02bSLaurent Vivier                                            &error);
94*854ee02bSLaurent Vivier     g_object_unref(launcher);
95*854ee02bSLaurent Vivier 
96*854ee02bSLaurent Vivier     if (!daemon) {
97*854ee02bSLaurent Vivier         error_setg(errp, "Error creating daemon: %s", error->message);
98*854ee02bSLaurent Vivier         return -1;
99*854ee02bSLaurent Vivier     }
100*854ee02bSLaurent Vivier 
101*854ee02bSLaurent Vivier     if (!g_subprocess_wait(daemon, NULL, &error)) {
102*854ee02bSLaurent Vivier         error_setg(errp, "Error waiting for daemon: %s", error->message);
103*854ee02bSLaurent Vivier         return -1;
104*854ee02bSLaurent Vivier     }
105*854ee02bSLaurent Vivier 
106*854ee02bSLaurent Vivier     if (g_subprocess_get_if_exited(daemon) &&
107*854ee02bSLaurent Vivier         g_subprocess_get_exit_status(daemon)) {
108*854ee02bSLaurent Vivier         return -1;
109*854ee02bSLaurent Vivier     }
110*854ee02bSLaurent Vivier 
111*854ee02bSLaurent Vivier     if (!g_file_get_contents(s->pidfile, &contents, NULL, &error)) {
112*854ee02bSLaurent Vivier         error_setg(errp, "Cannot read passt pid: %s", error->message);
113*854ee02bSLaurent Vivier         return -1;
114*854ee02bSLaurent Vivier     }
115*854ee02bSLaurent Vivier 
116*854ee02bSLaurent Vivier     s->pid = (pid_t)g_ascii_strtoll(contents, NULL, 10);
117*854ee02bSLaurent Vivier     if (s->pid <= 0) {
118*854ee02bSLaurent Vivier         error_setg(errp, "File '%s' did not contain a valid PID.", s->pidfile);
119*854ee02bSLaurent Vivier         return -1;
120*854ee02bSLaurent Vivier     }
121*854ee02bSLaurent Vivier 
122*854ee02bSLaurent Vivier     return 0;
123*854ee02bSLaurent Vivier }
124*854ee02bSLaurent Vivier 
125*854ee02bSLaurent Vivier static int net_passt_stream_start(NetPasstState *s, Error **errp)
126*854ee02bSLaurent Vivier {
127*854ee02bSLaurent Vivier     QIOChannelSocket *sioc;
128*854ee02bSLaurent Vivier     SocketAddress *addr;
129*854ee02bSLaurent Vivier     int sv[2];
130*854ee02bSLaurent Vivier 
131*854ee02bSLaurent Vivier     if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
132*854ee02bSLaurent Vivier         error_setg_errno(errp, errno, "socketpair() failed");
133*854ee02bSLaurent Vivier         return -1;
134*854ee02bSLaurent Vivier     }
135*854ee02bSLaurent Vivier 
136*854ee02bSLaurent Vivier     /* connect to passt */
137*854ee02bSLaurent Vivier     qemu_set_info_str(&s->data.nc, "connecting to passt");
138*854ee02bSLaurent Vivier 
139*854ee02bSLaurent Vivier     /* create socket channel */
140*854ee02bSLaurent Vivier     sioc = qio_channel_socket_new();
141*854ee02bSLaurent Vivier     s->data.ioc = QIO_CHANNEL(sioc);
142*854ee02bSLaurent Vivier     s->data.nc.link_down = true;
143*854ee02bSLaurent Vivier     s->data.send = net_passt_send;
144*854ee02bSLaurent Vivier 
145*854ee02bSLaurent Vivier     addr = g_new0(SocketAddress, 1);
146*854ee02bSLaurent Vivier     addr->type = SOCKET_ADDRESS_TYPE_FD;
147*854ee02bSLaurent Vivier     addr->u.fd.str = g_strdup_printf("%d", sv[0]);
148*854ee02bSLaurent Vivier 
149*854ee02bSLaurent Vivier     qio_channel_socket_connect_async(sioc, addr,
150*854ee02bSLaurent Vivier                                      net_passt_client_connected, s,
151*854ee02bSLaurent Vivier                                      NULL, NULL);
152*854ee02bSLaurent Vivier 
153*854ee02bSLaurent Vivier     qapi_free_SocketAddress(addr);
154*854ee02bSLaurent Vivier 
155*854ee02bSLaurent Vivier     /* start passt */
156*854ee02bSLaurent Vivier     if (net_passt_start_daemon(s, sv[1], errp) == -1) {
157*854ee02bSLaurent Vivier         close(sv[0]);
158*854ee02bSLaurent Vivier         close(sv[1]);
159*854ee02bSLaurent Vivier         return -1;
160*854ee02bSLaurent Vivier     }
161*854ee02bSLaurent Vivier     close(sv[1]);
162*854ee02bSLaurent Vivier 
163*854ee02bSLaurent Vivier     return 0;
164*854ee02bSLaurent Vivier }
165*854ee02bSLaurent Vivier 
166*854ee02bSLaurent Vivier static GPtrArray *net_passt_decode_args(const NetDevPasstOptions *passt,
167*854ee02bSLaurent Vivier                                         gchar *pidfile, Error **errp)
168*854ee02bSLaurent Vivier {
169*854ee02bSLaurent Vivier     GPtrArray *args = g_ptr_array_new_with_free_func(g_free);
170*854ee02bSLaurent Vivier 
171*854ee02bSLaurent Vivier     if (passt->path) {
172*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->path));
173*854ee02bSLaurent Vivier     } else {
174*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("passt"));
175*854ee02bSLaurent Vivier     }
176*854ee02bSLaurent Vivier 
177*854ee02bSLaurent Vivier     /* by default, be quiet */
178*854ee02bSLaurent Vivier     if (!passt->has_quiet || passt->quiet) {
179*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--quiet"));
180*854ee02bSLaurent Vivier     }
181*854ee02bSLaurent Vivier 
182*854ee02bSLaurent Vivier     if (passt->has_mtu) {
183*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--mtu"));
184*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup_printf("%"PRId64, passt->mtu));
185*854ee02bSLaurent Vivier     }
186*854ee02bSLaurent Vivier 
187*854ee02bSLaurent Vivier     if (passt->address) {
188*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--address"));
189*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->address));
190*854ee02bSLaurent Vivier     }
191*854ee02bSLaurent Vivier 
192*854ee02bSLaurent Vivier     if (passt->netmask) {
193*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--netmask"));
194*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->netmask));
195*854ee02bSLaurent Vivier     }
196*854ee02bSLaurent Vivier 
197*854ee02bSLaurent Vivier     if (passt->mac) {
198*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--mac-addr"));
199*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->mac));
200*854ee02bSLaurent Vivier     }
201*854ee02bSLaurent Vivier 
202*854ee02bSLaurent Vivier     if (passt->gateway) {
203*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--gateway"));
204*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->gateway));
205*854ee02bSLaurent Vivier     }
206*854ee02bSLaurent Vivier 
207*854ee02bSLaurent Vivier     if (passt->interface) {
208*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--interface"));
209*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->interface));
210*854ee02bSLaurent Vivier     }
211*854ee02bSLaurent Vivier 
212*854ee02bSLaurent Vivier     if (passt->outbound) {
213*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--outbound"));
214*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->outbound));
215*854ee02bSLaurent Vivier     }
216*854ee02bSLaurent Vivier 
217*854ee02bSLaurent Vivier     if (passt->outbound_if4) {
218*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--outbound-if4"));
219*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->outbound_if4));
220*854ee02bSLaurent Vivier     }
221*854ee02bSLaurent Vivier 
222*854ee02bSLaurent Vivier     if (passt->outbound_if6) {
223*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--outbound-if6"));
224*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->outbound_if6));
225*854ee02bSLaurent Vivier     }
226*854ee02bSLaurent Vivier 
227*854ee02bSLaurent Vivier     if (passt->dns) {
228*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--dns"));
229*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->dns));
230*854ee02bSLaurent Vivier     }
231*854ee02bSLaurent Vivier     if (passt->fqdn) {
232*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--fqdn"));
233*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->fqdn));
234*854ee02bSLaurent Vivier     }
235*854ee02bSLaurent Vivier 
236*854ee02bSLaurent Vivier     if (passt->has_dhcp_dns && !passt->dhcp_dns) {
237*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--no-dhcp-dns"));
238*854ee02bSLaurent Vivier     }
239*854ee02bSLaurent Vivier 
240*854ee02bSLaurent Vivier     if (passt->has_dhcp_search && !passt->dhcp_search) {
241*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--no-dhcp-search"));
242*854ee02bSLaurent Vivier     }
243*854ee02bSLaurent Vivier 
244*854ee02bSLaurent Vivier     if (passt->map_host_loopback) {
245*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--map-host-loopback"));
246*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->map_host_loopback));
247*854ee02bSLaurent Vivier     }
248*854ee02bSLaurent Vivier 
249*854ee02bSLaurent Vivier     if (passt->map_guest_addr) {
250*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--map-guest-addr"));
251*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->map_guest_addr));
252*854ee02bSLaurent Vivier     }
253*854ee02bSLaurent Vivier 
254*854ee02bSLaurent Vivier     if (passt->dns_forward) {
255*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--dns-forward"));
256*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->dns_forward));
257*854ee02bSLaurent Vivier     }
258*854ee02bSLaurent Vivier 
259*854ee02bSLaurent Vivier     if (passt->dns_host) {
260*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--dns-host"));
261*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup(passt->dns_host));
262*854ee02bSLaurent Vivier     }
263*854ee02bSLaurent Vivier 
264*854ee02bSLaurent Vivier     if (passt->has_tcp && !passt->tcp) {
265*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--no-tcp"));
266*854ee02bSLaurent Vivier     }
267*854ee02bSLaurent Vivier 
268*854ee02bSLaurent Vivier     if (passt->has_udp && !passt->udp) {
269*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--no-udp"));
270*854ee02bSLaurent Vivier     }
271*854ee02bSLaurent Vivier 
272*854ee02bSLaurent Vivier     if (passt->has_icmp && !passt->icmp) {
273*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--no-icmp"));
274*854ee02bSLaurent Vivier     }
275*854ee02bSLaurent Vivier 
276*854ee02bSLaurent Vivier     if (passt->has_dhcp && !passt->dhcp) {
277*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--no-dhcp"));
278*854ee02bSLaurent Vivier     }
279*854ee02bSLaurent Vivier 
280*854ee02bSLaurent Vivier     if (passt->has_ndp && !passt->ndp) {
281*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--no-ndp"));
282*854ee02bSLaurent Vivier     }
283*854ee02bSLaurent Vivier     if (passt->has_dhcpv6 && !passt->dhcpv6) {
284*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--no-dhcpv6"));
285*854ee02bSLaurent Vivier     }
286*854ee02bSLaurent Vivier 
287*854ee02bSLaurent Vivier     if (passt->has_ra && !passt->ra) {
288*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--no-ra"));
289*854ee02bSLaurent Vivier     }
290*854ee02bSLaurent Vivier 
291*854ee02bSLaurent Vivier     if (passt->has_freebind && passt->freebind) {
292*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--freebind"));
293*854ee02bSLaurent Vivier     }
294*854ee02bSLaurent Vivier 
295*854ee02bSLaurent Vivier     if (passt->has_ipv4 && !passt->ipv4) {
296*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--ipv6-only"));
297*854ee02bSLaurent Vivier     }
298*854ee02bSLaurent Vivier 
299*854ee02bSLaurent Vivier     if (passt->has_ipv6 && !passt->ipv6) {
300*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--ipv4-only"));
301*854ee02bSLaurent Vivier     }
302*854ee02bSLaurent Vivier 
303*854ee02bSLaurent Vivier     if (passt->has_search && passt->search) {
304*854ee02bSLaurent Vivier         const StringList *list = passt->search;
305*854ee02bSLaurent Vivier         GString *domains = g_string_new(list->value->str);
306*854ee02bSLaurent Vivier 
307*854ee02bSLaurent Vivier         list = list->next;
308*854ee02bSLaurent Vivier         while (list) {
309*854ee02bSLaurent Vivier             g_string_append(domains, " ");
310*854ee02bSLaurent Vivier             g_string_append(domains, list->value->str);
311*854ee02bSLaurent Vivier             list = list->next;
312*854ee02bSLaurent Vivier         }
313*854ee02bSLaurent Vivier 
314*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--search"));
315*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_string_free(domains, FALSE));
316*854ee02bSLaurent Vivier     }
317*854ee02bSLaurent Vivier 
318*854ee02bSLaurent Vivier     if (passt->has_tcp_ports && passt->tcp_ports) {
319*854ee02bSLaurent Vivier         const StringList *list = passt->tcp_ports;
320*854ee02bSLaurent Vivier         GString *tcp_ports = g_string_new(list->value->str);
321*854ee02bSLaurent Vivier 
322*854ee02bSLaurent Vivier         list = list->next;
323*854ee02bSLaurent Vivier         while (list) {
324*854ee02bSLaurent Vivier             g_string_append(tcp_ports, ",");
325*854ee02bSLaurent Vivier             g_string_append(tcp_ports, list->value->str);
326*854ee02bSLaurent Vivier             list = list->next;
327*854ee02bSLaurent Vivier         }
328*854ee02bSLaurent Vivier 
329*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--tcp-ports"));
330*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_string_free(tcp_ports, FALSE));
331*854ee02bSLaurent Vivier     }
332*854ee02bSLaurent Vivier 
333*854ee02bSLaurent Vivier     if (passt->has_udp_ports && passt->udp_ports) {
334*854ee02bSLaurent Vivier         const StringList *list = passt->udp_ports;
335*854ee02bSLaurent Vivier         GString *udp_ports = g_string_new(list->value->str);
336*854ee02bSLaurent Vivier 
337*854ee02bSLaurent Vivier         list = list->next;
338*854ee02bSLaurent Vivier         while (list) {
339*854ee02bSLaurent Vivier             g_string_append(udp_ports, ",");
340*854ee02bSLaurent Vivier             g_string_append(udp_ports, list->value->str);
341*854ee02bSLaurent Vivier             list = list->next;
342*854ee02bSLaurent Vivier         }
343*854ee02bSLaurent Vivier 
344*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_strdup("--udp-ports"));
345*854ee02bSLaurent Vivier         g_ptr_array_add(args, g_string_free(udp_ports, FALSE));
346*854ee02bSLaurent Vivier     }
347*854ee02bSLaurent Vivier 
348*854ee02bSLaurent Vivier     if (passt->has_param && passt->param) {
349*854ee02bSLaurent Vivier         const StringList *list = passt->param;
350*854ee02bSLaurent Vivier 
351*854ee02bSLaurent Vivier         while (list) {
352*854ee02bSLaurent Vivier             g_ptr_array_add(args, g_strdup(list->value->str));
353*854ee02bSLaurent Vivier             list = list->next;
354*854ee02bSLaurent Vivier         }
355*854ee02bSLaurent Vivier     }
356*854ee02bSLaurent Vivier 
357*854ee02bSLaurent Vivier     /* provide a pid file to be able to kil passt on exit */
358*854ee02bSLaurent Vivier     g_ptr_array_add(args, g_strdup("--pid"));
359*854ee02bSLaurent Vivier     g_ptr_array_add(args, g_strdup(pidfile));
360*854ee02bSLaurent Vivier 
361*854ee02bSLaurent Vivier     /* g_subprocess_launcher_take_fd() will set the socket on fd 3 */
362*854ee02bSLaurent Vivier     g_ptr_array_add(args, g_strdup("--fd"));
363*854ee02bSLaurent Vivier     g_ptr_array_add(args, g_strdup("3"));
364*854ee02bSLaurent Vivier 
365*854ee02bSLaurent Vivier     g_ptr_array_add(args, NULL);
366*854ee02bSLaurent Vivier 
367*854ee02bSLaurent Vivier     return args;
368*854ee02bSLaurent Vivier }
369*854ee02bSLaurent Vivier 
370*854ee02bSLaurent Vivier int net_init_passt(const Netdev *netdev, const char *name,
371*854ee02bSLaurent Vivier                    NetClientState *peer, Error **errp)
372*854ee02bSLaurent Vivier {
373*854ee02bSLaurent Vivier     g_autoptr(GError) error = NULL;
374*854ee02bSLaurent Vivier     NetClientState *nc;
375*854ee02bSLaurent Vivier     NetPasstState *s;
376*854ee02bSLaurent Vivier     GPtrArray *args;
377*854ee02bSLaurent Vivier     gchar *pidfile;
378*854ee02bSLaurent Vivier     int pidfd;
379*854ee02bSLaurent Vivier 
380*854ee02bSLaurent Vivier     assert(netdev->type == NET_CLIENT_DRIVER_PASST);
381*854ee02bSLaurent Vivier 
382*854ee02bSLaurent Vivier     pidfd = g_file_open_tmp("passt-XXXXXX.pid", &pidfile, &error);
383*854ee02bSLaurent Vivier     if (pidfd == -1) {
384*854ee02bSLaurent Vivier         error_setg(errp, "Failed to create temporary file: %s", error->message);
385*854ee02bSLaurent Vivier         return -1;
386*854ee02bSLaurent Vivier     }
387*854ee02bSLaurent Vivier     close(pidfd);
388*854ee02bSLaurent Vivier 
389*854ee02bSLaurent Vivier     args = net_passt_decode_args(&netdev->u.passt, pidfile, errp);
390*854ee02bSLaurent Vivier     if (args == NULL) {
391*854ee02bSLaurent Vivier         g_free(pidfile);
392*854ee02bSLaurent Vivier         return -1;
393*854ee02bSLaurent Vivier     }
394*854ee02bSLaurent Vivier 
395*854ee02bSLaurent Vivier     nc = qemu_new_net_client(&net_passt_info, peer, "passt", name);
396*854ee02bSLaurent Vivier     s = DO_UPCAST(NetPasstState, data.nc, nc);
397*854ee02bSLaurent Vivier 
398*854ee02bSLaurent Vivier     s->args = args;
399*854ee02bSLaurent Vivier     s->pidfile = pidfile;
400*854ee02bSLaurent Vivier 
401*854ee02bSLaurent Vivier     if (net_passt_stream_start(s, errp) == -1) {
402*854ee02bSLaurent Vivier         qemu_del_net_client(nc);
403*854ee02bSLaurent Vivier         return -1;
404*854ee02bSLaurent Vivier     }
405*854ee02bSLaurent Vivier 
406*854ee02bSLaurent Vivier     return 0;
407*854ee02bSLaurent Vivier }
408