From c8aa237c643e7cb44fe878eeb76399ff8b73821a Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:17 +0200 Subject: net: Don't deliver to disabled interfaces in qemu_sendv_packet Signed-off-by: Jan Kiszka Signed-off-by: Mark McLoughlin --- net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net.c') diff --git a/net.c b/net.c index 2d24a7ce5f..42b6b93247 100644 --- a/net.c +++ b/net.c @@ -494,7 +494,7 @@ ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov, if (vc->link_down) len = calc_iov_length(iov, iovcnt); - if (vc->fd_readv) + else if (vc->fd_readv) len = vc->fd_readv(vc->opaque, iov, iovcnt); else if (vc->fd_read) len = vc_sendv_compat(vc, iov, iovcnt); -- cgit v1.2.1 From c27ff60871aff588a35e51d1a90faed410993e55 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:17 +0200 Subject: net: Fix and improved ordered packet delivery Fix a race in qemu_send_packet when delivering deferred packets and add proper deferring also to qemu_sendv_packet. Signed-off-by: Jan Kiszka Signed-off-by: Mark McLoughlin --- net.c | 57 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 15 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 42b6b93247..6563b424ce 100644 --- a/net.c +++ b/net.c @@ -438,8 +438,8 @@ void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) vlan->delivering = 1; qemu_deliver_packet(vc, buf, size); while ((packet = vlan->send_queue) != NULL) { - qemu_deliver_packet(packet->sender, packet->data, packet->size); vlan->send_queue = packet->next; + qemu_deliver_packet(packet->sender, packet->data, packet->size); qemu_free(packet); } vlan->delivering = 0; @@ -476,30 +476,57 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt) return offset; } -ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov, +ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, int iovcnt) { - VLANState *vlan = vc1->vlan; + VLANState *vlan = sender->vlan; VLANClientState *vc; + VLANPacket *packet; ssize_t max_len = 0; + int i; - if (vc1->link_down) + if (sender->link_down) return calc_iov_length(iov, iovcnt); - for (vc = vlan->first_client; vc != NULL; vc = vc->next) { - ssize_t len = 0; + if (vlan->delivering) { + max_len = calc_iov_length(iov, iovcnt); - if (vc == vc1) - continue; + packet = qemu_malloc(sizeof(VLANPacket) + max_len); + packet->next = vlan->send_queue; + packet->sender = sender; + packet->size = 0; + for (i = 0; i < iovcnt; i++) { + size_t len = iov[i].iov_len; + + memcpy(packet->data + packet->size, iov[i].iov_base, len); + packet->size += len; + } + vlan->send_queue = packet; + } else { + vlan->delivering = 1; + + for (vc = vlan->first_client; vc != NULL; vc = vc->next) { + ssize_t len = 0; - if (vc->link_down) - len = calc_iov_length(iov, iovcnt); - else if (vc->fd_readv) - len = vc->fd_readv(vc->opaque, iov, iovcnt); - else if (vc->fd_read) - len = vc_sendv_compat(vc, iov, iovcnt); + if (vc == sender) { + continue; + } + if (vc->link_down) { + len = calc_iov_length(iov, iovcnt); + } else if (vc->fd_readv) { + len = vc->fd_readv(vc->opaque, iov, iovcnt); + } else if (vc->fd_read) { + len = vc_sendv_compat(vc, iov, iovcnt); + } + max_len = MAX(max_len, len); + } - max_len = MAX(max_len, len); + while ((packet = vlan->send_queue) != NULL) { + vlan->send_queue = packet->next; + qemu_deliver_packet(packet->sender, packet->data, packet->size); + qemu_free(packet); + } + vlan->delivering = 0; } return max_len; -- cgit v1.2.1 From 7c3370d4fe3fa6cda8655f109e4659afc8ca4269 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:17 +0200 Subject: slirp: Avoid zombie processes after fork_exec Slirp uses fork_exec for spawning service processes, and QEMU uses this for running smbd. As SIGCHLD is not handled, these processes become zombies on termination. Fix this by installing a proper signal handler, but also make sure we disable the signal while waiting on forked network setup/shutdown scripts. Signed-off-by: Jan Kiszka Signed-off-by: Mark McLoughlin --- net.c | 60 ++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 26 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 6563b424ce..97e1ac5ccd 100644 --- a/net.c +++ b/net.c @@ -1134,38 +1134,46 @@ static int tap_open(char *ifname, int ifname_size) static int launch_script(const char *setup_script, const char *ifname, int fd) { + sigset_t oldmask, mask; int pid, status; char *args[3]; char **parg; - /* try to launch network script */ - pid = fork(); - if (pid >= 0) { - if (pid == 0) { - int open_max = sysconf (_SC_OPEN_MAX), i; - for (i = 0; i < open_max; i++) - if (i != STDIN_FILENO && - i != STDOUT_FILENO && - i != STDERR_FILENO && - i != fd) - close(i); - - parg = args; - *parg++ = (char *)setup_script; - *parg++ = (char *)ifname; - *parg++ = NULL; - execv(setup_script, args); - _exit(1); - } - while (waitpid(pid, &status, 0) != pid); - if (!WIFEXITED(status) || - WEXITSTATUS(status) != 0) { - fprintf(stderr, "%s: could not launch network script\n", - setup_script); - return -1; + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &mask, &oldmask); + + /* try to launch network script */ + pid = fork(); + if (pid == 0) { + int open_max = sysconf(_SC_OPEN_MAX), i; + + for (i = 0; i < open_max; i++) { + if (i != STDIN_FILENO && + i != STDOUT_FILENO && + i != STDERR_FILENO && + i != fd) { + close(i); } } - return 0; + parg = args; + *parg++ = (char *)setup_script; + *parg++ = (char *)ifname; + *parg++ = NULL; + execv(setup_script, args); + _exit(1); + } else if (pid > 0) { + while (waitpid(pid, &status, 0) != pid) { + /* loop */ + } + sigprocmask(SIG_SETMASK, &oldmask, NULL); + + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + return 0; + } + } + fprintf(stderr, "%s: could not launch network script\n", setup_script); + return -1; } static int net_tap_init(VLANState *vlan, const char *model, -- cgit v1.2.1 From cda94b27821726df74eead0701d8401c1acda6ec Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 28 May 2009 14:07:31 +0100 Subject: Revert "Fix output of uninitialized strings" This reverts commit 8cf07dcbe7691dbe4f47563058659dba6ef66b05. This is a sorry saga. This commit: 8e4416af45 net: Add parameter checks for VLAN clients broken '-net socket' and this commit: ffad4116b9 net: Fix -net socket parameter checks fixed the problem but introduced another problem which this commit: 8cf07dcbe7 Fix output of uninitialized strings fixed that final problem, but causing us to lose some error reporting information in the process. Meanwhile Jan posted a patch to mostly re-do ffad4116b9 in a way that fixes the original issue, but without losing the error reporting information. So, let's revert 8cf07dcbe7 and apply Jan's patch. Signed-off-by: Mark McLoughlin --- net.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 97e1ac5ccd..390d6a66e5 100644 --- a/net.c +++ b/net.c @@ -1912,7 +1912,8 @@ int net_client_init(const char *device, const char *p) int idx = nic_get_free_idx(); if (check_params(nic_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); + fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", + buf, p); return -1; } if (idx == -1 || nb_nics >= MAX_NICS) { @@ -1962,7 +1963,8 @@ int net_client_init(const char *device, const char *p) "vlan", "name", "hostname", "restrict", "ip", NULL }; if (check_params(slirp_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); + fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", + buf, p); return -1; } if (get_param_value(buf, sizeof(buf), "hostname", p)) { @@ -2012,7 +2014,8 @@ int net_client_init(const char *device, const char *p) char ifname[64]; if (check_params(tap_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); + fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", + buf, p); return -1; } if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { @@ -2032,7 +2035,8 @@ int net_client_init(const char *device, const char *p) vlan->nb_host_devs++; if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { if (check_params(fd_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); + fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", + buf, p); return -1; } fd = strtol(buf, NULL, 0); @@ -2044,7 +2048,8 @@ int net_client_init(const char *device, const char *p) "vlan", "name", "ifname", "script", "downscript", NULL }; if (check_params(tap_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); + fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", + buf, p); return -1; } if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { @@ -2064,7 +2069,8 @@ int net_client_init(const char *device, const char *p) if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { int fd; if (check_params(fd_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); + fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", + buf, p); return -1; } fd = strtol(buf, NULL, 0); @@ -2076,7 +2082,8 @@ int net_client_init(const char *device, const char *p) "vlan", "name", "listen", NULL }; if (check_params(listen_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); + fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", + buf, p); return -1; } ret = net_socket_listen_init(vlan, device, name, buf); @@ -2085,7 +2092,8 @@ int net_client_init(const char *device, const char *p) "vlan", "name", "connect", NULL }; if (check_params(connect_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); + fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", + buf, p); return -1; } ret = net_socket_connect_init(vlan, device, name, buf); @@ -2094,7 +2102,8 @@ int net_client_init(const char *device, const char *p) "vlan", "name", "mcast", NULL }; if (check_params(mcast_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); + fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", + buf, p); return -1; } ret = net_socket_mcast_init(vlan, device, name, buf); @@ -2114,7 +2123,8 @@ int net_client_init(const char *device, const char *p) int vde_port, vde_mode; if (check_params(vde_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); + fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", + buf, p); return -1; } vlan->nb_host_devs++; -- cgit v1.2.1 From 0aa7a205c899c516d906673efbe9457f7af0dd3c Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:17 +0200 Subject: net: Real fix for check_params users OK, last try: 8e4416af45 broke -net socket, ffad4116b9 tried to fix it but broke error reporting of invalid parameters. So this patch widely reverts ffad4116b9 again and intead fixes those callers of check_params that originally suffered from overwritten buffers by using separate ones. Signed-off-by: Jan Kiszka Signed-off-by: Mark McLoughlin --- net.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 390d6a66e5..723e934224 100644 --- a/net.c +++ b/net.c @@ -1911,7 +1911,7 @@ int net_client_init(const char *device, const char *p) uint8_t *macaddr; int idx = nic_get_free_idx(); - if (check_params(nic_params, p) < 0) { + if (check_params(buf, sizeof(buf), nic_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -1962,7 +1962,7 @@ int net_client_init(const char *device, const char *p) static const char * const slirp_params[] = { "vlan", "name", "hostname", "restrict", "ip", NULL }; - if (check_params(slirp_params, p) < 0) { + if (check_params(buf, sizeof(buf), slirp_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -2013,7 +2013,7 @@ int net_client_init(const char *device, const char *p) }; char ifname[64]; - if (check_params(tap_params, p) < 0) { + if (check_params(buf, sizeof(buf), tap_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -2029,12 +2029,12 @@ int net_client_init(const char *device, const char *p) #elif defined (_AIX) #else if (!strcmp(device, "tap")) { - char ifname[64]; + char ifname[64], chkbuf[64]; char setup_script[1024], down_script[1024]; int fd; vlan->nb_host_devs++; if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { - if (check_params(fd_params, p) < 0) { + if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -2047,7 +2047,7 @@ int net_client_init(const char *device, const char *p) static const char * const tap_params[] = { "vlan", "name", "ifname", "script", "downscript", NULL }; - if (check_params(tap_params, p) < 0) { + if (check_params(chkbuf, sizeof(chkbuf), tap_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -2066,9 +2066,10 @@ int net_client_init(const char *device, const char *p) } else #endif if (!strcmp(device, "socket")) { + char chkbuf[64]; if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { int fd; - if (check_params(fd_params, p) < 0) { + if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -2081,7 +2082,7 @@ int net_client_init(const char *device, const char *p) static const char * const listen_params[] = { "vlan", "name", "listen", NULL }; - if (check_params(listen_params, p) < 0) { + if (check_params(chkbuf, sizeof(chkbuf), listen_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -2091,7 +2092,7 @@ int net_client_init(const char *device, const char *p) static const char * const connect_params[] = { "vlan", "name", "connect", NULL }; - if (check_params(connect_params, p) < 0) { + if (check_params(chkbuf, sizeof(chkbuf), connect_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -2101,7 +2102,7 @@ int net_client_init(const char *device, const char *p) static const char * const mcast_params[] = { "vlan", "name", "mcast", NULL }; - if (check_params(mcast_params, p) < 0) { + if (check_params(chkbuf, sizeof(chkbuf), mcast_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -2122,7 +2123,7 @@ int net_client_init(const char *device, const char *p) char vde_sock[1024], vde_group[512]; int vde_port, vde_mode; - if (check_params(vde_params, p) < 0) { + if (check_params(buf, sizeof(buf), vde_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; -- cgit v1.2.1 From c8decae2e135d2331268619aa07701c31595b6c9 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 28 May 2009 16:39:54 +0100 Subject: net: fix error reporting for some net parameter checks A small bit of confusion between buffers is causing errors like: qemu: invalid parameter '10' in 'script=/etc/qemu-ifup,fd=10' instead of: qemu: invalid parameter 'script' in 'script=/etc/qemu-ifup,fd=10' Signed-off-by: Mark McLoughlin --- net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 723e934224..2594ed73a9 100644 --- a/net.c +++ b/net.c @@ -2036,7 +2036,7 @@ int net_client_init(const char *device, const char *p) if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - buf, p); + chkbuf, p); return -1; } fd = strtol(buf, NULL, 0); @@ -2049,7 +2049,7 @@ int net_client_init(const char *device, const char *p) }; if (check_params(chkbuf, sizeof(chkbuf), tap_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - buf, p); + chkbuf, p); return -1; } if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { @@ -2071,7 +2071,7 @@ int net_client_init(const char *device, const char *p) int fd; if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - buf, p); + chkbuf, p); return -1; } fd = strtol(buf, NULL, 0); @@ -2084,7 +2084,7 @@ int net_client_init(const char *device, const char *p) }; if (check_params(chkbuf, sizeof(chkbuf), listen_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - buf, p); + chkbuf, p); return -1; } ret = net_socket_listen_init(vlan, device, name, buf); @@ -2094,7 +2094,7 @@ int net_client_init(const char *device, const char *p) }; if (check_params(chkbuf, sizeof(chkbuf), connect_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - buf, p); + chkbuf, p); return -1; } ret = net_socket_connect_init(vlan, device, name, buf); @@ -2104,7 +2104,7 @@ int net_client_init(const char *device, const char *p) }; if (check_params(chkbuf, sizeof(chkbuf), mcast_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - buf, p); + chkbuf, p); return -1; } ret = net_socket_mcast_init(vlan, device, name, buf); -- cgit v1.2.1 From 10ae5a7a98f7c1d901fbb6658324e9c4c4fec8cf Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:18 +0200 Subject: net: Improve parameter error reporting As host network devices can also be instantiated via the monitor, errors should then be reported to the related monitor instead of stderr. This requires larger refactoring, so this patch starts small with introducing a helper to catch both cases and convert net_client_init as well as net_slirp_redir. Signed-off-by: Jan Kiszka Signed-off-by: Mark McLoughlin --- net.c | 131 +++++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 69 insertions(+), 62 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 2594ed73a9..7f7616b00c 100644 --- a/net.c +++ b/net.c @@ -532,6 +532,21 @@ ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, return max_len; } +static void config_error(Monitor *mon, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (mon) { + monitor_vprintf(mon, fmt, ap); + } else { + fprintf(stderr, "qemu: "); + vfprintf(stderr, fmt, ap); + exit(1); + } + va_end(ap); +} + #if defined(CONFIG_SLIRP) /* slirp network adapter */ @@ -674,7 +689,7 @@ void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2 { int is_udp; char buf[256], *r; - const char *p, *errmsg; + const char *p; struct in_addr guest_addr; int host_port, guest_port; @@ -723,20 +738,12 @@ void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2 goto fail_syntax; if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) { - errmsg = "could not set up redirection\n"; - goto fail; + config_error(mon, "could not set up redirection '%s'\n", redir_str); } return; fail_syntax: - errmsg = "invalid redirection format\n"; - fail: - if (mon) { - monitor_printf(mon, "%s", errmsg); - } else { - fprintf(stderr, "qemu: %s", errmsg); - exit(1); - } + config_error(mon, "invalid redirection format '%s'\n", redir_str); } #ifndef _WIN32 @@ -1784,7 +1791,7 @@ static void net_dump_cleanup(VLANClientState *vc) qemu_free(s); } -static int net_dump_init(VLANState *vlan, const char *device, +static int net_dump_init(Monitor *mon, VLANState *vlan, const char *device, const char *name, const char *filename, int len) { struct pcap_file_hdr hdr; @@ -1794,7 +1801,7 @@ static int net_dump_init(VLANState *vlan, const char *device, s->fd = open(filename, O_CREAT | O_WRONLY, 0644); if (s->fd < 0) { - fprintf(stderr, "-net dump: can't open %s\n", filename); + config_error(mon, "-net dump: can't open %s\n", filename); return -1; } @@ -1809,7 +1816,7 @@ static int net_dump_init(VLANState *vlan, const char *device, hdr.linktype = 1; if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) { - perror("-net dump write error"); + config_error(mon, "-net dump write error: %s\n", strerror(errno)); close(s->fd); qemu_free(s); return -1; @@ -1884,7 +1891,7 @@ void qemu_check_nic_model_list(NICInfo *nd, const char * const *models, exit(exit_status); } -int net_client_init(const char *device, const char *p) +int net_client_init(Monitor *mon, const char *device, const char *p) { static const char * const fd_params[] = { "vlan", "name", "fd", NULL @@ -1901,7 +1908,7 @@ int net_client_init(const char *device, const char *p) vlan = qemu_find_vlan(vlan_id); if (get_param_value(buf, sizeof(buf), "name", p)) { - name = strdup(buf); + name = qemu_strdup(buf); } if (!strcmp(device, "nic")) { static const char * const nic_params[] = { @@ -1912,12 +1919,12 @@ int net_client_init(const char *device, const char *p) int idx = nic_get_free_idx(); if (check_params(buf, sizeof(buf), nic_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - buf, p); - return -1; + config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); + ret = -1; + goto out; } if (idx == -1 || nb_nics >= MAX_NICS) { - fprintf(stderr, "Too Many NICs\n"); + config_error(mon, "Too Many NICs\n"); ret = -1; goto out; } @@ -1932,7 +1939,7 @@ int net_client_init(const char *device, const char *p) if (get_param_value(buf, sizeof(buf), "macaddr", p)) { if (parse_macaddr(macaddr, buf) < 0) { - fprintf(stderr, "invalid syntax for ethernet address\n"); + config_error(mon, "invalid syntax for ethernet address\n"); ret = -1; goto out; } @@ -1950,8 +1957,9 @@ int net_client_init(const char *device, const char *p) } else if (!strcmp(device, "none")) { if (*p != '\0') { - fprintf(stderr, "qemu: 'none' takes no parameters\n"); - return -1; + config_error(mon, "'none' takes no parameters\n"); + ret = -1; + goto out; } /* does nothing. It is needed to signal that no network cards are wanted */ @@ -1963,9 +1971,9 @@ int net_client_init(const char *device, const char *p) "vlan", "name", "hostname", "restrict", "ip", NULL }; if (check_params(buf, sizeof(buf), slirp_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - buf, p); - return -1; + config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); + ret = -1; + goto out; } if (get_param_value(buf, sizeof(buf), "hostname", p)) { pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf); @@ -1986,7 +1994,7 @@ int net_client_init(const char *device, const char *p) port = strtol(p, &devname, 10); devname++; if (port < 1 || port > 65535) { - fprintf(stderr, "vmchannel wrong port number\n"); + config_error(mon, "vmchannel wrong port number\n"); ret = -1; goto out; } @@ -1994,8 +2002,8 @@ int net_client_init(const char *device, const char *p) snprintf(name, 20, "vmchannel%ld", port); vmc->hd = qemu_chr_open(name, devname, NULL); if (!vmc->hd) { - fprintf(stderr, "qemu: could not open vmchannel device" - "'%s'\n", devname); + config_error(mon, "could not open vmchannel device '%s'\n", + devname); ret = -1; goto out; } @@ -2014,12 +2022,12 @@ int net_client_init(const char *device, const char *p) char ifname[64]; if (check_params(buf, sizeof(buf), tap_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - buf, p); - return -1; + config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); + ret = -1; + goto out; } if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { - fprintf(stderr, "tap: no interface name\n"); + config_error(mon, "tap: no interface name\n"); ret = -1; goto out; } @@ -2035,9 +2043,9 @@ int net_client_init(const char *device, const char *p) vlan->nb_host_devs++; if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - chkbuf, p); - return -1; + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } fd = strtol(buf, NULL, 0); fcntl(fd, F_SETFL, O_NONBLOCK); @@ -2048,9 +2056,9 @@ int net_client_init(const char *device, const char *p) "vlan", "name", "ifname", "script", "downscript", NULL }; if (check_params(chkbuf, sizeof(chkbuf), tap_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - chkbuf, p); - return -1; + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { ifname[0] = '\0'; @@ -2070,9 +2078,9 @@ int net_client_init(const char *device, const char *p) if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { int fd; if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - chkbuf, p); - return -1; + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } fd = strtol(buf, NULL, 0); ret = -1; @@ -2083,9 +2091,9 @@ int net_client_init(const char *device, const char *p) "vlan", "name", "listen", NULL }; if (check_params(chkbuf, sizeof(chkbuf), listen_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - chkbuf, p); - return -1; + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } ret = net_socket_listen_init(vlan, device, name, buf); } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) { @@ -2093,9 +2101,9 @@ int net_client_init(const char *device, const char *p) "vlan", "name", "connect", NULL }; if (check_params(chkbuf, sizeof(chkbuf), connect_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - chkbuf, p); - return -1; + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } ret = net_socket_connect_init(vlan, device, name, buf); } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) { @@ -2103,13 +2111,13 @@ int net_client_init(const char *device, const char *p) "vlan", "name", "mcast", NULL }; if (check_params(chkbuf, sizeof(chkbuf), mcast_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - chkbuf, p); - return -1; + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } ret = net_socket_mcast_init(vlan, device, name, buf); } else { - fprintf(stderr, "Unknown socket options: %s\n", p); + config_error(mon, "Unknown socket options: %s\n", p); ret = -1; goto out; } @@ -2124,9 +2132,9 @@ int net_client_init(const char *device, const char *p) int vde_port, vde_mode; if (check_params(buf, sizeof(buf), vde_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", - buf, p); - return -1; + config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); + ret = -1; + goto out; } vlan->nb_host_devs++; if (get_param_value(vde_sock, sizeof(vde_sock), "sock", p) <= 0) { @@ -2157,18 +2165,17 @@ int net_client_init(const char *device, const char *p) if (!get_param_value(buf, sizeof(buf), "file", p)) { snprintf(buf, sizeof(buf), "qemu-vlan%d.pcap", vlan_id); } - ret = net_dump_init(vlan, device, name, buf, len); + ret = net_dump_init(mon, vlan, device, name, buf, len); } else { - fprintf(stderr, "Unknown network device: %s\n", device); + config_error(mon, "Unknown network device: %s\n", device); ret = -1; goto out; } if (ret < 0) { - fprintf(stderr, "Could not initialize device '%s'\n", device); + config_error(mon, "Could not initialize device '%s'\n", device); } out: - if (name) - free(name); + qemu_free(name); return ret; } @@ -2206,7 +2213,7 @@ void net_host_device_add(Monitor *mon, const char *device, const char *opts) monitor_printf(mon, "invalid host network device %s\n", device); return; } - if (net_client_init(device, opts ? opts : "") < 0) { + if (net_client_init(mon, device, opts ? opts : "") < 0) { monitor_printf(mon, "adding host network device %s failed\n", device); } } @@ -2252,7 +2259,7 @@ int net_client_parse(const char *str) if (*p == ',') p++; - return net_client_init(device, p); + return net_client_init(NULL, device, p); } void do_info_network(Monitor *mon) -- cgit v1.2.1 From b8e8af38ee4a4d516e75c64d1c3fbcf9a81d00e4 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:18 +0200 Subject: slirp: Reorder initialization This patch reorders the initialization of slirp itself as well as its associated features smb and redirection. So far the first reference to slirp triggered the initialization, independent of the actual -net user option which may carry additional parameters. Now we save any request to add a smb export or some redirections until the actual initialization of the stack. This also allows to move a few parameters that were passed via global variable into the argument list of net_slirp_init. Signed-off-by: Jan Kiszka Signed-off-by: Mark McLoughlin --- net.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 41 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 7f7616b00c..803b3352ad 100644 --- a/net.c +++ b/net.c @@ -551,11 +551,21 @@ static void config_error(Monitor *mon, const char *fmt, ...) /* slirp network adapter */ +struct slirp_config_str { + struct slirp_config_str *next; + const char *str; +}; + static int slirp_inited; -static int slirp_restrict; -static char *slirp_ip; +static struct slirp_config_str *slirp_redirs; +#ifndef _WIN32 +static const char *slirp_smb_export; +#endif static VLANClientState *slirp_vc; +static void slirp_smb(const char *exported_dir); +static void slirp_redirection(Monitor *mon, const char *redir_str); + int slirp_can_output(void) { return !slirp_vc || qemu_can_send_packet(slirp_vc); @@ -593,7 +603,8 @@ static void net_slirp_cleanup(VLANClientState *vc) slirp_in_use = 0; } -static int net_slirp_init(VLANState *vlan, const char *model, const char *name) +static int net_slirp_init(VLANState *vlan, const char *model, const char *name, + int restricted, const char *ip) { if (slirp_in_use) { /* slirp only supports a single instance so far */ @@ -601,10 +612,24 @@ static int net_slirp_init(VLANState *vlan, const char *model, const char *name) } if (!slirp_inited) { slirp_inited = 1; - slirp_init(slirp_restrict, slirp_ip); + slirp_init(restricted, ip); + + while (slirp_redirs) { + struct slirp_config_str *config = slirp_redirs; + + slirp_redirection(NULL, config->str); + slirp_redirs = config->next; + qemu_free(config); + } +#ifndef _WIN32 + if (slirp_smb_export) { + slirp_smb(slirp_smb_export); + } +#endif } - slirp_vc = qemu_new_vlan_client(vlan, model, name, - slirp_receive, NULL, net_slirp_cleanup, NULL); + + slirp_vc = qemu_new_vlan_client(vlan, model, name, slirp_receive, + NULL, net_slirp_cleanup, NULL); slirp_vc->info_str[0] = '\0'; slirp_in_use = 1; return 0; @@ -685,32 +710,18 @@ static void net_slirp_redir_rm(Monitor *mon, const char *port_str) monitor_printf(mon, "invalid format\n"); } -void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2) +static void slirp_redirection(Monitor *mon, const char *redir_str) { - int is_udp; - char buf[256], *r; - const char *p; struct in_addr guest_addr; int host_port, guest_port; - - if (!slirp_inited) { - slirp_inited = 1; - slirp_init(slirp_restrict, slirp_ip); - } - - if (!strcmp(redir_str, "remove")) { - net_slirp_redir_rm(mon, redir_opt2); - return; - } - - if (!strcmp(redir_str, "list")) { - net_slirp_redir_list(mon); - return; - } + const char *p; + char buf[256], *r; + int is_udp; p = redir_str; - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { goto fail_syntax; + } if (!strcmp(buf, "tcp") || buf[0] == '\0') { is_udp = 0; } else if (!strcmp(buf, "udp")) { @@ -719,23 +730,28 @@ void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2 goto fail_syntax; } - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { goto fail_syntax; + } host_port = strtol(buf, &r, 0); - if (r == buf) + if (r == buf) { goto fail_syntax; + } - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { goto fail_syntax; + } if (buf[0] == '\0') { pstrcpy(buf, sizeof(buf), "10.0.2.15"); } - if (!inet_aton(buf, &guest_addr)) + if (!inet_aton(buf, &guest_addr)) { goto fail_syntax; + } guest_port = strtol(p, &r, 0); - if (r == p) + if (r == p) { goto fail_syntax; + } if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) { config_error(mon, "could not set up redirection '%s'\n", redir_str); @@ -746,6 +762,35 @@ void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2 config_error(mon, "invalid redirection format '%s'\n", redir_str); } +void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2) +{ + struct slirp_config_str *config; + + if (!slirp_inited) { + if (mon) { + monitor_printf(mon, "user mode network stack not in use\n"); + } else { + config = qemu_malloc(sizeof(*config)); + config->str = redir_str; + config->next = slirp_redirs; + slirp_redirs = config; + } + return; + } + + if (!strcmp(redir_str, "remove")) { + net_slirp_redir_rm(mon, redir_opt2); + return; + } + + if (!strcmp(redir_str, "list")) { + net_slirp_redir_list(mon); + return; + } + + slirp_redirection(mon, redir_str); +} + #ifndef _WIN32 static char smb_dir[1024]; @@ -781,18 +826,12 @@ static void smb_exit(void) erase_dir(smb_dir); } -/* automatic user mode samba server configuration */ -void net_slirp_smb(const char *exported_dir) +static void slirp_smb(const char *exported_dir) { char smb_conf[1024]; char smb_cmdline[1024]; FILE *f; - if (!slirp_inited) { - slirp_inited = 1; - slirp_init(slirp_restrict, slirp_ip); - } - /* XXX: better tmp dir construction */ snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%ld", (long)getpid()); if (mkdir(smb_dir, 0700) < 0) { @@ -836,7 +875,21 @@ void net_slirp_smb(const char *exported_dir) slirp_add_exec(0, smb_cmdline, 4, 139); } +/* automatic user mode samba server configuration */ +void net_slirp_smb(const char *exported_dir) +{ + if (slirp_smb_export) { + fprintf(stderr, "-smb given twice\n"); + exit(1); + } + slirp_smb_export = exported_dir; + if (slirp_inited) { + slirp_smb(exported_dir); + } +} + #endif /* !defined(_WIN32) */ + void do_info_slirp(Monitor *mon) { slirp_stats(); @@ -1970,6 +2023,9 @@ int net_client_init(Monitor *mon, const char *device, const char *p) static const char * const slirp_params[] = { "vlan", "name", "hostname", "restrict", "ip", NULL }; + int restricted = 0; + char *ip = NULL; + if (check_params(buf, sizeof(buf), slirp_params, p) < 0) { config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); ret = -1; @@ -1979,13 +2035,14 @@ int net_client_init(Monitor *mon, const char *device, const char *p) pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf); } if (get_param_value(buf, sizeof(buf), "restrict", p)) { - slirp_restrict = (buf[0] == 'y') ? 1 : 0; + restricted = (buf[0] == 'y') ? 1 : 0; } if (get_param_value(buf, sizeof(buf), "ip", p)) { - slirp_ip = strdup(buf); + ip = qemu_strdup(buf); } vlan->nb_host_devs++; - ret = net_slirp_init(vlan, device, name); + ret = net_slirp_init(vlan, device, name, restricted, ip); + qemu_free(ip); } else if (!strcmp(device, "channel")) { long port; char name[20], *devname; -- cgit v1.2.1 From 5a6d88157420d7f10b46270edabbeed11ee4ebe5 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 09:43:37 +0100 Subject: net: factor tap_read_packet() out of tap_send() Move portability clutter out into its own function. Signed-off-by: Mark McLoughlin --- net.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 803b3352ad..da18f0f649 100644 --- a/net.c +++ b/net.c @@ -951,21 +951,31 @@ static void tap_receive(void *opaque, const uint8_t *buf, int size) } } -static void tap_send(void *opaque) -{ - TAPState *s = opaque; - uint8_t buf[4096]; - int size; - #ifdef __sun__ +static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) +{ struct strbuf sbuf; int f = 0; - sbuf.maxlen = sizeof(buf); + + sbuf.maxlen = maxlen; sbuf.buf = (char *)buf; - size = getmsg(s->fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1; + + return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1; +} #else - size = read(s->fd, buf, sizeof(buf)); +static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) +{ + return read(tapfd, buf, maxlen); +} #endif + +static void tap_send(void *opaque) +{ + TAPState *s = opaque; + uint8_t buf[4096]; + int size; + + size = tap_read_packet(s->fd, buf, sizeof(buf)); if (size > 0) { qemu_send_packet(s->vc, buf, size); } -- cgit v1.2.1 From 5b01e886d9eb4d5e94384a79634dcb43848e7bbf Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Mon, 18 May 2009 12:05:44 +0100 Subject: net: move the tap buffer into TAPState KVM uses a 64k buffer for reading from tapfd (for GSO support) and allocates the buffer with TAPState rather than on the stack. Not allocating it on the stack probably makes sense for qemu anyway, so merge it in advance of GSO support. Signed-off-by: Mark McLoughlin --- net.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index da18f0f649..443f769a03 100644 --- a/net.c +++ b/net.c @@ -921,6 +921,7 @@ typedef struct TAPState { int fd; char down_script[1024]; char down_script_arg[128]; + uint8_t buf[4096]; } TAPState; static int launch_script(const char *setup_script, const char *ifname, int fd); @@ -972,12 +973,11 @@ static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) static void tap_send(void *opaque) { TAPState *s = opaque; - uint8_t buf[4096]; int size; - size = tap_read_packet(s->fd, buf, sizeof(buf)); + size = tap_read_packet(s->fd, s->buf, sizeof(s->buf)); if (size > 0) { - qemu_send_packet(s->vc, buf, size); + qemu_send_packet(s->vc, s->buf, size); } } -- cgit v1.2.1 From 2e1e06411095ed122d44bf0e3f5e18e8a6304b16 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 09:36:43 +0100 Subject: net: vlan clients with no fd_can_read() can always receive If a vlan client has no fd_can_read(), that means it can always receive packets. The current code assumes it can *never* receive packets. Signed-off-by: Mark McLoughlin --- net.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 443f769a03..0d9e520301 100644 --- a/net.c +++ b/net.c @@ -389,15 +389,19 @@ VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque) return NULL; } -int qemu_can_send_packet(VLANClientState *vc1) +int qemu_can_send_packet(VLANClientState *sender) { - VLANState *vlan = vc1->vlan; + VLANState *vlan = sender->vlan; VLANClientState *vc; - for(vc = vlan->first_client; vc != NULL; vc = vc->next) { - if (vc != vc1) { - if (vc->fd_can_read && vc->fd_can_read(vc->opaque)) - return 1; + for (vc = vlan->first_client; vc != NULL; vc = vc->next) { + if (vc == sender) { + continue; + } + + /* no fd_can_read() handler, they can always receive */ + if (!vc->fd_can_read || vc->fd_can_read(vc->opaque)) { + return 1; } } return 0; -- cgit v1.2.1 From 3471b757d0ca63a0e8188c4c96acd1c279a8c737 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 09:50:32 +0100 Subject: net: only read from tapfd when we can send Reduce the number of packets dropped under heavy network traffic by only reading a packet from the tapfd when a client can actually handle it. Signed-off-by: Mark McLoughlin --- net.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'net.c') diff --git a/net.c b/net.c index 0d9e520301..54ad98f077 100644 --- a/net.c +++ b/net.c @@ -956,6 +956,13 @@ static void tap_receive(void *opaque, const uint8_t *buf, int size) } } +static int tap_can_send(void *opaque) +{ + TAPState *s = opaque; + + return qemu_can_send_packet(s->vc); +} + #ifdef __sun__ static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) { @@ -1011,7 +1018,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan, s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, NULL, tap_cleanup, s); s->vc->fd_readv = tap_receive_iov; - qemu_set_fd_handler(s->fd, tap_send, NULL, s); + qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd); return s; } -- cgit v1.2.1 From 463af5349a787160642f023dad10eaf0cb419fb7 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Mon, 18 May 2009 12:55:27 +0100 Subject: net: add fd_readv() handler to qemu_new_vlan_client() args This, apparently, is the style we prefer - all VLANClientState should be an argument to qemu_new_vlan_client(). Signed-off-by: Mark McLoughlin --- net.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 54ad98f077..cc8cee3f1c 100644 --- a/net.c +++ b/net.c @@ -332,8 +332,9 @@ static char *assign_name(VLANClientState *vc1, const char *model) VLANClientState *qemu_new_vlan_client(VLANState *vlan, const char *model, const char *name, - IOReadHandler *fd_read, IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, + IOReadvHandler *fd_readv, NetCleanup *cleanup, void *opaque) { @@ -344,8 +345,9 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, vc->name = strdup(name); else vc->name = assign_name(vc, model); - vc->fd_read = fd_read; vc->fd_can_read = fd_can_read; + vc->fd_read = fd_read; + vc->fd_readv = fd_readv; vc->cleanup = cleanup; vc->opaque = opaque; vc->vlan = vlan; @@ -632,7 +634,7 @@ static int net_slirp_init(VLANState *vlan, const char *model, const char *name, #endif } - slirp_vc = qemu_new_vlan_client(vlan, model, name, slirp_receive, + slirp_vc = qemu_new_vlan_client(vlan, model, name, NULL, slirp_receive, NULL, net_slirp_cleanup, NULL); slirp_vc->info_str[0] = '\0'; slirp_in_use = 1; @@ -1015,9 +1017,8 @@ static TAPState *net_tap_fd_init(VLANState *vlan, s = qemu_mallocz(sizeof(TAPState)); s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, - NULL, tap_cleanup, s); - s->vc->fd_readv = tap_receive_iov; + s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive, + tap_receive_iov, tap_cleanup, s); qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd); return s; @@ -1351,7 +1352,7 @@ static int net_vde_init(VLANState *vlan, const char *model, free(s); return -1; } - s->vc = qemu_new_vlan_client(vlan, model, name, vde_from_qemu, + s->vc = qemu_new_vlan_client(vlan, model, name, NULL, vde_from_qemu, NULL, vde_cleanup, s); qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d", @@ -1589,7 +1590,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, s = qemu_mallocz(sizeof(NetSocketState)); s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive_dgram, + s->vc = qemu_new_vlan_client(vlan, model, name, NULL, net_socket_receive_dgram, NULL, net_socket_cleanup, s); qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); @@ -1617,7 +1618,7 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, NetSocketState *s; s = qemu_mallocz(sizeof(NetSocketState)); s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive, + s->vc = qemu_new_vlan_client(vlan, model, name, NULL, net_socket_receive, NULL, net_socket_cleanup, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "socket: fd=%d", fd); @@ -1896,7 +1897,7 @@ static int net_dump_init(Monitor *mon, VLANState *vlan, const char *device, return -1; } - s->pcap_vc = qemu_new_vlan_client(vlan, device, name, dump_receive, NULL, + s->pcap_vc = qemu_new_vlan_client(vlan, device, name, NULL, dump_receive, NULL, net_dump_cleanup, s); snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str), "dump to %s (len=%d)", filename, len); -- cgit v1.2.1 From cda9046ba7dbba45f3016e5d60caffa2d72960fa Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Mon, 18 May 2009 13:13:16 +0100 Subject: net: re-name vc->fd_read() to vc->receive() VLANClientState's fd_read() handler doesn't read from file descriptors, it adds a buffer to the client's receive queue. Re-name the handlers to make things a little less confusing. Signed-off-by: Mark McLoughlin --- net.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index cc8cee3f1c..515745d83a 100644 --- a/net.c +++ b/net.c @@ -332,9 +332,9 @@ static char *assign_name(VLANClientState *vc1, const char *model) VLANClientState *qemu_new_vlan_client(VLANState *vlan, const char *model, const char *name, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, - IOReadvHandler *fd_readv, + NetCanReceive *can_receive, + NetReceive *receive, + NetReceiveIOV *receive_iov, NetCleanup *cleanup, void *opaque) { @@ -345,9 +345,9 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, vc->name = strdup(name); else vc->name = assign_name(vc, model); - vc->fd_can_read = fd_can_read; - vc->fd_read = fd_read; - vc->fd_readv = fd_readv; + vc->can_receive = can_receive; + vc->receive = receive; + vc->receive_iov = receive_iov; vc->cleanup = cleanup; vc->opaque = opaque; vc->vlan = vlan; @@ -401,8 +401,8 @@ int qemu_can_send_packet(VLANClientState *sender) continue; } - /* no fd_can_read() handler, they can always receive */ - if (!vc->fd_can_read || vc->fd_can_read(vc->opaque)) { + /* no can_receive() handler, they can always receive */ + if (!vc->can_receive || vc->can_receive(vc->opaque)) { return 1; } } @@ -416,7 +416,7 @@ qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size) for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) { if (vc != sender && !vc->link_down) { - vc->fd_read(vc->opaque, buf, size); + vc->receive(vc->opaque, buf, size); } } } @@ -467,7 +467,7 @@ static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov, offset += len; } - vc->fd_read(vc->opaque, buffer, offset); + vc->receive(vc->opaque, buffer, offset); return offset; } @@ -519,9 +519,9 @@ ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, } if (vc->link_down) { len = calc_iov_length(iov, iovcnt); - } else if (vc->fd_readv) { - len = vc->fd_readv(vc->opaque, iov, iovcnt); - } else if (vc->fd_read) { + } else if (vc->receive_iov) { + len = vc->receive_iov(vc->opaque, iov, iovcnt); + } else if (vc->receive) { len = vc_sendv_compat(vc, iov, iovcnt); } max_len = MAX(max_len, len); @@ -593,7 +593,7 @@ int slirp_is_inited(void) return slirp_inited; } -static void slirp_receive(void *opaque, const uint8_t *buf, int size) +static void slirp_receive(void *opaque, const uint8_t *buf, size_t size) { #ifdef DEBUG_SLIRP printf("slirp input:\n"); @@ -945,7 +945,7 @@ static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, return len; } -static void tap_receive(void *opaque, const uint8_t *buf, int size) +static void tap_receive(void *opaque, const uint8_t *buf, size_t size) { TAPState *s = opaque; int ret; @@ -1380,7 +1380,7 @@ typedef struct NetSocketListenState { } NetSocketListenState; /* XXX: we consider we can send the whole packet without blocking */ -static void net_socket_receive(void *opaque, const uint8_t *buf, int size) +static void net_socket_receive(void *opaque, const uint8_t *buf, size_t size) { NetSocketState *s = opaque; uint32_t len; @@ -1390,7 +1390,7 @@ static void net_socket_receive(void *opaque, const uint8_t *buf, int size) send_all(s->fd, buf, size); } -static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size) +static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, size_t size) { NetSocketState *s = opaque; sendto(s->fd, buf, size, 0, @@ -1831,7 +1831,7 @@ struct pcap_sf_pkthdr { uint32_t len; }; -static void dump_receive(void *opaque, const uint8_t *buf, int size) +static void dump_receive(void *opaque, const uint8_t *buf, size_t size) { DumpState *s = opaque; struct pcap_sf_pkthdr hdr; -- cgit v1.2.1 From e3f5ec2b5e92706e3b807059f79b1fb5d936e567 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Mon, 18 May 2009 13:33:03 +0100 Subject: net: pass VLANClientState* as first arg to receive handlers Give static type checking a chance to catch errors. Signed-off-by: Mark McLoughlin --- net.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 515745d83a..da79d99a12 100644 --- a/net.c +++ b/net.c @@ -402,7 +402,7 @@ int qemu_can_send_packet(VLANClientState *sender) } /* no can_receive() handler, they can always receive */ - if (!vc->can_receive || vc->can_receive(vc->opaque)) { + if (!vc->can_receive || vc->can_receive(vc)) { return 1; } } @@ -416,7 +416,7 @@ qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size) for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) { if (vc != sender && !vc->link_down) { - vc->receive(vc->opaque, buf, size); + vc->receive(vc, buf, size); } } } @@ -467,7 +467,7 @@ static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov, offset += len; } - vc->receive(vc->opaque, buffer, offset); + vc->receive(vc, buffer, offset); return offset; } @@ -520,7 +520,7 @@ ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, if (vc->link_down) { len = calc_iov_length(iov, iovcnt); } else if (vc->receive_iov) { - len = vc->receive_iov(vc->opaque, iov, iovcnt); + len = vc->receive_iov(vc, iov, iovcnt); } else if (vc->receive) { len = vc_sendv_compat(vc, iov, iovcnt); } @@ -593,7 +593,7 @@ int slirp_is_inited(void) return slirp_inited; } -static void slirp_receive(void *opaque, const uint8_t *buf, size_t size) +static void slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { #ifdef DEBUG_SLIRP printf("slirp input:\n"); @@ -932,10 +932,10 @@ typedef struct TAPState { static int launch_script(const char *setup_script, const char *ifname, int fd); -static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, +static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov, int iovcnt) { - TAPState *s = opaque; + TAPState *s = vc->opaque; ssize_t len; do { @@ -945,9 +945,9 @@ static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, return len; } -static void tap_receive(void *opaque, const uint8_t *buf, size_t size) +static void tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - TAPState *s = opaque; + TAPState *s = vc->opaque; int ret; for(;;) { ret = write(s->fd, buf, size); @@ -1311,9 +1311,9 @@ static void vde_to_qemu(void *opaque) } } -static void vde_from_qemu(void *opaque, const uint8_t *buf, int size) +static void vde_receive(VLANClientState *vc, const uint8_t *buf, int size) { - VDEState *s = opaque; + VDEState *s = vc->opaque; int ret; for(;;) { ret = vde_send(s->vde, (const char *)buf, size, 0); @@ -1352,7 +1352,7 @@ static int net_vde_init(VLANState *vlan, const char *model, free(s); return -1; } - s->vc = qemu_new_vlan_client(vlan, model, name, NULL, vde_from_qemu, + s->vc = qemu_new_vlan_client(vlan, model, name, NULL, vde_receive, NULL, vde_cleanup, s); qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d", @@ -1380,9 +1380,9 @@ typedef struct NetSocketListenState { } NetSocketListenState; /* XXX: we consider we can send the whole packet without blocking */ -static void net_socket_receive(void *opaque, const uint8_t *buf, size_t size) +static void net_socket_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - NetSocketState *s = opaque; + NetSocketState *s = vc->opaque; uint32_t len; len = htonl(size); @@ -1390,9 +1390,9 @@ static void net_socket_receive(void *opaque, const uint8_t *buf, size_t size) send_all(s->fd, buf, size); } -static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, size_t size) +static void net_socket_receive_dgram(VLANClientState *vc, const uint8_t *buf, size_t size) { - NetSocketState *s = opaque; + NetSocketState *s = vc->opaque; sendto(s->fd, buf, size, 0, (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); } @@ -1831,9 +1831,9 @@ struct pcap_sf_pkthdr { uint32_t len; }; -static void dump_receive(void *opaque, const uint8_t *buf, size_t size) +static void dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - DumpState *s = opaque; + DumpState *s = vc->opaque; struct pcap_sf_pkthdr hdr; int64_t ts; int caplen; -- cgit v1.2.1 From 4f1c942b7fb29864ad86cb3af9076da38f38f74e Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Mon, 18 May 2009 13:40:55 +0100 Subject: net: add return value to packet receive handler This allows us to handle queue full conditions rather than dropping the packet on the floor. Signed-off-by: Mark McLoughlin --- net.c | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index da79d99a12..8403120750 100644 --- a/net.c +++ b/net.c @@ -593,13 +593,14 @@ int slirp_is_inited(void) return slirp_inited; } -static void slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { #ifdef DEBUG_SLIRP printf("slirp input:\n"); hex_dump(stdout, buf, size); #endif slirp_input(buf, size); + return size; } static int slirp_in_use; @@ -945,17 +946,16 @@ static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov, return len; } -static void tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { TAPState *s = vc->opaque; - int ret; - for(;;) { - ret = write(s->fd, buf, size); - if (ret < 0 && (errno == EINTR || errno == EAGAIN)) { - } else { - break; - } - } + ssize_t len; + + do { + len = write(s->fd, buf, size); + } while (len == -1 && (errno == EINTR || errno == EAGAIN)); + + return len; } static int tap_can_send(void *opaque) @@ -1311,17 +1311,16 @@ static void vde_to_qemu(void *opaque) } } -static void vde_receive(VLANClientState *vc, const uint8_t *buf, int size) +static ssize_t vde_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { VDEState *s = vc->opaque; - int ret; - for(;;) { - ret = vde_send(s->vde, (const char *)buf, size, 0); - if (ret < 0 && errno == EINTR) { - } else { - break; - } - } + ssize ret; + + do { + ret = vde_send(s->vde, (const char *)buf, size, 0); + } while (ret < 0 && errno == EINTR); + + return ret; } static void vde_cleanup(VLANClientState *vc) @@ -1380,21 +1379,22 @@ typedef struct NetSocketListenState { } NetSocketListenState; /* XXX: we consider we can send the whole packet without blocking */ -static void net_socket_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t net_socket_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { NetSocketState *s = vc->opaque; uint32_t len; len = htonl(size); send_all(s->fd, (const uint8_t *)&len, sizeof(len)); - send_all(s->fd, buf, size); + return send_all(s->fd, buf, size); } -static void net_socket_receive_dgram(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t net_socket_receive_dgram(VLANClientState *vc, const uint8_t *buf, size_t size) { NetSocketState *s = vc->opaque; - sendto(s->fd, buf, size, 0, - (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); + + return sendto(s->fd, buf, size, 0, + (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); } static void net_socket_send(void *opaque) @@ -1831,7 +1831,7 @@ struct pcap_sf_pkthdr { uint32_t len; }; -static void dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { DumpState *s = vc->opaque; struct pcap_sf_pkthdr hdr; @@ -1840,7 +1840,7 @@ static void dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size) /* Early return in case of previous error. */ if (s->fd < 0) { - return; + return size; } ts = muldiv64(qemu_get_clock(vm_clock), 1000000, ticks_per_sec); @@ -1856,6 +1856,8 @@ static void dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size) close(s->fd); s->fd = -1; } + + return size; } static void net_dump_cleanup(VLANClientState *vc) -- cgit v1.2.1 From 3e021d40b7548b2eeec62a082411c0745a5c635f Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 11:34:52 +0100 Subject: net: return status from qemu_deliver_packet() Will allow qemu_send_packet() handle queue full condition. Signed-off-by: Mark McLoughlin --- net.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 8403120750..e48b0fe5e7 100644 --- a/net.c +++ b/net.c @@ -409,16 +409,30 @@ int qemu_can_send_packet(VLANClientState *sender) return 0; } -static void +static int qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size) { VLANClientState *vc; + int ret = -1; for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) { - if (vc != sender && !vc->link_down) { - vc->receive(vc, buf, size); + ssize_t len; + + if (vc == sender) { + continue; + } + + if (vc->link_down) { + ret = size; + continue; } + + len = vc->receive(vc, buf, size); + + ret = (ret >= 0) ? ret : len; } + + return ret; } void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) -- cgit v1.2.1 From e94667b91ccfdb70164ae320b1c4ded6b5b8a3ec Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 11:48:12 +0100 Subject: net: split out packet queueing and flushing into separate functions We'll be doing more packet queueing in later commits. Signed-off-by: Mark McLoughlin --- net.c | 155 ++++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 98 insertions(+), 57 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index e48b0fe5e7..94a8e985ea 100644 --- a/net.c +++ b/net.c @@ -415,6 +415,8 @@ qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size) VLANClientState *vc; int ret = -1; + sender->vlan->delivering = 1; + for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) { ssize_t len; @@ -432,13 +434,38 @@ qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size) ret = (ret >= 0) ? ret : len; } + sender->vlan->delivering = 0; + return ret; } +static void qemu_flush_queued_packets(VLANClientState *vc) +{ + VLANPacket *packet; + + while ((packet = vc->vlan->send_queue) != NULL) { + vc->vlan->send_queue = packet->next; + qemu_deliver_packet(packet->sender, packet->data, packet->size); + qemu_free(packet); + } +} + +static void +qemu_enqueue_packet(VLANClientState *sender, const uint8_t *buf, int size) +{ + VLANPacket *packet; + + packet = qemu_malloc(sizeof(VLANPacket) + size); + packet->next = sender->vlan->send_queue; + packet->sender = sender; + packet->size = size; + memcpy(packet->data, buf, size); + sender->vlan->send_queue = packet; +} + void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) { VLANState *vlan = vc->vlan; - VLANPacket *packet; if (vc->link_down) return; @@ -448,22 +475,12 @@ void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) hex_dump(stdout, buf, size); #endif if (vlan->delivering) { - packet = qemu_malloc(sizeof(VLANPacket) + size); - packet->next = vlan->send_queue; - packet->sender = vc; - packet->size = size; - memcpy(packet->data, buf, size); - vlan->send_queue = packet; - } else { - vlan->delivering = 1; - qemu_deliver_packet(vc, buf, size); - while ((packet = vlan->send_queue) != NULL) { - vlan->send_queue = packet->next; - qemu_deliver_packet(packet->sender, packet->data, packet->size); - qemu_free(packet); - } - vlan->delivering = 0; + qemu_enqueue_packet(vc, buf, size); + return; } + + qemu_deliver_packet(vc, buf, size); + qemu_flush_queued_packets(vc); } static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov, @@ -496,60 +513,84 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt) return offset; } -ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, - int iovcnt) +static int qemu_deliver_packet_iov(VLANClientState *sender, + const struct iovec *iov, int iovcnt) { - VLANState *vlan = sender->vlan; VLANClientState *vc; + int ret = -1; + + sender->vlan->delivering = 1; + + for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) { + ssize_t len; + + if (vc == sender) { + continue; + } + + if (vc->link_down) { + ret = calc_iov_length(iov, iovcnt); + continue; + } + + if (vc->receive_iov) { + len = vc->receive_iov(vc, iov, iovcnt); + } else { + len = vc_sendv_compat(vc, iov, iovcnt); + } + + ret = (ret >= 0) ? ret : len; + } + + sender->vlan->delivering = 0; + + return ret; +} + +static ssize_t qemu_enqueue_packet_iov(VLANClientState *sender, + const struct iovec *iov, int iovcnt) +{ VLANPacket *packet; - ssize_t max_len = 0; + size_t max_len = 0; int i; - if (sender->link_down) - return calc_iov_length(iov, iovcnt); + max_len = calc_iov_length(iov, iovcnt); - if (vlan->delivering) { - max_len = calc_iov_length(iov, iovcnt); + packet = qemu_malloc(sizeof(VLANPacket) + max_len); + packet->next = sender->vlan->send_queue; + packet->sender = sender; + packet->size = 0; - packet = qemu_malloc(sizeof(VLANPacket) + max_len); - packet->next = vlan->send_queue; - packet->sender = sender; - packet->size = 0; - for (i = 0; i < iovcnt; i++) { - size_t len = iov[i].iov_len; + for (i = 0; i < iovcnt; i++) { + size_t len = iov[i].iov_len; - memcpy(packet->data + packet->size, iov[i].iov_base, len); - packet->size += len; - } - vlan->send_queue = packet; - } else { - vlan->delivering = 1; + memcpy(packet->data + packet->size, iov[i].iov_base, len); + packet->size += len; + } - for (vc = vlan->first_client; vc != NULL; vc = vc->next) { - ssize_t len = 0; + sender->vlan->send_queue = packet; - if (vc == sender) { - continue; - } - if (vc->link_down) { - len = calc_iov_length(iov, iovcnt); - } else if (vc->receive_iov) { - len = vc->receive_iov(vc, iov, iovcnt); - } else if (vc->receive) { - len = vc_sendv_compat(vc, iov, iovcnt); - } - max_len = MAX(max_len, len); - } + return packet->size; +} - while ((packet = vlan->send_queue) != NULL) { - vlan->send_queue = packet->next; - qemu_deliver_packet(packet->sender, packet->data, packet->size); - qemu_free(packet); - } - vlan->delivering = 0; +ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, + int iovcnt) +{ + int ret; + + if (sender->link_down) { + return calc_iov_length(iov, iovcnt); + } + + if (sender->vlan->delivering) { + return qemu_enqueue_packet_iov(sender, iov, iovcnt); } - return max_len; + ret = qemu_deliver_packet_iov(sender, iov, iovcnt); + + qemu_flush_queued_packets(sender); + + return ret; } static void config_error(Monitor *mon, const char *fmt, ...) -- cgit v1.2.1 From f3b6c7fcf8fca857b3c3ba0aa5b3a06d7ce0ac37 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 12:15:26 +0100 Subject: net: add qemu_send_packet_async() Add a qemu_send_packet() variant which will queue up the packet if it cannot be sent when all client queues are full. It later invokes the supplied callback when the packet has been sent. If qemu_send_packet_async() returns zero, the caller is expected to not send any more packets until the queued packet has been sent. Packets are queued iff a receive() handler returns zero (indicating queue full) and the caller has provided a sent notification callback (indicating it will stop and start its own queue). We need the packet sending API to support queueing because: - a sending client should process all available packets in one go (e.g. virtio-net emptying its tx ring) - a receiving client may not be able to handle the packet (e.g. -EAGAIN from write() to tapfd) - the sending client could detect this condition in advance (e.g. by select() for writable on tapfd) - that's too much overhead (e.g. a select() call per packet) - therefore the sending client must handle the condition by dropping the packet or queueing it - dropping packets is poor form; we should queue. However, we don't want queueing to be completely transparent. We want the sending client to stop sending packets as soon as a packet is queued. This allows the sending client to be throttled by the receiver. Signed-off-by: Mark McLoughlin --- net.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 21 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index 94a8e985ea..e7f5138343 100644 --- a/net.c +++ b/net.c @@ -439,19 +439,32 @@ qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size) return ret; } -static void qemu_flush_queued_packets(VLANClientState *vc) +void qemu_flush_queued_packets(VLANClientState *vc) { VLANPacket *packet; while ((packet = vc->vlan->send_queue) != NULL) { + int ret; + vc->vlan->send_queue = packet->next; - qemu_deliver_packet(packet->sender, packet->data, packet->size); + + ret = qemu_deliver_packet(packet->sender, packet->data, packet->size); + if (ret == 0 && packet->sent_cb != NULL) { + packet->next = vc->vlan->send_queue; + vc->vlan->send_queue = packet; + break; + } + + if (packet->sent_cb) + packet->sent_cb(packet->sender); + qemu_free(packet); } } -static void -qemu_enqueue_packet(VLANClientState *sender, const uint8_t *buf, int size) +static void qemu_enqueue_packet(VLANClientState *sender, + const uint8_t *buf, int size, + NetPacketSent *sent_cb) { VLANPacket *packet; @@ -459,28 +472,45 @@ qemu_enqueue_packet(VLANClientState *sender, const uint8_t *buf, int size) packet->next = sender->vlan->send_queue; packet->sender = sender; packet->size = size; + packet->sent_cb = sent_cb; memcpy(packet->data, buf, size); sender->vlan->send_queue = packet; } -void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) +ssize_t qemu_send_packet_async(VLANClientState *sender, + const uint8_t *buf, int size, + NetPacketSent *sent_cb) { - VLANState *vlan = vc->vlan; + int ret; - if (vc->link_down) - return; + if (sender->link_down) { + return size; + } #ifdef DEBUG_NET - printf("vlan %d send:\n", vlan->id); + printf("vlan %d send:\n", sender->vlan->id); hex_dump(stdout, buf, size); #endif - if (vlan->delivering) { - qemu_enqueue_packet(vc, buf, size); - return; + + if (sender->vlan->delivering) { + qemu_enqueue_packet(sender, buf, size, NULL); + return size; } - qemu_deliver_packet(vc, buf, size); - qemu_flush_queued_packets(vc); + ret = qemu_deliver_packet(sender, buf, size); + if (ret == 0 && sent_cb != NULL) { + qemu_enqueue_packet(sender, buf, size, sent_cb); + return 0; + } + + qemu_flush_queued_packets(sender); + + return ret; +} + +void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) +{ + qemu_send_packet_async(vc, buf, size, NULL); } static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov, @@ -498,9 +528,7 @@ static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov, offset += len; } - vc->receive(vc, buffer, offset); - - return offset; + return vc->receive(vc, buffer, offset); } static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt) @@ -548,7 +576,8 @@ static int qemu_deliver_packet_iov(VLANClientState *sender, } static ssize_t qemu_enqueue_packet_iov(VLANClientState *sender, - const struct iovec *iov, int iovcnt) + const struct iovec *iov, int iovcnt, + NetPacketSent *sent_cb) { VLANPacket *packet; size_t max_len = 0; @@ -559,6 +588,7 @@ static ssize_t qemu_enqueue_packet_iov(VLANClientState *sender, packet = qemu_malloc(sizeof(VLANPacket) + max_len); packet->next = sender->vlan->send_queue; packet->sender = sender; + packet->sent_cb = sent_cb; packet->size = 0; for (i = 0; i < iovcnt; i++) { @@ -573,8 +603,9 @@ static ssize_t qemu_enqueue_packet_iov(VLANClientState *sender, return packet->size; } -ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, - int iovcnt) +ssize_t qemu_sendv_packet_async(VLANClientState *sender, + const struct iovec *iov, int iovcnt, + NetPacketSent *sent_cb) { int ret; @@ -583,16 +614,26 @@ ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, } if (sender->vlan->delivering) { - return qemu_enqueue_packet_iov(sender, iov, iovcnt); + return qemu_enqueue_packet_iov(sender, iov, iovcnt, NULL); } ret = qemu_deliver_packet_iov(sender, iov, iovcnt); + if (ret == 0 && sent_cb != NULL) { + qemu_enqueue_packet_iov(sender, iov, iovcnt, sent_cb); + return 0; + } qemu_flush_queued_packets(sender); return ret; } +ssize_t +qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt) +{ + return qemu_sendv_packet_async(vc, iov, iovcnt, NULL); +} + static void config_error(Monitor *mon, const char *fmt, ...) { va_list ap; -- cgit v1.2.1 From e19eb22486f258a421108ac22b8380a4e2f16b97 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 13:30:24 +0100 Subject: net: make use of async packet sending API in tap client If a packet is queued by qemu_send_packet(), remove I/O handler for the tap fd until we get notification that the packet has been sent. A not insignificant side effect of this is we can now drain the tap send queue in one go without fear of packets being dropped. Signed-off-by: Mark McLoughlin --- net.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'net.c') diff --git a/net.c b/net.c index e7f5138343..4cf27be99c 100644 --- a/net.c +++ b/net.c @@ -1079,15 +1079,31 @@ static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) } #endif +static void tap_send(void *opaque); + +static void tap_send_completed(VLANClientState *vc) +{ + TAPState *s = vc->opaque; + + qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s); +} + static void tap_send(void *opaque) { TAPState *s = opaque; int size; - size = tap_read_packet(s->fd, s->buf, sizeof(s->buf)); - if (size > 0) { - qemu_send_packet(s->vc, s->buf, size); - } + do { + size = tap_read_packet(s->fd, s->buf, sizeof(s->buf)); + if (size <= 0) { + break; + } + + size = qemu_send_packet_async(s->vc, s->buf, size, tap_send_completed); + if (size == 0) { + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + } + } while (size > 0); } static void tap_cleanup(VLANClientState *vc) -- cgit v1.2.1