1 /* 2 * passt network backend 3 * 4 * Copyright Red Hat 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 #include "qemu/osdep.h" 9 #include <glib/gstdio.h> 10 #include "qemu/error-report.h" 11 #include <gio/gio.h> 12 #include "net/net.h" 13 #include "clients.h" 14 #include "qapi/error.h" 15 #include "io/net-listener.h" 16 #include "chardev/char-fe.h" 17 #include "net/vhost_net.h" 18 #include "hw/virtio/vhost.h" 19 #include "hw/virtio/vhost-user.h" 20 #include "standard-headers/linux/virtio_net.h" 21 #include "stream_data.h" 22 23 #ifdef CONFIG_VHOST_USER 24 static const int user_feature_bits[] = { 25 VIRTIO_F_NOTIFY_ON_EMPTY, 26 VIRTIO_F_NOTIFICATION_DATA, 27 VIRTIO_RING_F_INDIRECT_DESC, 28 VIRTIO_RING_F_EVENT_IDX, 29 30 VIRTIO_F_ANY_LAYOUT, 31 VIRTIO_F_VERSION_1, 32 VIRTIO_NET_F_CSUM, 33 VIRTIO_NET_F_GUEST_CSUM, 34 VIRTIO_NET_F_GSO, 35 VIRTIO_NET_F_GUEST_TSO4, 36 VIRTIO_NET_F_GUEST_TSO6, 37 VIRTIO_NET_F_GUEST_ECN, 38 VIRTIO_NET_F_GUEST_UFO, 39 VIRTIO_NET_F_HOST_TSO4, 40 VIRTIO_NET_F_HOST_TSO6, 41 VIRTIO_NET_F_HOST_ECN, 42 VIRTIO_NET_F_HOST_UFO, 43 VIRTIO_NET_F_MRG_RXBUF, 44 VIRTIO_NET_F_MTU, 45 VIRTIO_F_IOMMU_PLATFORM, 46 VIRTIO_F_RING_PACKED, 47 VIRTIO_F_RING_RESET, 48 VIRTIO_F_IN_ORDER, 49 VIRTIO_NET_F_RSS, 50 VIRTIO_NET_F_RSC_EXT, 51 VIRTIO_NET_F_HASH_REPORT, 52 VIRTIO_NET_F_GUEST_USO4, 53 VIRTIO_NET_F_GUEST_USO6, 54 VIRTIO_NET_F_HOST_USO, 55 56 /* This bit implies RARP isn't sent by QEMU out of band */ 57 VIRTIO_NET_F_GUEST_ANNOUNCE, 58 59 VIRTIO_NET_F_MQ, 60 61 VHOST_INVALID_FEATURE_BIT 62 }; 63 #endif 64 65 typedef struct NetPasstState { 66 NetStreamData data; 67 GPtrArray *args; 68 gchar *pidfile; 69 pid_t pid; 70 #ifdef CONFIG_VHOST_USER 71 /* vhost user */ 72 VhostUserState *vhost_user; 73 VHostNetState *vhost_net; 74 CharBackend vhost_chr; 75 guint vhost_watch; 76 uint64_t acked_features; 77 bool started; 78 #endif 79 } NetPasstState; 80 81 static int net_passt_stream_start(NetPasstState *s, Error **errp); 82 83 static void net_passt_cleanup(NetClientState *nc) 84 { 85 NetPasstState *s = DO_UPCAST(NetPasstState, data.nc, nc); 86 87 #ifdef CONFIG_VHOST_USER 88 if (s->vhost_net) { 89 vhost_net_cleanup(s->vhost_net); 90 g_free(s->vhost_net); 91 s->vhost_net = NULL; 92 } 93 if (s->vhost_watch) { 94 g_source_remove(s->vhost_watch); 95 s->vhost_watch = 0; 96 } 97 qemu_chr_fe_deinit(&s->vhost_chr, true); 98 if (s->vhost_user) { 99 vhost_user_cleanup(s->vhost_user); 100 g_free(s->vhost_user); 101 s->vhost_user = NULL; 102 } 103 #endif 104 105 kill(s->pid, SIGTERM); 106 g_remove(s->pidfile); 107 g_free(s->pidfile); 108 g_ptr_array_free(s->args, TRUE); 109 } 110 111 static ssize_t net_passt_receive(NetClientState *nc, const uint8_t *buf, 112 size_t size) 113 { 114 NetStreamData *d = DO_UPCAST(NetStreamData, nc, nc); 115 116 return net_stream_data_receive(d, buf, size); 117 } 118 119 static gboolean net_passt_send(QIOChannel *ioc, GIOCondition condition, 120 gpointer data) 121 { 122 if (net_stream_data_send(ioc, condition, data) == G_SOURCE_REMOVE) { 123 NetPasstState *s = DO_UPCAST(NetPasstState, data, data); 124 Error *error; 125 126 /* we need to restart passt */ 127 kill(s->pid, SIGTERM); 128 if (net_passt_stream_start(s, &error) == -1) { 129 error_report_err(error); 130 } 131 132 return G_SOURCE_REMOVE; 133 } 134 135 return G_SOURCE_CONTINUE; 136 } 137 138 #ifdef CONFIG_VHOST_USER 139 static int passt_set_vnet_endianness(NetClientState *nc, bool enable) 140 { 141 assert(nc->info->type == NET_CLIENT_DRIVER_PASST); 142 143 return 0; 144 } 145 146 static bool passt_has_vnet_hdr(NetClientState *nc) 147 { 148 NetPasstState *s = DO_UPCAST(NetPasstState, data.nc, nc); 149 150 assert(nc->info->type == NET_CLIENT_DRIVER_PASST); 151 152 return s->vhost_user != NULL; 153 } 154 155 static bool passt_has_ufo(NetClientState *nc) 156 { 157 NetPasstState *s = DO_UPCAST(NetPasstState, data.nc, nc); 158 159 assert(nc->info->type == NET_CLIENT_DRIVER_PASST); 160 161 return s->vhost_user != NULL; 162 } 163 164 static bool passt_check_peer_type(NetClientState *nc, ObjectClass *oc, 165 Error **errp) 166 { 167 NetPasstState *s = DO_UPCAST(NetPasstState, data.nc, nc); 168 const char *driver = object_class_get_name(oc); 169 170 assert(nc->info->type == NET_CLIENT_DRIVER_PASST); 171 172 if (s->vhost_user == NULL) { 173 return true; 174 } 175 176 if (!g_str_has_prefix(driver, "virtio-net-")) { 177 error_setg(errp, "vhost-user requires frontend driver virtio-net-*"); 178 return false; 179 } 180 181 return true; 182 } 183 184 static struct vhost_net *passt_get_vhost_net(NetClientState *nc) 185 { 186 NetPasstState *s = DO_UPCAST(NetPasstState, data.nc, nc); 187 188 assert(nc->info->type == NET_CLIENT_DRIVER_PASST); 189 190 return s->vhost_net; 191 } 192 193 static uint64_t passt_get_acked_features(NetClientState *nc) 194 { 195 NetPasstState *s = DO_UPCAST(NetPasstState, data.nc, nc); 196 197 assert(nc->info->type == NET_CLIENT_DRIVER_PASST); 198 199 return s->acked_features; 200 } 201 202 static void passt_save_acked_features(NetClientState *nc) 203 { 204 NetPasstState *s = DO_UPCAST(NetPasstState, data.nc, nc); 205 206 assert(nc->info->type == NET_CLIENT_DRIVER_PASST); 207 208 if (s->vhost_net) { 209 uint64_t features = vhost_net_get_acked_features(s->vhost_net); 210 if (features) { 211 s->acked_features = features; 212 } 213 } 214 } 215 #endif 216 217 static NetClientInfo net_passt_info = { 218 .type = NET_CLIENT_DRIVER_PASST, 219 .size = sizeof(NetPasstState), 220 .receive = net_passt_receive, 221 .cleanup = net_passt_cleanup, 222 #ifdef CONFIG_VHOST_USER 223 .has_vnet_hdr = passt_has_vnet_hdr, 224 .has_ufo = passt_has_ufo, 225 .set_vnet_be = passt_set_vnet_endianness, 226 .set_vnet_le = passt_set_vnet_endianness, 227 .check_peer_type = passt_check_peer_type, 228 .get_vhost_net = passt_get_vhost_net, 229 #endif 230 }; 231 232 static void net_passt_client_connected(QIOTask *task, gpointer opaque) 233 { 234 NetPasstState *s = opaque; 235 236 if (net_stream_data_client_connected(task, &s->data) == 0) { 237 qemu_set_info_str(&s->data.nc, "stream,connected to pid %d", s->pid); 238 } 239 } 240 241 static int net_passt_start_daemon(NetPasstState *s, int sock, Error **errp) 242 { 243 g_autoptr(GSubprocess) daemon = NULL; 244 g_autofree gchar *contents = NULL; 245 g_autoptr(GError) error = NULL; 246 GSubprocessLauncher *launcher; 247 248 qemu_set_info_str(&s->data.nc, "launching passt"); 249 250 launcher = g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_NONE); 251 g_subprocess_launcher_take_fd(launcher, sock, 3); 252 253 daemon = g_subprocess_launcher_spawnv(launcher, 254 (const gchar *const *)s->args->pdata, 255 &error); 256 g_object_unref(launcher); 257 258 if (!daemon) { 259 error_setg(errp, "Error creating daemon: %s", error->message); 260 return -1; 261 } 262 263 if (!g_subprocess_wait(daemon, NULL, &error)) { 264 error_setg(errp, "Error waiting for daemon: %s", error->message); 265 return -1; 266 } 267 268 if (g_subprocess_get_if_exited(daemon) && 269 g_subprocess_get_exit_status(daemon)) { 270 return -1; 271 } 272 273 if (!g_file_get_contents(s->pidfile, &contents, NULL, &error)) { 274 error_setg(errp, "Cannot read passt pid: %s", error->message); 275 return -1; 276 } 277 278 s->pid = (pid_t)g_ascii_strtoll(contents, NULL, 10); 279 if (s->pid <= 0) { 280 error_setg(errp, "File '%s' did not contain a valid PID.", s->pidfile); 281 return -1; 282 } 283 284 return 0; 285 } 286 287 static int net_passt_stream_start(NetPasstState *s, Error **errp) 288 { 289 QIOChannelSocket *sioc; 290 SocketAddress *addr; 291 int sv[2]; 292 293 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { 294 error_setg_errno(errp, errno, "socketpair() failed"); 295 return -1; 296 } 297 298 /* connect to passt */ 299 qemu_set_info_str(&s->data.nc, "connecting to passt"); 300 301 /* create socket channel */ 302 sioc = qio_channel_socket_new(); 303 s->data.ioc = QIO_CHANNEL(sioc); 304 s->data.nc.link_down = true; 305 s->data.send = net_passt_send; 306 307 addr = g_new0(SocketAddress, 1); 308 addr->type = SOCKET_ADDRESS_TYPE_FD; 309 addr->u.fd.str = g_strdup_printf("%d", sv[0]); 310 311 qio_channel_socket_connect_async(sioc, addr, 312 net_passt_client_connected, s, 313 NULL, NULL); 314 315 qapi_free_SocketAddress(addr); 316 317 /* start passt */ 318 if (net_passt_start_daemon(s, sv[1], errp) == -1) { 319 close(sv[0]); 320 close(sv[1]); 321 return -1; 322 } 323 close(sv[1]); 324 325 return 0; 326 } 327 328 #ifdef CONFIG_VHOST_USER 329 static gboolean passt_vhost_user_watch(void *do_not_use, GIOCondition cond, 330 void *opaque) 331 { 332 NetPasstState *s = opaque; 333 334 qemu_chr_fe_disconnect(&s->vhost_chr); 335 336 return G_SOURCE_CONTINUE; 337 } 338 339 static void passt_vhost_user_event(void *opaque, QEMUChrEvent event); 340 341 static void chr_closed_bh(void *opaque) 342 { 343 NetPasstState *s = opaque; 344 345 passt_save_acked_features(&s->data.nc); 346 347 net_client_set_link(&(NetClientState *){ &s->data.nc }, 1, false); 348 349 qemu_chr_fe_set_handlers(&s->vhost_chr, NULL, NULL, passt_vhost_user_event, 350 NULL, s, NULL, true); 351 } 352 353 static void passt_vhost_user_stop(NetPasstState *s) 354 { 355 passt_save_acked_features(&s->data.nc); 356 vhost_net_cleanup(s->vhost_net); 357 } 358 359 static int passt_vhost_user_start(NetPasstState *s, VhostUserState *be) 360 { 361 struct vhost_net *net = NULL; 362 VhostNetOptions options; 363 364 options.backend_type = VHOST_BACKEND_TYPE_USER; 365 options.net_backend = &s->data.nc; 366 options.opaque = be; 367 options.busyloop_timeout = 0; 368 options.nvqs = 2; 369 options.feature_bits = user_feature_bits; 370 options.max_tx_queue_size = VIRTQUEUE_MAX_SIZE; 371 options.get_acked_features = passt_get_acked_features; 372 options.save_acked_features = passt_save_acked_features; 373 options.is_vhost_user = true; 374 375 net = vhost_net_init(&options); 376 if (!net) { 377 error_report("failed to init passt vhost_net"); 378 passt_vhost_user_stop(s); 379 return -1; 380 } 381 382 if (s->vhost_net) { 383 vhost_net_cleanup(s->vhost_net); 384 g_free(s->vhost_net); 385 } 386 s->vhost_net = net; 387 388 return 0; 389 } 390 391 static void passt_vhost_user_event(void *opaque, QEMUChrEvent event) 392 { 393 NetPasstState *s = opaque; 394 395 switch (event) { 396 case CHR_EVENT_OPENED: 397 if (passt_vhost_user_start(s, s->vhost_user) < 0) { 398 qemu_chr_fe_disconnect(&s->vhost_chr); 399 return; 400 } 401 s->vhost_watch = qemu_chr_fe_add_watch(&s->vhost_chr, G_IO_HUP, 402 passt_vhost_user_watch, s); 403 net_client_set_link(&(NetClientState *){ &s->data.nc }, 1, true); 404 s->started = true; 405 break; 406 case CHR_EVENT_CLOSED: 407 if (s->vhost_watch) { 408 AioContext *ctx = qemu_get_current_aio_context(); 409 410 g_source_remove(s->vhost_watch); 411 s->vhost_watch = 0; 412 qemu_chr_fe_set_handlers(&s->vhost_chr, NULL, NULL, NULL, NULL, 413 NULL, NULL, false); 414 415 aio_bh_schedule_oneshot(ctx, chr_closed_bh, s); 416 } 417 break; 418 case CHR_EVENT_BREAK: 419 case CHR_EVENT_MUX_IN: 420 case CHR_EVENT_MUX_OUT: 421 /* Ignore */ 422 break; 423 } 424 } 425 426 static int net_passt_vhost_user_init(NetPasstState *s, Error **errp) 427 { 428 Chardev *chr; 429 int sv[2]; 430 431 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { 432 error_setg_errno(errp, errno, "socketpair() failed"); 433 return -1; 434 } 435 436 /* connect to passt */ 437 qemu_set_info_str(&s->data.nc, "connecting to passt"); 438 439 /* create chardev */ 440 441 chr = CHARDEV(object_new(TYPE_CHARDEV_SOCKET)); 442 if (!chr || qemu_chr_add_client(chr, sv[0]) == -1) { 443 object_unref(OBJECT(chr)); 444 error_setg(errp, "Failed to make socket chardev"); 445 goto err; 446 } 447 448 s->vhost_user = g_new0(struct VhostUserState, 1); 449 if (!qemu_chr_fe_init(&s->vhost_chr, chr, errp) || 450 !vhost_user_init(s->vhost_user, &s->vhost_chr, errp)) { 451 goto err; 452 } 453 454 /* start passt */ 455 if (net_passt_start_daemon(s, sv[1], errp) == -1) { 456 goto err; 457 } 458 459 do { 460 if (qemu_chr_fe_wait_connected(&s->vhost_chr, errp) < 0) { 461 goto err; 462 } 463 464 qemu_chr_fe_set_handlers(&s->vhost_chr, NULL, NULL, 465 passt_vhost_user_event, NULL, s, NULL, 466 true); 467 } while (!s->started); 468 469 qemu_set_info_str(&s->data.nc, "vhost-user,connected to pid %d", s->pid); 470 471 close(sv[1]); 472 return 0; 473 err: 474 close(sv[0]); 475 close(sv[1]); 476 477 return -1; 478 } 479 #else 480 static int net_passt_vhost_user_init(NetPasstState *s, Error **errp) 481 { 482 error_setg(errp, "vhost-user support has not been built"); 483 484 return -1; 485 } 486 #endif 487 488 static GPtrArray *net_passt_decode_args(const NetDevPasstOptions *passt, 489 gchar *pidfile, Error **errp) 490 { 491 GPtrArray *args = g_ptr_array_new_with_free_func(g_free); 492 493 if (passt->path) { 494 g_ptr_array_add(args, g_strdup(passt->path)); 495 } else { 496 g_ptr_array_add(args, g_strdup("passt")); 497 } 498 499 if (passt->has_vhost_user && passt->vhost_user) { 500 g_ptr_array_add(args, g_strdup("--vhost-user")); 501 } 502 503 /* by default, be quiet */ 504 if (!passt->has_quiet || passt->quiet) { 505 g_ptr_array_add(args, g_strdup("--quiet")); 506 } 507 508 if (passt->has_mtu) { 509 g_ptr_array_add(args, g_strdup("--mtu")); 510 g_ptr_array_add(args, g_strdup_printf("%"PRId64, passt->mtu)); 511 } 512 513 if (passt->address) { 514 g_ptr_array_add(args, g_strdup("--address")); 515 g_ptr_array_add(args, g_strdup(passt->address)); 516 } 517 518 if (passt->netmask) { 519 g_ptr_array_add(args, g_strdup("--netmask")); 520 g_ptr_array_add(args, g_strdup(passt->netmask)); 521 } 522 523 if (passt->mac) { 524 g_ptr_array_add(args, g_strdup("--mac-addr")); 525 g_ptr_array_add(args, g_strdup(passt->mac)); 526 } 527 528 if (passt->gateway) { 529 g_ptr_array_add(args, g_strdup("--gateway")); 530 g_ptr_array_add(args, g_strdup(passt->gateway)); 531 } 532 533 if (passt->interface) { 534 g_ptr_array_add(args, g_strdup("--interface")); 535 g_ptr_array_add(args, g_strdup(passt->interface)); 536 } 537 538 if (passt->outbound) { 539 g_ptr_array_add(args, g_strdup("--outbound")); 540 g_ptr_array_add(args, g_strdup(passt->outbound)); 541 } 542 543 if (passt->outbound_if4) { 544 g_ptr_array_add(args, g_strdup("--outbound-if4")); 545 g_ptr_array_add(args, g_strdup(passt->outbound_if4)); 546 } 547 548 if (passt->outbound_if6) { 549 g_ptr_array_add(args, g_strdup("--outbound-if6")); 550 g_ptr_array_add(args, g_strdup(passt->outbound_if6)); 551 } 552 553 if (passt->dns) { 554 g_ptr_array_add(args, g_strdup("--dns")); 555 g_ptr_array_add(args, g_strdup(passt->dns)); 556 } 557 if (passt->fqdn) { 558 g_ptr_array_add(args, g_strdup("--fqdn")); 559 g_ptr_array_add(args, g_strdup(passt->fqdn)); 560 } 561 562 if (passt->has_dhcp_dns && !passt->dhcp_dns) { 563 g_ptr_array_add(args, g_strdup("--no-dhcp-dns")); 564 } 565 566 if (passt->has_dhcp_search && !passt->dhcp_search) { 567 g_ptr_array_add(args, g_strdup("--no-dhcp-search")); 568 } 569 570 if (passt->map_host_loopback) { 571 g_ptr_array_add(args, g_strdup("--map-host-loopback")); 572 g_ptr_array_add(args, g_strdup(passt->map_host_loopback)); 573 } 574 575 if (passt->map_guest_addr) { 576 g_ptr_array_add(args, g_strdup("--map-guest-addr")); 577 g_ptr_array_add(args, g_strdup(passt->map_guest_addr)); 578 } 579 580 if (passt->dns_forward) { 581 g_ptr_array_add(args, g_strdup("--dns-forward")); 582 g_ptr_array_add(args, g_strdup(passt->dns_forward)); 583 } 584 585 if (passt->dns_host) { 586 g_ptr_array_add(args, g_strdup("--dns-host")); 587 g_ptr_array_add(args, g_strdup(passt->dns_host)); 588 } 589 590 if (passt->has_tcp && !passt->tcp) { 591 g_ptr_array_add(args, g_strdup("--no-tcp")); 592 } 593 594 if (passt->has_udp && !passt->udp) { 595 g_ptr_array_add(args, g_strdup("--no-udp")); 596 } 597 598 if (passt->has_icmp && !passt->icmp) { 599 g_ptr_array_add(args, g_strdup("--no-icmp")); 600 } 601 602 if (passt->has_dhcp && !passt->dhcp) { 603 g_ptr_array_add(args, g_strdup("--no-dhcp")); 604 } 605 606 if (passt->has_ndp && !passt->ndp) { 607 g_ptr_array_add(args, g_strdup("--no-ndp")); 608 } 609 if (passt->has_dhcpv6 && !passt->dhcpv6) { 610 g_ptr_array_add(args, g_strdup("--no-dhcpv6")); 611 } 612 613 if (passt->has_ra && !passt->ra) { 614 g_ptr_array_add(args, g_strdup("--no-ra")); 615 } 616 617 if (passt->has_freebind && passt->freebind) { 618 g_ptr_array_add(args, g_strdup("--freebind")); 619 } 620 621 if (passt->has_ipv4 && !passt->ipv4) { 622 g_ptr_array_add(args, g_strdup("--ipv6-only")); 623 } 624 625 if (passt->has_ipv6 && !passt->ipv6) { 626 g_ptr_array_add(args, g_strdup("--ipv4-only")); 627 } 628 629 if (passt->has_search && passt->search) { 630 const StringList *list = passt->search; 631 GString *domains = g_string_new(list->value->str); 632 633 list = list->next; 634 while (list) { 635 g_string_append(domains, " "); 636 g_string_append(domains, list->value->str); 637 list = list->next; 638 } 639 640 g_ptr_array_add(args, g_strdup("--search")); 641 g_ptr_array_add(args, g_string_free(domains, FALSE)); 642 } 643 644 if (passt->has_tcp_ports && passt->tcp_ports) { 645 const StringList *list = passt->tcp_ports; 646 GString *tcp_ports = g_string_new(list->value->str); 647 648 list = list->next; 649 while (list) { 650 g_string_append(tcp_ports, ","); 651 g_string_append(tcp_ports, list->value->str); 652 list = list->next; 653 } 654 655 g_ptr_array_add(args, g_strdup("--tcp-ports")); 656 g_ptr_array_add(args, g_string_free(tcp_ports, FALSE)); 657 } 658 659 if (passt->has_udp_ports && passt->udp_ports) { 660 const StringList *list = passt->udp_ports; 661 GString *udp_ports = g_string_new(list->value->str); 662 663 list = list->next; 664 while (list) { 665 g_string_append(udp_ports, ","); 666 g_string_append(udp_ports, list->value->str); 667 list = list->next; 668 } 669 670 g_ptr_array_add(args, g_strdup("--udp-ports")); 671 g_ptr_array_add(args, g_string_free(udp_ports, FALSE)); 672 } 673 674 if (passt->has_param && passt->param) { 675 const StringList *list = passt->param; 676 677 while (list) { 678 g_ptr_array_add(args, g_strdup(list->value->str)); 679 list = list->next; 680 } 681 } 682 683 /* provide a pid file to be able to kil passt on exit */ 684 g_ptr_array_add(args, g_strdup("--pid")); 685 g_ptr_array_add(args, g_strdup(pidfile)); 686 687 /* g_subprocess_launcher_take_fd() will set the socket on fd 3 */ 688 g_ptr_array_add(args, g_strdup("--fd")); 689 g_ptr_array_add(args, g_strdup("3")); 690 691 g_ptr_array_add(args, NULL); 692 693 return args; 694 } 695 696 int net_init_passt(const Netdev *netdev, const char *name, 697 NetClientState *peer, Error **errp) 698 { 699 g_autoptr(GError) error = NULL; 700 NetClientState *nc; 701 NetPasstState *s; 702 GPtrArray *args; 703 gchar *pidfile; 704 int pidfd; 705 706 assert(netdev->type == NET_CLIENT_DRIVER_PASST); 707 708 pidfd = g_file_open_tmp("passt-XXXXXX.pid", &pidfile, &error); 709 if (pidfd == -1) { 710 error_setg(errp, "Failed to create temporary file: %s", error->message); 711 return -1; 712 } 713 close(pidfd); 714 715 args = net_passt_decode_args(&netdev->u.passt, pidfile, errp); 716 if (args == NULL) { 717 g_free(pidfile); 718 return -1; 719 } 720 721 nc = qemu_new_net_client(&net_passt_info, peer, "passt", name); 722 s = DO_UPCAST(NetPasstState, data.nc, nc); 723 724 s->args = args; 725 s->pidfile = pidfile; 726 727 if (netdev->u.passt.has_vhost_user && netdev->u.passt.vhost_user) { 728 if (net_passt_vhost_user_init(s, errp) == -1) { 729 qemu_del_net_client(nc); 730 return -1; 731 } 732 733 return 0; 734 } 735 736 if (net_passt_stream_start(s, errp) == -1) { 737 qemu_del_net_client(nc); 738 return -1; 739 } 740 741 return 0; 742 } 743