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 */