@samitouri / QOSamiQemu / commits / d7a6ada379

net: introduce net_parse_fds()

Add common net_parse_fds() and net_free_fds() helpers and use them in tap.c and af-xdp.c. Choose returning queues instead of fds, because we'll have derived helper in net/tap, which will be able to return fds=NULL and non-zero queues on success. That's also why we move to INT_MAX for queues, to support negative return value for net_parse_fds() (for failure paths). Note that redundant restriction of MAX_TAP_QUEUES is dropped for tap.c Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Reviewed-by: Ben Chaney <bchaney@akamai.com> Signed-off-by: Jason Wang <jasowang@redhat.com>

Vladimir Sementsov-Ogievskiy committed Mar 18, 2026 at 14:31 UTC d7a6ada3792433f02716fa31f1e4f6596dae6727
4 files changed +85 -104
net/af-xdp.c
+2 -31
@@ -21,6 +21,7 @@
21 #include "clients.h"
22 #include "monitor/monitor.h"
23 #include "net/net.h"
24 +#include "net/util.h"
25 #include "qapi/error.h"
26 #include "qemu/cutils.h"
27 #include "qemu/error-report.h"
@@ -441,35 +442,6 @@ static NetClientInfo net_af_xdp_info = {
442 .cleanup = af_xdp_cleanup,
443 };
444
444 -static int *parse_socket_fds(const char *sock_fds_str,
445 - int n_expected, Error **errp)
446 -{
447 - gchar **substrings = g_strsplit(sock_fds_str, ":", -1);
448 - int i, n_sock_fds = g_strv_length(substrings);
449 - int *sock_fds = NULL;
450 -
451 - if (n_sock_fds != n_expected) {
452 - error_setg(errp, "expected %d socket fds, got %d",
453 - n_expected, n_sock_fds);
454 - goto exit;
455 - }
456 -
457 - sock_fds = g_new(int, n_sock_fds);
458 -
459 - for (i = 0; i < n_sock_fds; i++) {
460 - sock_fds[i] = monitor_fd_param(monitor_cur(), substrings[i], errp);
461 - if (sock_fds[i] < 0) {
462 - g_free(sock_fds);
463 - sock_fds = NULL;
464 - goto exit;
465 - }
466 - }
467 -
468 -exit:
469 - g_strfreev(substrings);
470 - return sock_fds;
471 -}
472 -
445 /*
446 * The exported init function.
447 *
@@ -530,8 +502,7 @@ int net_init_af_xdp(const Netdev *netdev,
502 }
503
504 if (opts->sock_fds) {
533 - sock_fds = parse_socket_fds(opts->sock_fds, queues, errp);
534 - if (!sock_fds) {
505 + if (net_parse_fds(opts->sock_fds, &sock_fds, queues, errp) < 0) {
506 return -1;
507 }
508 }
net/tap.c
+19 -73
@@ -45,6 +45,7 @@
45 #include "hw/virtio/vhost.h"
46
47 #include "net/tap.h"
48 +#include "net/util.h"
49
50 #include "net/vhost_net.h"
51
@@ -701,8 +702,6 @@ static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr,
702 return fd;
703 }
704
704 -#define MAX_TAP_QUEUES 1024
705 -
705 static bool net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
706 const char *name,
707 const char *ifname, const char *script,
@@ -782,32 +781,6 @@ failed:
781 return false;
782 }
783
785 -static int get_fds(char *str, char *fds[], int max)
786 -{
787 - char *ptr = str, *this;
788 - size_t len = strlen(str);
789 - int i = 0;
790 -
791 - while (i < max && ptr < str + len) {
792 - this = strchr(ptr, ':');
793 -
794 - if (this == NULL) {
795 - fds[i] = g_strdup(ptr);
796 - } else {
797 - fds[i] = g_strndup(ptr, this - ptr);
798 - }
799 -
800 - i++;
801 - if (this == NULL) {
802 - break;
803 - } else {
804 - ptr = this + 1;
805 - }
806 - }
807 -
808 - return i;
809 -}
810 -
784 int net_init_tap(const Netdev *netdev, const char *name,
785 NetClientState *peer, Error **errp)
786 {
@@ -815,9 +788,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
788 int fd = -1, vhostfd = -1, vnet_hdr = 0, i = 0, queues;
789 /* for the no-fd, no-helper case */
790 char ifname[128];
818 - char **fds = NULL, **vhost_fds = NULL;
819 - int nfds = 0, nvhosts = 0;
820 -
791 + int *fds = NULL, *vhost_fds = NULL;
792
793 assert(netdev->type == NET_CLIENT_DRIVER_TAP);
794 tap = &netdev->u.tap;
@@ -890,46 +861,31 @@ int net_init_tap(const Netdev *netdev, const char *name,
861 goto fail;
862 }
863 } else if (tap->fds) {
893 - fds = g_new0(char *, MAX_TAP_QUEUES);
894 - vhost_fds = g_new0(char *, MAX_TAP_QUEUES);
895 -
896 - nfds = get_fds(tap->fds, fds, MAX_TAP_QUEUES);
897 - if (tap->vhostfds) {
898 - nvhosts = get_fds(tap->vhostfds, vhost_fds, MAX_TAP_QUEUES);
899 - if (nfds != nvhosts) {
900 - error_setg(errp, "The number of fds passed does not match "
901 - "the number of vhostfds passed");
902 - goto fail;
903 - }
864 + queues = net_parse_fds(tap->fds, &fds, 0, errp);
865 + if (queues < 0) {
866 + goto fail;
867 }
868
906 - for (i = 0; i < nfds; i++) {
907 - fd = monitor_fd_param(monitor_cur(), fds[i], errp);
908 - if (fd == -1) {
909 - goto fail;
910 - }
869 + if (tap->vhostfds && net_parse_fds(tap->vhostfds, &vhost_fds,
870 + queues, errp) < 0) {
871 + goto fail;
872 + }
873
912 - if (!qemu_set_blocking(fd, false, errp)) {
874 + for (i = 0; i < queues; i++) {
875 + if (!qemu_set_blocking(fds[i], false, errp)) {
876 goto fail;
877 }
878
916 - if (tap->vhostfds) {
917 - vhostfd = monitor_fd_param(monitor_cur(), vhost_fds[i], errp);
918 - if (vhostfd == -1) {
919 - goto fail;
920 - }
921 -
922 - if (!qemu_set_blocking(vhostfd, false, errp)) {
923 - goto fail;
924 - }
879 + if (vhost_fds && !qemu_set_blocking(vhost_fds[i], false, errp)) {
880 + goto fail;
881 }
882
883 if (i == 0) {
928 - vnet_hdr = tap_probe_vnet_hdr(fd, errp);
884 + vnet_hdr = tap_probe_vnet_hdr(fds[i], errp);
885 if (vnet_hdr < 0) {
886 goto fail;
887 }
932 - } else if (vnet_hdr != tap_probe_vnet_hdr(fd, NULL)) {
888 + } else if (vnet_hdr != tap_probe_vnet_hdr(fds[i], NULL)) {
889 error_setg(errp,
890 "vnet_hdr not consistent across given tap fds");
891 goto fail;
@@ -937,8 +893,8 @@ int net_init_tap(const Netdev *netdev, const char *name,
893
894 if (!net_init_tap_one(tap, peer, name, ifname,
895 NULL, NULL,
940 - vhostfd,
941 - vnet_hdr, fd, errp)) {
896 + vhost_fds ? vhost_fds[i] : -1,
897 + vnet_hdr, fds[i], errp)) {
898 goto fail;
899 }
900 }
@@ -1003,18 +959,8 @@ int net_init_tap(const Netdev *netdev, const char *name,
959 fail:
960 close(fd);
961 close(vhostfd);
1006 - if (vhost_fds) {
1007 - for (i = 0; i < nvhosts; i++) {
1008 - g_free(vhost_fds[i]);
1009 - }
1010 - g_free(vhost_fds);
1011 - }
1012 - if (fds) {
1013 - for (i = 0; i < nfds; i++) {
1014 - g_free(fds[i]);
1015 - }
1016 - g_free(fds);
1017 - }
962 + net_free_fds(fds, queues);
963 + net_free_fds(vhost_fds, queues);
964 return -1;
965 }
966
net/util.c
+50
@@ -23,6 +23,8 @@
23 */
24
25 #include "qemu/osdep.h"
26 +#include "monitor/monitor.h"
27 +#include "qapi/error.h"
28 #include "util.h"
29
30 int net_parse_macaddr(uint8_t *macaddr, const char *p)
@@ -57,3 +59,51 @@ int net_parse_macaddr(uint8_t *macaddr, const char *p)
59
60 return 0;
61 }
62 +
63 +void net_free_fds(int *fds, int nfds)
64 +{
65 + int i;
66 +
67 + if (!fds || nfds <= 0) {
68 + return;
69 + }
70 +
71 + for (i = 0; i < nfds; i++) {
72 + if (fds[i] != -1) {
73 + close(fds[i]);
74 + }
75 + }
76 +
77 + g_free(fds);
78 +}
79 +
80 +int net_parse_fds(const char *fds_param, int **fds, int expected_nfds,
81 + Error **errp)
82 +{
83 + g_auto(GStrv) fdnames = g_strsplit(fds_param, ":", -1);
84 + unsigned nfds = g_strv_length(fdnames);
85 + int i;
86 +
87 + if (nfds > INT_MAX) {
88 + error_setg(errp, "fds parameter exceeds maximum of %d", INT_MAX);
89 + return -1;
90 + }
91 +
92 + if (expected_nfds && nfds != expected_nfds) {
93 + error_setg(errp, "expected %u socket fds, got %u", expected_nfds, nfds);
94 + return -1;
95 + }
96 +
97 + *fds = g_new(int, nfds);
98 +
99 + for (i = 0; i < nfds; i++) {
100 + (*fds)[i] = monitor_fd_param(monitor_cur(), fdnames[i], errp);
101 + if ((*fds)[i] == -1) {
102 + net_free_fds(*fds, i);
103 + *fds = NULL;
104 + return -1;
105 + }
106 + }
107 +
108 + return nfds;
109 +}
net/util.h
+14
@@ -83,4 +83,18 @@ static inline bool in6_equal_net(const struct in6_addr *a,
83
84 int net_parse_macaddr(uint8_t *macaddr, const char *p);
85
86 +/*
87 + * Close all @fds and free @fds itself
88 + */
89 +void net_free_fds(int *fds, int nfds);
90 +
91 +/*
92 + * Parse @fds_param, where monitor fds are separated by a colon.
93 + * @nfds must be non-NULL. If *@nfds is zero - set it accordingly.
94 + * If *@nfds is non-zero - check that we have exactly *@nfds fds
95 + * and fail otherwise.
96 + */
97 +int net_parse_fds(const char *fds_param, int **fds, int expected_nfds,
98 + Error **errp);
99 +
100 #endif /* QEMU_NET_UTIL_H */