From c8aa237c643e7cb44fe878eeb76399ff8b73821a Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:17 +0200 Subject: [PATCH 01/28] 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(-) 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); From c27ff60871aff588a35e51d1a90faed410993e55 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:17 +0200 Subject: [PATCH 02/28] 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(-) 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; - 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); + memcpy(packet->data + packet->size, iov[i].iov_base, len); + packet->size += len; + } + vlan->send_queue = packet; + } else { + vlan->delivering = 1; - max_len = MAX(max_len, len); + for (vc = vlan->first_client; vc != NULL; vc = vc->next) { + ssize_t len = 0; + + 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); + } + + 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; From 7c3370d4fe3fa6cda8655f109e4659afc8ca4269 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:17 +0200 Subject: [PATCH 03/28] 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 | 58 +++++++++++++++++++++++++++++++++------------------------- vl.c | 13 +++++++++++-- 2 files changed, 44 insertions(+), 27 deletions(-) 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); + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &mask, &oldmask); - 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; + /* 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, diff --git a/vl.c b/vl.c index fcf853222c..a5f966d4c7 100644 --- a/vl.c +++ b/vl.c @@ -4783,7 +4783,12 @@ static void termsig_handler(int signal) qemu_system_shutdown_request(); } -static void termsig_setup(void) +static void sigchld_handler(int signal) +{ + waitpid(-1, NULL, WNOHANG); +} + +static void sighandler_setup(void) { struct sigaction act; @@ -4792,6 +4797,10 @@ static void termsig_setup(void) sigaction(SIGINT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGTERM, &act, NULL); + + act.sa_handler = sigchld_handler; + act.sa_flags = SA_NOCLDSTOP; + sigaction(SIGCHLD, &act, NULL); } #endif @@ -5918,7 +5927,7 @@ int main(int argc, char **argv, char **envp) #ifndef _WIN32 /* must be after terminal init, SDL library changes signal handlers */ - termsig_setup(); + sighandler_setup(); #endif /* Maintain compatibility with multiple stdio monitors */ From cda94b27821726df74eead0701d8401c1acda6ec Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 28 May 2009 14:07:31 +0100 Subject: [PATCH 04/28] 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 ++++++++++++++++++++---------- vl.c | 3 ++- 2 files changed, 22 insertions(+), 11 deletions(-) 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++; diff --git a/vl.c b/vl.c index a5f966d4c7..ff438d0903 100644 --- a/vl.c +++ b/vl.c @@ -2228,7 +2228,8 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) NULL }; if (check_params(params, str) < 0) { - fprintf(stderr, "qemu: unknown parameter in '%s'\n", str); + fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n", + buf, str); return -1; } From 0aa7a205c899c516d906673efbe9457f7af0dd3c Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:17 +0200 Subject: [PATCH 05/28] 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 ++++++++++++----------- sysemu.h | 3 ++- vl.c | 39 ++++++++++++++------------------------- 3 files changed, 28 insertions(+), 37 deletions(-) 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; diff --git a/sysemu.h b/sysemu.h index 658aeec0b0..e5e5ba0603 100644 --- a/sysemu.h +++ b/sysemu.h @@ -270,7 +270,8 @@ void usb_info(Monitor *mon); int get_param_value(char *buf, int buf_size, const char *tag, const char *str); -int check_params(const char * const *params, const char *str); +int check_params(char *buf, int buf_size, + const char * const *params, const char *str); void register_devices(void); diff --git a/vl.c b/vl.c index ff438d0903..659e9f7bc5 100644 --- a/vl.c +++ b/vl.c @@ -1836,45 +1836,34 @@ int get_param_value(char *buf, int buf_size, return 0; } -int check_params(const char * const *params, const char *str) +int check_params(char *buf, int buf_size, + const char * const *params, const char *str) { - int name_buf_size = 1; const char *p; - char *name_buf; - int i, len; - int ret = 0; - - for (i = 0; params[i] != NULL; i++) { - len = strlen(params[i]) + 1; - if (len > name_buf_size) { - name_buf_size = len; - } - } - name_buf = qemu_malloc(name_buf_size); + int i; p = str; while (*p != '\0') { - p = get_opt_name(name_buf, name_buf_size, p, '='); + p = get_opt_name(buf, buf_size, p, '='); if (*p != '=') { - ret = -1; - break; + return -1; } p++; - for(i = 0; params[i] != NULL; i++) - if (!strcmp(params[i], name_buf)) + for (i = 0; params[i] != NULL; i++) { + if (!strcmp(params[i], buf)) { break; + } + } if (params[i] == NULL) { - ret = -1; - break; + return -1; } p = get_opt_value(NULL, 0, p); - if (*p != ',') + if (*p != ',') { break; + } p++; } - - qemu_free(name_buf); - return ret; + return 0; } /***********************************************************/ @@ -2227,7 +2216,7 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) "cache", "format", "serial", "werror", NULL }; - if (check_params(params, str) < 0) { + if (check_params(buf, sizeof(buf), params, str) < 0) { fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n", buf, str); return -1; From c8decae2e135d2331268619aa07701c31595b6c9 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 28 May 2009 16:39:54 +0100 Subject: [PATCH 06/28] 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(-) 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); From 10ae5a7a98f7c1d901fbb6658324e9c4c4fec8cf Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:18 +0200 Subject: [PATCH 07/28] 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 --- hw/pci-hotplug.c | 7 +-- net.c | 131 +++++++++++++++++++++++++---------------------- net.h | 2 +- vl.c | 2 +- 4 files changed, 75 insertions(+), 67 deletions(-) diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index 4d18ea2fca..abe5bae4ac 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -33,11 +33,12 @@ #include "virtio-blk.h" #if defined(TARGET_I386) || defined(TARGET_X86_64) -static PCIDevice *qemu_pci_hot_add_nic(PCIBus *pci_bus, const char *opts) +static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, PCIBus *pci_bus, + const char *opts) { int ret; - ret = net_client_init("nic", opts); + ret = net_client_init(mon, "nic", opts); if (ret < 0) return NULL; return pci_nic_init(pci_bus, &nd_table[ret], -1, "rtl8139"); @@ -149,7 +150,7 @@ void pci_device_hot_add(Monitor *mon, const char *pci_addr, const char *type, } if (strcmp(type, "nic") == 0) - dev = qemu_pci_hot_add_nic(pci_bus, opts); + dev = qemu_pci_hot_add_nic(mon, pci_bus, opts); else if (strcmp(type, "storage") == 0) dev = qemu_pci_hot_add_storage(mon, pci_bus, opts); else 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) diff --git a/net.h b/net.h index feee021f78..3e602f7299 100644 --- a/net.h +++ b/net.h @@ -108,7 +108,7 @@ uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto, void net_checksum_calculate(uint8_t *data, int length); /* from net.c */ -int net_client_init(const char *device, const char *p); +int net_client_init(Monitor *mon, const char *device, const char *p); void net_client_uninit(NICInfo *nd); int net_client_parse(const char *str); void net_slirp_smb(const char *exported_dir); diff --git a/vl.c b/vl.c index 659e9f7bc5..94027c0d0d 100644 --- a/vl.c +++ b/vl.c @@ -2699,7 +2699,7 @@ static int usb_device_add(const char *devname, int is_hotplug) } else if (strstart(devname, "net:", &p)) { int nic = nb_nics; - if (net_client_init("nic", p) < 0) + if (net_client_init(NULL, "nic", p) < 0) return -1; nd_table[nic].model = "usb"; dev = usb_net_init(&nd_table[nic]); From b8e8af38ee4a4d516e75c64d1c3fbcf9a81d00e4 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:18 +0200 Subject: [PATCH 08/28] 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 | 173 +++++++++++++++++++++++++++++++---------------- slirp/libslirp.h | 2 +- slirp/slirp.c | 2 +- 3 files changed, 117 insertions(+), 60 deletions(-) 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,17 +710,72 @@ 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; + const char *p; + char buf[256], *r; + int is_udp; + + p = redir_str; + 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")) { + is_udp = 1; + } else { + goto fail_syntax; + } + + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } + host_port = strtol(buf, &r, 0); + if (r == buf) { + goto fail_syntax; + } + + 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)) { + goto fail_syntax; + } + + guest_port = strtol(p, &r, 0); + 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); + } + return; + + fail_syntax: + 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) { - slirp_inited = 1; - slirp_init(slirp_restrict, slirp_ip); + 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")) { @@ -708,42 +788,7 @@ void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2 return; } - p = redir_str; - 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")) { - is_udp = 1; - } else { - goto fail_syntax; - } - - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) - goto fail_syntax; - host_port = strtol(buf, &r, 0); - if (r == buf) - goto fail_syntax; - - 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)) - goto fail_syntax; - - guest_port = strtol(p, &r, 0); - 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); - } - return; - - fail_syntax: - config_error(mon, "invalid redirection format '%s'\n", redir_str); + slirp_redirection(mon, redir_str); } #ifndef _WIN32 @@ -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; diff --git a/slirp/libslirp.h b/slirp/libslirp.h index b2313b43c6..d0df24b2af 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -5,7 +5,7 @@ extern "C" { #endif -void slirp_init(int restricted, char *special_ip); +void slirp_init(int restricted, const char *special_ip); void slirp_select_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds); diff --git a/slirp/slirp.c b/slirp/slirp.c index 9cab73124e..30d4ee2d26 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -171,7 +171,7 @@ static void slirp_cleanup(void) static void slirp_state_save(QEMUFile *f, void *opaque); static int slirp_state_load(QEMUFile *f, void *opaque, int version_id); -void slirp_init(int restricted, char *special_ip) +void slirp_init(int restricted, const char *special_ip) { // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); From 5a6d88157420d7f10b46270edabbeed11ee4ebe5 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 09:43:37 +0100 Subject: [PATCH 09/28] 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(-) 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) } } +#ifdef __sun__ +static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) +{ + struct strbuf sbuf; + int f = 0; + + sbuf.maxlen = maxlen; + sbuf.buf = (char *)buf; + + return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1; +} +#else +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; -#ifdef __sun__ - struct strbuf sbuf; - int f = 0; - sbuf.maxlen = sizeof(buf); - sbuf.buf = (char *)buf; - size = getmsg(s->fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1; -#else - size = read(s->fd, buf, sizeof(buf)); -#endif + size = tap_read_packet(s->fd, buf, sizeof(buf)); if (size > 0) { qemu_send_packet(s->vc, buf, size); } From 5b01e886d9eb4d5e94384a79634dcb43848e7bbf Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Mon, 18 May 2009 12:05:44 +0100 Subject: [PATCH 10/28] 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(-) 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); } } From 2e1e06411095ed122d44bf0e3f5e18e8a6304b16 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 09:36:43 +0100 Subject: [PATCH 11/28] 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(-) 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; From 3471b757d0ca63a0e8188c4c96acd1c279a8c737 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 09:50:32 +0100 Subject: [PATCH 12/28] 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(-) 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; } From 463af5349a787160642f023dad10eaf0cb419fb7 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Mon, 18 May 2009 12:55:27 +0100 Subject: [PATCH 13/28] 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 --- hw/dp8393x.c | 4 ++-- hw/e1000.c | 4 ++-- hw/eepro100.c | 2 +- hw/etraxfs_eth.c | 2 +- hw/mcf_fec.c | 2 +- hw/mipsnet.c | 2 +- hw/musicpal.c | 2 +- hw/ne2000.c | 4 ++-- hw/pcnet.c | 2 +- hw/qdev.c | 7 ++++--- hw/rtl8139.c | 2 +- hw/smc91c111.c | 2 +- hw/stellaris_enet.c | 2 +- hw/usb-net.c | 3 ++- hw/virtio-net.c | 2 +- hw/xen_nic.c | 4 ++-- net.c | 21 +++++++++++---------- net.h | 6 ++++-- tap-win32.c | 2 +- 19 files changed, 40 insertions(+), 35 deletions(-) diff --git a/hw/dp8393x.c b/hw/dp8393x.c index 5aa12119cb..9257167b1f 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -888,8 +888,8 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s); s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ - s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - nic_receive, nic_can_receive, nic_cleanup, s); + s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, nic_can_receive, + nic_receive, NULL, nic_cleanup, s); qemu_format_nic_info_str(s->vc, nd->macaddr); qemu_register_reset(nic_reset, 0, s); diff --git a/hw/e1000.c b/hw/e1000.c index 26657922c5..01ee57f031 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1106,8 +1106,8 @@ static void pci_e1000_init(PCIDevice *pci_dev) memset(&d->tx, 0, sizeof d->tx); d->vc = qdev_get_vlan_client(&d->dev.qdev, - e1000_receive, e1000_can_receive, - e1000_cleanup, d); + e1000_can_receive, e1000_receive, + NULL, e1000_cleanup, d); d->vc->link_status_changed = e1000_set_link_status; qemu_format_nic_info_str(d->vc, macaddr); diff --git a/hw/eepro100.c b/hw/eepro100.c index fcb091c9f4..5450b83f36 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1766,7 +1766,7 @@ static void nic_init(PCIDevice *pci_dev, uint32_t device) nic_reset(s); s->vc = qdev_get_vlan_client(&d->dev.qdev, - nic_receive, nic_can_receive, + nic_can_receive, nic_receive, NULL, nic_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 68b8de38eb..bb612840c1 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -593,7 +593,7 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, cpu_register_physical_memory (base, 0x5c, eth->ethregs); eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - eth_receive, eth_can_receive, + eth_can_receive, eth_receive, NULL, eth_cleanup, eth); eth->vc->opaque = eth; eth->vc->link_status_changed = eth_set_link; diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 6c0acc5789..86b3aafa6a 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -462,7 +462,7 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) cpu_register_physical_memory(base, 0x400, s->mmio_index); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - mcf_fec_receive, mcf_fec_can_receive, + mcf_fec_can_receive, mcf_fec_receive, NULL, mcf_fec_cleanup, s); memcpy(s->macaddr, nd->macaddr, 6); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/mipsnet.c b/hw/mipsnet.c index e842984219..82a8c935a1 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -262,7 +262,7 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) s->irq = irq; if (nd && nd->vlan) { s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - mipsnet_receive, mipsnet_can_receive, + mipsnet_can_receive, mipsnet_receive, NULL, mipsnet_cleanup, s); } else { s->vc = NULL; diff --git a/hw/musicpal.c b/hw/musicpal.c index 9389af9589..fcefa6e32e 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -753,7 +753,7 @@ static void mv88w8618_eth_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); s->vc = qdev_get_vlan_client(&dev->qdev, - eth_receive, eth_can_receive, + eth_can_receive, eth_receive, NULL, eth_cleanup, s); s->mmio_index = cpu_register_io_memory(0, mv88w8618_eth_readfn, mv88w8618_eth_writefn, s); diff --git a/hw/ne2000.c b/hw/ne2000.c index 2af0d109b9..aea66b784f 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -757,7 +757,7 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) ne2000_reset(s); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - ne2000_receive, ne2000_can_receive, + ne2000_can_receive, ne2000_receive, NULL, isa_ne2000_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); @@ -821,7 +821,7 @@ static void pci_ne2000_init(PCIDevice *pci_dev) qdev_get_macaddr(&d->dev.qdev, s->macaddr); ne2000_reset(s); s->vc = qdev_get_vlan_client(&d->dev.qdev, - ne2000_receive, ne2000_can_receive, + ne2000_can_receive, ne2000_receive, NULL, ne2000_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/pcnet.c b/hw/pcnet.c index c44ba7edf4..5eba467253 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1952,7 +1952,7 @@ static void pcnet_common_init(DeviceState *dev, PCNetState *s, qdev_get_macaddr(dev, s->macaddr); s->vc = qdev_get_vlan_client(dev, - pcnet_receive, pcnet_can_receive, + pcnet_can_receive, pcnet_receive, NULL, cleanup, s); pcnet_h_reset(s); register_savevm("pcnet", -1, 2, pcnet_save, pcnet_load, s); diff --git a/hw/qdev.c b/hw/qdev.c index 689cf4cf93..90b42532a5 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -258,15 +258,16 @@ void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin) } VLANClientState *qdev_get_vlan_client(DeviceState *dev, - IOReadHandler *fd_read, IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, + IOReadvHandler *fd_readv, NetCleanup *cleanup, void *opaque) { NICInfo *nd = dev->nd; assert(nd); - return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - fd_read, fd_can_read, cleanup, opaque); + return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, fd_can_read, + fd_read, fd_readv, cleanup, opaque); } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index d99f35c130..ab68bda8bf 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3475,7 +3475,7 @@ static void pci_rtl8139_init(PCIDevice *dev) qdev_get_macaddr(&dev->qdev, s->macaddr); rtl8139_reset(s); s->vc = qdev_get_vlan_client(&dev->qdev, - rtl8139_receive, rtl8139_can_receive, + rtl8139_can_receive, rtl8139_receive, NULL, rtl8139_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 38cbd016e9..b20d535ee1 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -711,7 +711,7 @@ static void smc91c111_init1(SysBusDevice *dev) smc91c111_reset(s); s->vc = qdev_get_vlan_client(&dev->qdev, - smc91c111_receive, smc91c111_can_receive, + smc91c111_can_receive, smc91c111_receive, NULL, smc91c111_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); /* ??? Save/restore. */ diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 36fabd3260..8b7df099f0 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -405,8 +405,8 @@ static void stellaris_enet_init(SysBusDevice *dev) qdev_get_macaddr(&dev->qdev, s->macaddr); s->vc = qdev_get_vlan_client(&dev->qdev, - stellaris_enet_receive, stellaris_enet_can_receive, + stellaris_enet_receive, NULL, stellaris_enet_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/usb-net.c b/hw/usb-net.c index 9e6442506f..fda0aa5857 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1458,8 +1458,9 @@ USBDevice *usb_net_init(NICInfo *nd) pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Network Interface"); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - usbnet_receive, usbnet_can_receive, + usbnet_receive, + NULL, usbnet_cleanup, s); qemu_format_nic_info_str(s->vc, s->mac); diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 60aa6dab1b..561330825e 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -606,8 +606,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev) qdev_get_macaddr(dev, n->mac); n->status = VIRTIO_NET_S_LINK_UP; n->vc = qdev_get_vlan_client(dev, - virtio_net_receive, virtio_net_can_receive, + virtio_net_receive, NULL, virtio_net_cleanup, n); n->vc->link_status_changed = virtio_net_set_link_status; diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 4206132aea..350556e990 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -301,8 +301,8 @@ static int net_init(struct XenDevice *xendev) vlan = qemu_find_vlan(netdev->xendev.dev); netdev->vs = qemu_new_vlan_client(vlan, "xen", NULL, - net_rx_packet, net_rx_ok, NULL, - netdev); + net_rx_ok, net_rx_packet, NULL, + NULL, netdev); snprintf(netdev->vs->info_str, sizeof(netdev->vs->info_str), "nic: xenbus vif macaddr=%s", netdev->mac); 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); diff --git a/net.h b/net.h index 3e602f7299..ab445aa2ec 100644 --- a/net.h +++ b/net.h @@ -51,8 +51,9 @@ VLANState *qemu_find_vlan(int id); 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); void qemu_del_vlan_client(VLANClientState *vc); @@ -129,8 +130,9 @@ void net_host_device_remove(Monitor *mon, int vlan_id, const char *device); void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr); VLANClientState *qdev_get_vlan_client(DeviceState *dev, - IOReadHandler *fd_read, IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, + IOReadvHandler *fd_readv, NetCleanup *cleanup, void *opaque); diff --git a/tap-win32.c b/tap-win32.c index 3ff957fe69..008158da16 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -684,7 +684,7 @@ int tap_win32_init(VLANState *vlan, const char *model, return -1; } - s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, + s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive, NULL, tap_cleanup, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), From cda9046ba7dbba45f3016e5d60caffa2d72960fa Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Mon, 18 May 2009 13:13:16 +0100 Subject: [PATCH 14/28] 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 --- hw/dp8393x.c | 4 ++-- hw/e1000.c | 6 +++--- hw/eepro100.c | 2 +- hw/etraxfs_eth.c | 2 +- hw/mcf_fec.c | 2 +- hw/mipsnet.c | 2 +- hw/musicpal.c | 2 +- hw/ne2000.c | 2 +- hw/pcnet.c | 2 +- hw/qdev.c | 10 +++++----- hw/rtl8139.c | 2 +- hw/smc91c111.c | 2 +- hw/stellaris_enet.c | 2 +- hw/usb-net.c | 2 +- hw/virtio-net.c | 2 +- hw/xen_nic.c | 6 +++--- net.c | 36 ++++++++++++++++++------------------ net.h | 23 ++++++++++++----------- savevm.c | 2 +- tap-win32.c | 2 +- 20 files changed, 57 insertions(+), 56 deletions(-) diff --git a/hw/dp8393x.c b/hw/dp8393x.c index 9257167b1f..1b48d9684e 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -409,7 +409,7 @@ static void do_transmit_packets(dp8393xState *s) s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; if (s->vc->fd_can_read(s)) { s->loopback_packet = 1; - s->vc->fd_read(s, s->tx_buffer, tx_len); + s->vc->receive(s, s->tx_buffer, tx_len); } } else { /* Transmit packet */ @@ -725,7 +725,7 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) return -1; } -static void nic_receive(void *opaque, const uint8_t * buf, int size) +static void nic_receive(void *opaque, const uint8_t * buf, size_t size) { uint16_t data[10]; dp8393xState *s = opaque; diff --git a/hw/e1000.c b/hw/e1000.c index 01ee57f031..20544d2943 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -600,7 +600,7 @@ e1000_can_receive(void *opaque) } static void -e1000_receive(void *opaque, const uint8_t *buf, int size) +e1000_receive(void *opaque, const uint8_t *buf, size_t size) { E1000State *s = opaque; struct e1000_rx_desc desc; @@ -614,8 +614,8 @@ e1000_receive(void *opaque, const uint8_t *buf, int size) return; if (size > s->rxbuf_size) { - DBGOUT(RX, "packet too large for buffers (%d > %d)\n", size, - s->rxbuf_size); + DBGOUT(RX, "packet too large for buffers (%lu > %d)\n", + (unsigned long)size, s->rxbuf_size); return; } diff --git a/hw/eepro100.c b/hw/eepro100.c index 5450b83f36..39e8fccfbc 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1441,7 +1441,7 @@ static int nic_can_receive(void *opaque) //~ return !eepro100_buffer_full(s); } -static void nic_receive(void *opaque, const uint8_t * buf, int size) +static void nic_receive(void *opaque, const uint8_t * buf, size_t size) { /* TODO: * - Magic packets should set bit 30 in power management driver register. diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index bb612840c1..2446f0dcb9 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -501,7 +501,7 @@ static int eth_can_receive(void *opaque) return 1; } -static void eth_receive(void *opaque, const uint8_t *buf, int size) +static void eth_receive(void *opaque, const uint8_t *buf, size_t size) { unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; struct fs_eth *eth = opaque; diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 86b3aafa6a..0b0f17ade6 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -353,7 +353,7 @@ static int mcf_fec_can_receive(void *opaque) return s->rx_enabled; } -static void mcf_fec_receive(void *opaque, const uint8_t *buf, int size) +static void mcf_fec_receive(void *opaque, const uint8_t *buf, size_t size) { mcf_fec_state *s = (mcf_fec_state *)opaque; mcf_fec_bd bd; diff --git a/hw/mipsnet.c b/hw/mipsnet.c index 82a8c935a1..a22f49aabc 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -75,7 +75,7 @@ static int mipsnet_can_receive(void *opaque) return !mipsnet_buffer_full(s); } -static void mipsnet_receive(void *opaque, const uint8_t *buf, int size) +static void mipsnet_receive(void *opaque, const uint8_t *buf, size_t size) { MIPSnetState *s = opaque; diff --git a/hw/musicpal.c b/hw/musicpal.c index fcefa6e32e..b7810ca7be 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -562,7 +562,7 @@ static int eth_can_receive(void *opaque) return 1; } -static void eth_receive(void *opaque, const uint8_t *buf, int size) +static void eth_receive(void *opaque, const uint8_t *buf, size_t size) { mv88w8618_eth_state *s = opaque; uint32_t desc_addr; diff --git a/hw/ne2000.c b/hw/ne2000.c index aea66b784f..502c8ae664 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -224,7 +224,7 @@ static int ne2000_can_receive(void *opaque) #define MIN_BUF_SIZE 60 -static void ne2000_receive(void *opaque, const uint8_t *buf, int size) +static void ne2000_receive(void *opaque, const uint8_t *buf, size_t size) { NE2000State *s = opaque; uint8_t *p; diff --git a/hw/pcnet.c b/hw/pcnet.c index 5eba467253..4defc437b3 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1076,7 +1076,7 @@ static int pcnet_can_receive(void *opaque) #define MIN_BUF_SIZE 60 -static void pcnet_receive(void *opaque, const uint8_t *buf, int size) +static void pcnet_receive(void *opaque, const uint8_t *buf, size_t size) { PCNetState *s = opaque; int is_padr = 0, is_bcast = 0, is_ladr = 0; diff --git a/hw/qdev.c b/hw/qdev.c index 90b42532a5..bab351c12f 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -258,16 +258,16 @@ void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin) } VLANClientState *qdev_get_vlan_client(DeviceState *dev, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, - IOReadvHandler *fd_readv, + NetCanReceive *can_receive, + NetReceive *receive, + NetReceiveIOV *receive_iov, NetCleanup *cleanup, void *opaque) { NICInfo *nd = dev->nd; assert(nd); - return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, fd_can_read, - fd_read, fd_readv, cleanup, opaque); + return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive, + receive, receive_iov, cleanup, opaque); } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index ab68bda8bf..14119d476e 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -1158,7 +1158,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d } } -static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) +static void rtl8139_receive(void *opaque, const uint8_t *buf, size_t size) { rtl8139_do_receive(opaque, buf, size, 1); } diff --git a/hw/smc91c111.c b/hw/smc91c111.c index b20d535ee1..6d1fbb32c2 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -602,7 +602,7 @@ static int smc91c111_can_receive(void *opaque) return 1; } -static void smc91c111_receive(void *opaque, const uint8_t *buf, int size) +static void smc91c111_receive(void *opaque, const uint8_t *buf, size_t size) { smc91c111_state *s = (smc91c111_state *)opaque; int status; diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 8b7df099f0..3ee9a8832c 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -78,7 +78,7 @@ static void stellaris_enet_update(stellaris_enet_state *s) } /* TODO: Implement MAC address filtering. */ -static void stellaris_enet_receive(void *opaque, const uint8_t *buf, int size) +static void stellaris_enet_receive(void *opaque, const uint8_t *buf, size_t size) { stellaris_enet_state *s = (stellaris_enet_state *)opaque; int n; diff --git a/hw/usb-net.c b/hw/usb-net.c index fda0aa5857..693e9767d2 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1369,7 +1369,7 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) return ret; } -static void usbnet_receive(void *opaque, const uint8_t *buf, int size) +static void usbnet_receive(void *opaque, const uint8_t *buf, size_t size) { USBNetState *s = opaque; struct rndis_packet_msg_type *msg; diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 561330825e..3ca93f5872 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -361,7 +361,7 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) return 0; } -static void virtio_net_receive(void *opaque, const uint8_t *buf, int size) +static void virtio_net_receive(void *opaque, const uint8_t *buf, size_t size) { VirtIONet *n = opaque; struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL; diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 350556e990..0643e57877 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -243,7 +243,7 @@ static int net_rx_ok(void *opaque) return 1; } -static void net_rx_packet(void *opaque, const uint8_t *buf, int size) +static void net_rx_packet(void *opaque, const uint8_t *buf, size_t size) { struct XenNetDev *netdev = opaque; netif_rx_request_t rxreq; @@ -262,8 +262,8 @@ static void net_rx_packet(void *opaque, const uint8_t *buf, int size) return; } if (size > XC_PAGE_SIZE - NET_IP_ALIGN) { - xen_be_printf(&netdev->xendev, 0, "packet too big (%d > %ld)", - size, XC_PAGE_SIZE - NET_IP_ALIGN); + xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)", + (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN); return; } 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; diff --git a/net.h b/net.h index ab445aa2ec..4d204e06e6 100644 --- a/net.h +++ b/net.h @@ -5,19 +5,20 @@ /* VLANs support */ -typedef ssize_t (IOReadvHandler)(void *, const struct iovec *, int); - typedef struct VLANClientState VLANClientState; +typedef int (NetCanReceive)(void *); +typedef void (NetReceive)(void *, const uint8_t *, size_t); +typedef ssize_t (NetReceiveIOV)(void *, const struct iovec *, int); typedef void (NetCleanup) (VLANClientState *); typedef void (LinkStatusChanged)(VLANClientState *); struct VLANClientState { - IOReadHandler *fd_read; - IOReadvHandler *fd_readv; + NetReceive *receive; + NetReceiveIOV *receive_iov; /* Packets may still be sent if this returns zero. It's used to rate-limit the slirp code. */ - IOCanRWHandler *fd_can_read; + NetCanReceive *can_receive; NetCleanup *cleanup; LinkStatusChanged *link_status_changed; int link_down; @@ -51,9 +52,9 @@ VLANState *qemu_find_vlan(int id); 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); void qemu_del_vlan_client(VLANClientState *vc); @@ -130,9 +131,9 @@ void net_host_device_remove(Monitor *mon, int vlan_id, const char *device); void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr); VLANClientState *qdev_get_vlan_client(DeviceState *dev, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, - IOReadvHandler *fd_readv, + NetCanReceive *can_receive, + NetReceive *receive, + NetReceiveIOV *receive_iov, NetCleanup *cleanup, void *opaque); diff --git a/savevm.c b/savevm.c index 248aea3edf..6da5e73a96 100644 --- a/savevm.c +++ b/savevm.c @@ -131,7 +131,7 @@ static void qemu_announce_self_once(void *opaque) len = announce_self_create(buf, nd_table[i].macaddr); vlan = nd_table[i].vlan; for(vc = vlan->first_client; vc != NULL; vc = vc->next) { - vc->fd_read(vc->opaque, buf, len); + vc->receive(vc->opaque, buf, len); } } if (count--) { diff --git a/tap-win32.c b/tap-win32.c index 008158da16..ccf7e45e55 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -650,7 +650,7 @@ static void tap_cleanup(VLANClientState *vc) qemu_free(s); } -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; From e3f5ec2b5e92706e3b807059f79b1fb5d936e567 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Mon, 18 May 2009 13:33:03 +0100 Subject: [PATCH 15/28] net: pass VLANClientState* as first arg to receive handlers Give static type checking a chance to catch errors. Signed-off-by: Mark McLoughlin --- hw/dp8393x.c | 12 ++++++------ hw/e1000.c | 8 ++++---- hw/eepro100.c | 8 ++++---- hw/etraxfs_eth.c | 6 +++--- hw/mcf_fec.c | 8 ++++---- hw/mipsnet.c | 10 +++++----- hw/musicpal.c | 6 +++--- hw/ne2000.c | 8 ++++---- hw/pcnet.c | 10 +++++----- hw/rtl8139.c | 14 +++++++------- hw/smc91c111.c | 8 ++++---- hw/stellaris_enet.c | 12 ++++++------ hw/usb-net.c | 8 ++++---- hw/virtio-net.c | 8 ++++---- hw/xen_nic.c | 8 ++++---- net.c | 36 ++++++++++++++++++------------------ net.h | 6 +++--- savevm.c | 2 +- tap-win32.c | 2 +- 19 files changed, 90 insertions(+), 90 deletions(-) diff --git a/hw/dp8393x.c b/hw/dp8393x.c index 1b48d9684e..de399837b9 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -407,9 +407,9 @@ static void do_transmit_packets(dp8393xState *s) if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) { /* Loopback */ s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; - if (s->vc->fd_can_read(s)) { + if (s->vc->can_receive(s->vc)) { s->loopback_packet = 1; - s->vc->receive(s, s->tx_buffer, tx_len); + s->vc->receive(s->vc, s->tx_buffer, tx_len); } } else { /* Transmit packet */ @@ -676,9 +676,9 @@ static CPUWriteMemoryFunc *dp8393x_write[3] = { dp8393x_writel, }; -static int nic_can_receive(void *opaque) +static int nic_can_receive(VLANClientState *vc) { - dp8393xState *s = opaque; + dp8393xState *s = vc->opaque; if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN)) return 0; @@ -725,10 +725,10 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) return -1; } -static void nic_receive(void *opaque, const uint8_t * buf, size_t size) +static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) { uint16_t data[10]; - dp8393xState *s = opaque; + dp8393xState *s = vc->opaque; int packet_type; uint32_t available, address; int width, rx_len = size; diff --git a/hw/e1000.c b/hw/e1000.c index 20544d2943..6d3eb313ec 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -592,17 +592,17 @@ e1000_set_link_status(VLANClientState *vc) } static int -e1000_can_receive(void *opaque) +e1000_can_receive(VLANClientState *vc) { - E1000State *s = opaque; + E1000State *s = vc->opaque; return (s->mac_reg[RCTL] & E1000_RCTL_EN); } static void -e1000_receive(void *opaque, const uint8_t *buf, size_t size) +e1000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - E1000State *s = opaque; + E1000State *s = vc->opaque; struct e1000_rx_desc desc; target_phys_addr_t base; unsigned int n, rdt; diff --git a/hw/eepro100.c b/hw/eepro100.c index 39e8fccfbc..3300fbe9ea 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1433,21 +1433,21 @@ static void pci_mmio_map(PCIDevice * pci_dev, int region_num, } } -static int nic_can_receive(void *opaque) +static int nic_can_receive(VLANClientState *vc) { - EEPRO100State *s = opaque; + EEPRO100State *s = vc->opaque; logout("%p\n", s); return get_ru_state(s) == ru_ready; //~ return !eepro100_buffer_full(s); } -static void nic_receive(void *opaque, const uint8_t * buf, size_t size) +static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) { /* TODO: * - Magic packets should set bit 30 in power management driver register. * - Interesting packets should set bit 29 in power management driver register. */ - EEPRO100State *s = opaque; + EEPRO100State *s = vc->opaque; uint16_t rfd_status = 0xa000; static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 2446f0dcb9..78af76b9bb 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -496,15 +496,15 @@ static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa) return match; } -static int eth_can_receive(void *opaque) +static int eth_can_receive(VLANClientState *vc) { return 1; } -static void eth_receive(void *opaque, const uint8_t *buf, size_t size) +static void eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct fs_eth *eth = opaque; + struct fs_eth *eth = vc->opaque; int use_ma0 = eth->regs[RW_REC_CTRL] & 1; int use_ma1 = eth->regs[RW_REC_CTRL] & 2; int r_bcast = eth->regs[RW_REC_CTRL] & 8; diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 0b0f17ade6..d2534d05fb 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -347,15 +347,15 @@ static void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value) mcf_fec_update(s); } -static int mcf_fec_can_receive(void *opaque) +static int mcf_fec_can_receive(VLANClientState *vc) { - mcf_fec_state *s = (mcf_fec_state *)opaque; + mcf_fec_state *s = vc->opaque; return s->rx_enabled; } -static void mcf_fec_receive(void *opaque, const uint8_t *buf, size_t size) +static void mcf_fec_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - mcf_fec_state *s = (mcf_fec_state *)opaque; + mcf_fec_state *s = vc->opaque; mcf_fec_bd bd; uint32_t flags = 0; uint32_t addr; diff --git a/hw/mipsnet.c b/hw/mipsnet.c index a22f49aabc..e9128cbb34 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -66,23 +66,23 @@ static int mipsnet_buffer_full(MIPSnetState *s) return 0; } -static int mipsnet_can_receive(void *opaque) +static int mipsnet_can_receive(VLANClientState *vc) { - MIPSnetState *s = opaque; + MIPSnetState *s = vc->opaque; if (s->busy) return 0; return !mipsnet_buffer_full(s); } -static void mipsnet_receive(void *opaque, const uint8_t *buf, size_t size) +static void mipsnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - MIPSnetState *s = opaque; + MIPSnetState *s = vc->opaque; #ifdef DEBUG_MIPSNET_RECEIVE printf("mipsnet: receiving len=%d\n", size); #endif - if (!mipsnet_can_receive(opaque)) + if (!mipsnet_can_receive(vc)) return; s->busy = 1; diff --git a/hw/musicpal.c b/hw/musicpal.c index b7810ca7be..844edb8f37 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -557,14 +557,14 @@ static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc) le32_to_cpus(&desc->next); } -static int eth_can_receive(void *opaque) +static int eth_can_receive(VLANClientState *vc) { return 1; } -static void eth_receive(void *opaque, const uint8_t *buf, size_t size) +static void eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - mv88w8618_eth_state *s = opaque; + mv88w8618_eth_state *s = vc->opaque; uint32_t desc_addr; mv88w8618_rx_desc desc; int i; diff --git a/hw/ne2000.c b/hw/ne2000.c index 502c8ae664..c0fc34c4b2 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -213,9 +213,9 @@ static int ne2000_buffer_full(NE2000State *s) return 0; } -static int ne2000_can_receive(void *opaque) +static int ne2000_can_receive(VLANClientState *vc) { - NE2000State *s = opaque; + NE2000State *s = vc->opaque; if (s->cmd & E8390_STOP) return 1; @@ -224,9 +224,9 @@ static int ne2000_can_receive(void *opaque) #define MIN_BUF_SIZE 60 -static void ne2000_receive(void *opaque, const uint8_t *buf, size_t size) +static void ne2000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - NE2000State *s = opaque; + NE2000State *s = vc->opaque; uint8_t *p; unsigned int total_len, next, avail, len, index, mcast_idx; uint8_t buf1[60]; diff --git a/hw/pcnet.c b/hw/pcnet.c index 4defc437b3..a8297df2af 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1062,9 +1062,9 @@ static int pcnet_tdte_poll(PCNetState *s) return !!(CSR_CXST(s) & 0x8000); } -static int pcnet_can_receive(void *opaque) +static int pcnet_can_receive(VLANClientState *vc) { - PCNetState *s = opaque; + PCNetState *s = vc->opaque; if (CSR_STOP(s) || CSR_SPND(s)) return 0; @@ -1076,9 +1076,9 @@ static int pcnet_can_receive(void *opaque) #define MIN_BUF_SIZE 60 -static void pcnet_receive(void *opaque, const uint8_t *buf, size_t size) +static void pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - PCNetState *s = opaque; + PCNetState *s = vc->opaque; int is_padr = 0, is_bcast = 0, is_ladr = 0; uint8_t buf1[60]; int remaining; @@ -1302,7 +1302,7 @@ static void pcnet_transmit(PCNetState *s) if (BCR_SWSTYLE(s) == 1) add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; - pcnet_receive(s, s->buffer, s->xmit_pos); + pcnet_receive(s->vc, s->buffer, s->xmit_pos); s->looptest = 0; } else if (s->vc) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 14119d476e..8626d5e6b8 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -790,9 +790,9 @@ static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high) #endif } -static int rtl8139_can_receive(void *opaque) +static int rtl8139_can_receive(VLANClientState *vc) { - RTL8139State *s = opaque; + RTL8139State *s = vc->opaque; int avail; /* Receive (drop) packets if card is disabled. */ @@ -812,9 +812,9 @@ static int rtl8139_can_receive(void *opaque) } } -static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int do_interrupt) +static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size, int do_interrupt) { - RTL8139State *s = opaque; + RTL8139State *s = vc->opaque; uint32_t packet_header = 0; @@ -1158,9 +1158,9 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d } } -static void rtl8139_receive(void *opaque, const uint8_t *buf, size_t size) +static void rtl8139_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - rtl8139_do_receive(opaque, buf, size, 1); + rtl8139_do_receive(vc, buf, size, 1); } static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) @@ -1757,7 +1757,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size if (TxLoopBack == (s->TxConfig & TxLoopBack)) { DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); - rtl8139_do_receive(s, buf, size, do_interrupt); + rtl8139_do_receive(s->vc, buf, size, do_interrupt); } else { diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 6d1fbb32c2..383f0b7daa 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -591,9 +591,9 @@ static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset) return val; } -static int smc91c111_can_receive(void *opaque) +static int smc91c111_can_receive(VLANClientState *vc) { - smc91c111_state *s = (smc91c111_state *)opaque; + smc91c111_state *s = vc->opaque; if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) return 1; @@ -602,9 +602,9 @@ static int smc91c111_can_receive(void *opaque) return 1; } -static void smc91c111_receive(void *opaque, const uint8_t *buf, size_t size) +static void smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - smc91c111_state *s = (smc91c111_state *)opaque; + smc91c111_state *s = vc->opaque; int status; int packetsize; uint32_t crc; diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 3ee9a8832c..7f308290da 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -78,9 +78,9 @@ static void stellaris_enet_update(stellaris_enet_state *s) } /* TODO: Implement MAC address filtering. */ -static void stellaris_enet_receive(void *opaque, const uint8_t *buf, size_t size) +static void stellaris_enet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - stellaris_enet_state *s = (stellaris_enet_state *)opaque; + stellaris_enet_state *s = vc->opaque; int n; uint8_t *p; uint32_t crc; @@ -118,9 +118,9 @@ static void stellaris_enet_receive(void *opaque, const uint8_t *buf, size_t size stellaris_enet_update(s); } -static int stellaris_enet_can_receive(void *opaque) +static int stellaris_enet_can_receive(VLANClientState *vc) { - stellaris_enet_state *s = (stellaris_enet_state *)opaque; + stellaris_enet_state *s = vc->opaque; if ((s->rctl & SE_RCTL_RXEN) == 0) return 1; @@ -128,9 +128,9 @@ static int stellaris_enet_can_receive(void *opaque) return (s->np < 31); } -static uint32_t stellaris_enet_read(void *opaque, target_phys_addr_t offset) +static uint32_t stellaris_enet_read(VLANClientState *vc, target_phys_addr_t offset) { - stellaris_enet_state *s = (stellaris_enet_state *)opaque; + stellaris_enet_state *s = vc->opaque; uint32_t val; switch (offset) { diff --git a/hw/usb-net.c b/hw/usb-net.c index 693e9767d2..d8d5e773f5 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1369,9 +1369,9 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) return ret; } -static void usbnet_receive(void *opaque, const uint8_t *buf, size_t size) +static void usbnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - USBNetState *s = opaque; + USBNetState *s = vc->opaque; struct rndis_packet_msg_type *msg; if (s->rndis) { @@ -1405,9 +1405,9 @@ static void usbnet_receive(void *opaque, const uint8_t *buf, size_t size) s->in_ptr = 0; } -static int usbnet_can_receive(void *opaque) +static int usbnet_can_receive(VLANClientState *vc) { - USBNetState *s = opaque; + USBNetState *s = vc->opaque; if (s->rndis && !s->rndis_state == RNDIS_DATA_INITIALIZED) return 1; diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 3ca93f5872..1ffebac222 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -288,9 +288,9 @@ static int do_virtio_net_can_receive(VirtIONet *n, int bufsize) return 1; } -static int virtio_net_can_receive(void *opaque) +static int virtio_net_can_receive(VLANClientState *vc) { - VirtIONet *n = opaque; + VirtIONet *n = vc->opaque; return do_virtio_net_can_receive(n, VIRTIO_NET_MAX_BUFSIZE); } @@ -361,9 +361,9 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) return 0; } -static void virtio_net_receive(void *opaque, const uint8_t *buf, size_t size) +static void virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - VirtIONet *n = opaque; + VirtIONet *n = vc->opaque; struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL; size_t hdr_len, offset, i; diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 0643e57877..173e87a8ff 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -223,9 +223,9 @@ static void net_rx_response(struct XenNetDev *netdev, #define NET_IP_ALIGN 2 -static int net_rx_ok(void *opaque) +static int net_rx_ok(VLANClientState *vc) { - struct XenNetDev *netdev = opaque; + struct XenNetDev *netdev = vc->opaque; RING_IDX rc, rp; if (netdev->xendev.be_state != XenbusStateConnected) @@ -243,9 +243,9 @@ static int net_rx_ok(void *opaque) return 1; } -static void net_rx_packet(void *opaque, const uint8_t *buf, size_t size) +static void net_rx_packet(VLANClientState *vc, const uint8_t *buf, size_t size) { - struct XenNetDev *netdev = opaque; + struct XenNetDev *netdev = vc->opaque; netif_rx_request_t rxreq; RING_IDX rc, rp; void *page; 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; diff --git a/net.h b/net.h index 4d204e06e6..a28827c4a7 100644 --- a/net.h +++ b/net.h @@ -7,9 +7,9 @@ typedef struct VLANClientState VLANClientState; -typedef int (NetCanReceive)(void *); -typedef void (NetReceive)(void *, const uint8_t *, size_t); -typedef ssize_t (NetReceiveIOV)(void *, const struct iovec *, int); +typedef int (NetCanReceive)(VLANClientState *); +typedef void (NetReceive)(VLANClientState *, const uint8_t *, size_t); +typedef ssize_t (NetReceiveIOV)(VLANClientState *, const struct iovec *, int); typedef void (NetCleanup) (VLANClientState *); typedef void (LinkStatusChanged)(VLANClientState *); diff --git a/savevm.c b/savevm.c index 6da5e73a96..cae711762d 100644 --- a/savevm.c +++ b/savevm.c @@ -131,7 +131,7 @@ static void qemu_announce_self_once(void *opaque) len = announce_self_create(buf, nd_table[i].macaddr); vlan = nd_table[i].vlan; for(vc = vlan->first_client; vc != NULL; vc = vc->next) { - vc->receive(vc->opaque, buf, len); + vc->receive(vc, buf, len); } } if (count--) { diff --git a/tap-win32.c b/tap-win32.c index ccf7e45e55..ff1e1ed5f4 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -650,7 +650,7 @@ static void tap_cleanup(VLANClientState *vc) qemu_free(s); } -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; From 4f1c942b7fb29864ad86cb3af9076da38f38f74e Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Mon, 18 May 2009 13:40:55 +0100 Subject: [PATCH 16/28] 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 --- hw/dp8393x.c | 8 ++++--- hw/e1000.c | 14 +++++++----- hw/eepro100.c | 15 +++++++------ hw/etraxfs_eth.c | 8 ++++--- hw/mcf_fec.c | 3 ++- hw/mipsnet.c | 6 +++-- hw/musicpal.c | 5 +++-- hw/ne2000.c | 15 ++++++++----- hw/pcnet.c | 7 ++++-- hw/rtl8139.c | 29 +++++++++++++----------- hw/smc91c111.c | 10 +++++---- hw/stellaris_enet.c | 8 ++++--- hw/usb-net.c | 9 ++++---- hw/virtio-net.c | 10 +++++---- hw/xen_nic.c | 12 +++++----- net.c | 54 +++++++++++++++++++++++---------------------- net.h | 2 +- tap-win32.c | 6 ++--- 18 files changed, 126 insertions(+), 95 deletions(-) diff --git a/hw/dp8393x.c b/hw/dp8393x.c index de399837b9..cff84aa0a1 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -725,7 +725,7 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) return -1; } -static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) +static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) { uint16_t data[10]; dp8393xState *s = vc->opaque; @@ -742,7 +742,7 @@ static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) packet_type = receive_filter(s, buf, size); if (packet_type < 0) { DPRINTF("packet not for netcard\n"); - return; + return -1; } /* XXX: Check byte ordering */ @@ -755,7 +755,7 @@ static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0); if (data[0 * width] & 0x1) { /* Still EOL ; stop reception */ - return; + return -1; } else { s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; } @@ -833,6 +833,8 @@ static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) /* Done */ dp8393x_update_irq(s); + + return size; } static void nic_reset(void *opaque) diff --git a/hw/e1000.c b/hw/e1000.c index 6d3eb313ec..7f8f5b2ae4 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -599,7 +599,7 @@ e1000_can_receive(VLANClientState *vc) return (s->mac_reg[RCTL] & E1000_RCTL_EN); } -static void +static ssize_t e1000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { E1000State *s = vc->opaque; @@ -611,16 +611,16 @@ e1000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) uint8_t vlan_status = 0, vlan_offset = 0; if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) - return; + return -1; if (size > s->rxbuf_size) { DBGOUT(RX, "packet too large for buffers (%lu > %d)\n", (unsigned long)size, s->rxbuf_size); - return; + return -1; } if (!receive_filter(s, buf, size)) - return; + return size; if (vlan_enabled(s) && is_vlan_packet(s, buf)) { vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14))); @@ -635,7 +635,7 @@ e1000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) do { if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) { set_ics(s, 0, E1000_ICS_RXO); - return; + return -1; } base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] + sizeof(desc) * s->mac_reg[RDH]; @@ -659,7 +659,7 @@ e1000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n", rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]); set_ics(s, 0, E1000_ICS_RXO); - return; + return -1; } } while (desc.buffer_addr == 0); @@ -677,6 +677,8 @@ e1000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) n |= E1000_ICS_RXDMT0; set_ics(s, 0, n); + + return size; } static uint32_t diff --git a/hw/eepro100.c b/hw/eepro100.c index 3300fbe9ea..a6355dc754 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1441,7 +1441,7 @@ static int nic_can_receive(VLANClientState *vc) //~ return !eepro100_buffer_full(s); } -static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) +static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) { /* TODO: * - Magic packets should set bit 30 in power management driver register. @@ -1458,18 +1458,18 @@ static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) if (s->configuration[8] & 0x80) { /* CSMA is disabled. */ logout("%p received while CSMA is disabled\n", s); - return; + return -1; } else if (size < 64 && (s->configuration[7] & 1)) { /* Short frame and configuration byte 7/0 (discard short receive) set: * Short frame is discarded */ logout("%p received short frame (%d byte)\n", s, size); s->statistics.rx_short_frame_errors++; - //~ return; + //~ return -1; } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & 8)) { /* Long frame and configuration byte 18/3 (long receive ok) not set: * Long frames are discarded. */ logout("%p received long frame (%d byte), ignored\n", s, size); - return; + return -1; } else if (memcmp(buf, s->macaddr, 6) == 0) { // !!! /* Frame matches individual address. */ /* TODO: check configuration byte 15/4 (ignore U/L). */ @@ -1485,7 +1485,7 @@ static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) assert(!(s->configuration[21] & BIT(3))); int mcast_idx = compute_mcast_idx(buf); if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) { - return; + return size; } rfd_status |= 0x0002; } else if (s->configuration[15] & 1) { @@ -1495,7 +1495,7 @@ static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) } else { logout("%p received frame, ignored, len=%d,%s\n", s, size, nic_dump(buf, size)); - return; + return size; } if (get_ru_state(s) != ru_ready) { @@ -1503,7 +1503,7 @@ static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) logout("no ressources, state=%u\n", get_ru_state(s)); s->statistics.rx_resource_errors++; //~ assert(!"no ressources"); - return; + return -1; } //~ !!! //~ $3 = {status = 0x0, command = 0xc000, link = 0x2d220, rx_buf_addr = 0x207dc, count = 0x0, size = 0x5f8, packet = {0x0 }} @@ -1540,6 +1540,7 @@ static void nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) /* S bit is set. */ set_ru_state(s, ru_suspended); } + return size; } static int nic_load(QEMUFile * f, void *opaque, int version_id) diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 78af76b9bb..c7df44ee45 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -501,7 +501,7 @@ static int eth_can_receive(VLANClientState *vc) return 1; } -static void eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; struct fs_eth *eth = vc->opaque; @@ -510,7 +510,7 @@ static void eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) int r_bcast = eth->regs[RW_REC_CTRL] & 8; if (size < 12) - return; + return -1; D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], @@ -521,10 +521,12 @@ static void eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) && (!r_bcast || memcmp(buf, sa_bcast, 6)) && !eth_match_groupaddr(eth, buf)) - return; + return size; /* FIXME: Find another way to pass on the fake csum. */ etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1); + + return size; } static int eth_tx_push(void *opaque, unsigned char *buf, int len) diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index d2534d05fb..179ec19e07 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -353,7 +353,7 @@ static int mcf_fec_can_receive(VLANClientState *vc) return s->rx_enabled; } -static void mcf_fec_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t mcf_fec_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { mcf_fec_state *s = vc->opaque; mcf_fec_bd bd; @@ -426,6 +426,7 @@ static void mcf_fec_receive(VLANClientState *vc, const uint8_t *buf, size_t size s->rx_descriptor = addr; mcf_fec_enable_rx(s); mcf_fec_update(s); + return size; } static CPUReadMemoryFunc *mcf_fec_readfn[] = { diff --git a/hw/mipsnet.c b/hw/mipsnet.c index e9128cbb34..803522949b 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -75,7 +75,7 @@ static int mipsnet_can_receive(VLANClientState *vc) return !mipsnet_buffer_full(s); } -static void mipsnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t mipsnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { MIPSnetState *s = vc->opaque; @@ -83,7 +83,7 @@ static void mipsnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size printf("mipsnet: receiving len=%d\n", size); #endif if (!mipsnet_can_receive(vc)) - return; + return -1; s->busy = 1; @@ -98,6 +98,8 @@ static void mipsnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size /* Now we can signal we have received something. */ s->intctl |= MIPSNET_INTCTL_RXDONE; mipsnet_update_irq(s); + + return size; } static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr) diff --git a/hw/musicpal.c b/hw/musicpal.c index 844edb8f37..8c70a2bec8 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -562,7 +562,7 @@ static int eth_can_receive(VLANClientState *vc) return 1; } -static void eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { mv88w8618_eth_state *s = vc->opaque; uint32_t desc_addr; @@ -586,11 +586,12 @@ static void eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size) if (s->icr & s->imr) qemu_irq_raise(s->irq); eth_rx_desc_put(desc_addr, &desc); - return; + return size; } desc_addr = desc.next; } while (desc_addr != s->rx_queue[i]); } + return size; } static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc) diff --git a/hw/ne2000.c b/hw/ne2000.c index c0fc34c4b2..f5ae9d7394 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -224,9 +224,10 @@ static int ne2000_can_receive(VLANClientState *vc) #define MIN_BUF_SIZE 60 -static void ne2000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t ne2000_receive(VLANClientState *vc, const uint8_t *buf, size_t size_) { NE2000State *s = vc->opaque; + int size = size_; uint8_t *p; unsigned int total_len, next, avail, len, index, mcast_idx; uint8_t buf1[60]; @@ -238,7 +239,7 @@ static void ne2000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) #endif if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) - return; + return -1; /* XXX: check this */ if (s->rxcr & 0x10) { @@ -247,14 +248,14 @@ static void ne2000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) if (!memcmp(buf, broadcast_macaddr, 6)) { /* broadcast address */ if (!(s->rxcr & 0x04)) - return; + return size; } else if (buf[0] & 0x01) { /* multicast */ if (!(s->rxcr & 0x08)) - return; + return size; mcast_idx = compute_mcast_idx(buf); if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) - return; + return size; } else if (s->mem[0] == buf[0] && s->mem[2] == buf[1] && s->mem[4] == buf[2] && @@ -263,7 +264,7 @@ static void ne2000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) s->mem[10] == buf[5]) { /* match */ } else { - return; + return size; } } @@ -316,6 +317,8 @@ static void ne2000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) /* now we can signal we have received something */ s->isr |= ENISR_RX; ne2000_update_irq(s); + + return size_; } static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) diff --git a/hw/pcnet.c b/hw/pcnet.c index a8297df2af..b5793ff246 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1076,16 +1076,17 @@ static int pcnet_can_receive(VLANClientState *vc) #define MIN_BUF_SIZE 60 -static void pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size_) { PCNetState *s = vc->opaque; int is_padr = 0, is_bcast = 0, is_ladr = 0; uint8_t buf1[60]; int remaining; int crc_err = 0; + int size = size_; if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) - return; + return -1; #ifdef PCNET_DEBUG printf("pcnet_receive size=%d\n", size); @@ -1252,6 +1253,8 @@ static void pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) pcnet_poll(s); pcnet_update_irq(s); + + return size_; } static void pcnet_transmit(PCNetState *s) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 8626d5e6b8..c86b782e4c 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -812,9 +812,10 @@ static int rtl8139_can_receive(VLANClientState *vc) } } -static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size, int do_interrupt) +static ssize_t rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, size_t size_, int do_interrupt) { RTL8139State *s = vc->opaque; + int size = size_; uint32_t packet_header = 0; @@ -828,7 +829,7 @@ static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size if (!s->clock_enabled) { DEBUG_PRINT(("RTL8139: stopped ==========================\n")); - return; + return -1; } /* first check if receiver is enabled */ @@ -836,7 +837,7 @@ static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size if (!rtl8139_receiver_enabled(s)) { DEBUG_PRINT(("RTL8139: receiver disabled ================\n")); - return; + return -1; } /* XXX: check this */ @@ -854,7 +855,7 @@ static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size /* update tally counter */ ++s->tally_counters.RxERR; - return; + return size; } packet_header |= RxBroadcast; @@ -873,7 +874,7 @@ static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size /* update tally counter */ ++s->tally_counters.RxERR; - return; + return size; } int mcast_idx = compute_mcast_idx(buf); @@ -885,7 +886,7 @@ static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size /* update tally counter */ ++s->tally_counters.RxERR; - return; + return size; } packet_header |= RxMulticast; @@ -909,7 +910,7 @@ static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size /* update tally counter */ ++s->tally_counters.RxERR; - return; + return size; } packet_header |= RxPhysical; @@ -926,7 +927,7 @@ static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size /* update tally counter */ ++s->tally_counters.RxERR; - return; + return size; } } @@ -993,7 +994,7 @@ static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size ++s->tally_counters.MissPkt; rtl8139_update_irq(s); - return; + return size_; } uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK; @@ -1013,7 +1014,7 @@ static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size ++s->tally_counters.MissPkt; rtl8139_update_irq(s); - return; + return size_; } target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI); @@ -1118,7 +1119,7 @@ static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size s->IntrStatus |= RxOverflow; ++s->RxMissed; rtl8139_update_irq(s); - return; + return size_; } packet_header |= RxStatusOK; @@ -1156,11 +1157,13 @@ static void rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, int size { rtl8139_update_irq(s); } + + return size_; } -static void rtl8139_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t rtl8139_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - rtl8139_do_receive(vc, buf, size, 1); + return rtl8139_do_receive(vc, buf, size, 1); } static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 383f0b7daa..93a1fae0dc 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -602,7 +602,7 @@ static int smc91c111_can_receive(VLANClientState *vc) return 1; } -static void smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { smc91c111_state *s = vc->opaque; int status; @@ -612,7 +612,7 @@ static void smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t si uint8_t *p; if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) - return; + return -1; /* Short packets are padded with zeros. Receiving a packet < 64 bytes long is considered an error condition. */ if (size < 64) @@ -625,10 +625,10 @@ static void smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t si packetsize += 4; /* TODO: Flag overrun and receive errors. */ if (packetsize > 2048) - return; + return -1; packetnum = smc91c111_allocate_packet(s); if (packetnum == 0x80) - return; + return -1; s->rx_fifo[s->rx_fifo_len++] = packetnum; p = &s->data[packetnum][0]; @@ -676,6 +676,8 @@ static void smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t si /* TODO: Raise early RX interrupt? */ s->int_level |= INT_RCV; smc91c111_update(s); + + return size; } static CPUReadMemoryFunc *smc91c111_readfn[] = { diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 7f308290da..f5b83e445c 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -78,7 +78,7 @@ static void stellaris_enet_update(stellaris_enet_state *s) } /* TODO: Implement MAC address filtering. */ -static void stellaris_enet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t stellaris_enet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { stellaris_enet_state *s = vc->opaque; int n; @@ -86,10 +86,10 @@ static void stellaris_enet_receive(VLANClientState *vc, const uint8_t *buf, size uint32_t crc; if ((s->rctl & SE_RCTL_RXEN) == 0) - return; + return -1; if (s->np >= 31) { DPRINTF("Packet dropped\n"); - return; + return -1; } DPRINTF("Received packet len=%d\n", size); @@ -116,6 +116,8 @@ static void stellaris_enet_receive(VLANClientState *vc, const uint8_t *buf, size s->ris |= SE_INT_RX; stellaris_enet_update(s); + + return size; } static int stellaris_enet_can_receive(VLANClientState *vc) diff --git a/hw/usb-net.c b/hw/usb-net.c index d8d5e773f5..0e80ca6923 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1369,7 +1369,7 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) return ret; } -static void usbnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t usbnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { USBNetState *s = vc->opaque; struct rndis_packet_msg_type *msg; @@ -1377,9 +1377,9 @@ static void usbnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) if (s->rndis) { msg = (struct rndis_packet_msg_type *) s->in_buf; if (!s->rndis_state == RNDIS_DATA_INITIALIZED) - return; + return -1; if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf)) - return; + return -1; memset(msg, 0, sizeof(struct rndis_packet_msg_type)); msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG); @@ -1398,11 +1398,12 @@ static void usbnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size) s->in_len = size + sizeof(struct rndis_packet_msg_type); } else { if (size > sizeof(s->in_buf)) - return; + return -1; memcpy(s->in_buf, buf, size); s->in_len = size; } s->in_ptr = 0; + return size; } static int usbnet_can_receive(VLANClientState *vc) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 1ffebac222..6b34c5afc1 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -361,17 +361,17 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) return 0; } -static void virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { VirtIONet *n = vc->opaque; struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL; size_t hdr_len, offset, i; if (!do_virtio_net_can_receive(n, size)) - return; + return -1; if (!receive_filter(n, buf, size)) - return; + return size; /* hdr_len refers to the header we supply to the guest */ hdr_len = n->mergeable_rx_bufs ? @@ -389,7 +389,7 @@ static void virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_t s if ((i != 0 && !n->mergeable_rx_bufs) || virtqueue_pop(n->rx_vq, &elem) == 0) { if (i == 0) - return; + return -1; fprintf(stderr, "virtio-net truncating packet\n"); exit(1); } @@ -431,6 +431,8 @@ static void virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_t s virtqueue_flush(n->rx_vq, i); virtio_notify(&n->vdev, n->rx_vq); + + return size; } /* TX */ diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 173e87a8ff..9a3c870c2d 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -243,7 +243,7 @@ static int net_rx_ok(VLANClientState *vc) return 1; } -static void net_rx_packet(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t net_rx_packet(VLANClientState *vc, const uint8_t *buf, size_t size) { struct XenNetDev *netdev = vc->opaque; netif_rx_request_t rxreq; @@ -251,7 +251,7 @@ static void net_rx_packet(VLANClientState *vc, const uint8_t *buf, size_t size) void *page; if (netdev->xendev.be_state != XenbusStateConnected) - return; + return -1; rc = netdev->rx_ring.req_cons; rp = netdev->rx_ring.sring->req_prod; @@ -259,12 +259,12 @@ static void net_rx_packet(VLANClientState *vc, const uint8_t *buf, size_t size) if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) { xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n"); - return; + return -1; } if (size > XC_PAGE_SIZE - NET_IP_ALIGN) { xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)", (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN); - return; + return -1; } memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq)); @@ -277,11 +277,13 @@ static void net_rx_packet(VLANClientState *vc, const uint8_t *buf, size_t size) xen_be_printf(&netdev->xendev, 0, "error: rx gref dereference failed (%d)\n", rxreq.gref); net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0); - return; + return -1; } memcpy(page + NET_IP_ALIGN, buf, size); xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1); net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0); + + return size; } /* ------------------------------------------------------------- */ 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) diff --git a/net.h b/net.h index a28827c4a7..f1cedf4d17 100644 --- a/net.h +++ b/net.h @@ -8,7 +8,7 @@ typedef struct VLANClientState VLANClientState; typedef int (NetCanReceive)(VLANClientState *); -typedef void (NetReceive)(VLANClientState *, const uint8_t *, size_t); +typedef ssize_t (NetReceive)(VLANClientState *, const uint8_t *, size_t); typedef ssize_t (NetReceiveIOV)(VLANClientState *, const struct iovec *, int); typedef void (NetCleanup) (VLANClientState *); typedef void (LinkStatusChanged)(VLANClientState *); diff --git a/tap-win32.c b/tap-win32.c index ff1e1ed5f4..ba93355a74 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -650,11 +650,11 @@ static void tap_cleanup(VLANClientState *vc) qemu_free(s); } -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 = opaque; + TAPState *s = vc->opaque; - tap_win32_write(s->handle, buf, size); + return tap_win32_write(s->handle, buf, size); } static void tap_win32_send(void *opaque) From 3e021d40b7548b2eeec62a082411c0745a5c635f Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 11:34:52 +0100 Subject: [PATCH 17/28] 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(-) 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) From e94667b91ccfdb70164ae320b1c4ded6b5b8a3ec Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 11:48:12 +0100 Subject: [PATCH 18/28] 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 | 167 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 104 insertions(+), 63 deletions(-) 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; } +static int qemu_deliver_packet_iov(VLANClientState *sender, + const struct iovec *iov, int iovcnt) +{ + 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; + size_t max_len = 0; + int i; + + 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; + + 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; + } + + sender->vlan->send_queue = packet; + + return packet->size; +} + ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, int iovcnt) { - VLANState *vlan = sender->vlan; - VLANClientState *vc; - VLANPacket *packet; - ssize_t max_len = 0; - int i; + int ret; - if (sender->link_down) + if (sender->link_down) { return calc_iov_length(iov, iovcnt); - - if (vlan->delivering) { - max_len = calc_iov_length(iov, iovcnt); - - 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 == 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); - } - - 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; + if (sender->vlan->delivering) { + return qemu_enqueue_packet_iov(sender, iov, iovcnt); + } + + ret = qemu_deliver_packet_iov(sender, iov, iovcnt); + + qemu_flush_queued_packets(sender); + + return ret; } static void config_error(Monitor *mon, const char *fmt, ...) From f3b6c7fcf8fca857b3c3ba0aa5b3a06d7ce0ac37 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 12:15:26 +0100 Subject: [PATCH 19/28] 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 | 91 +++++++++++++++++++++++++++++++++++++++++++---------------- net.h | 8 ++++++ 2 files changed, 74 insertions(+), 25 deletions(-) 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; - -#ifdef DEBUG_NET - printf("vlan %d send:\n", vlan->id); - hex_dump(stdout, buf, size); -#endif - if (vlan->delivering) { - qemu_enqueue_packet(vc, buf, size); - return; + if (sender->link_down) { + return size; } - qemu_deliver_packet(vc, buf, size); - qemu_flush_queued_packets(vc); +#ifdef DEBUG_NET + printf("vlan %d send:\n", sender->vlan->id); + hex_dump(stdout, buf, size); +#endif + + if (sender->vlan->delivering) { + qemu_enqueue_packet(sender, buf, size, NULL); + return size; + } + + 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; diff --git a/net.h b/net.h index f1cedf4d17..89e7706be4 100644 --- a/net.h +++ b/net.h @@ -32,10 +32,13 @@ struct VLANClientState { typedef struct VLANPacket VLANPacket; +typedef void (NetPacketSent) (VLANClientState *); + struct VLANPacket { struct VLANPacket *next; VLANClientState *sender; int size; + NetPacketSent *sent_cb; uint8_t data[0]; }; @@ -62,7 +65,12 @@ VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque); int qemu_can_send_packet(VLANClientState *vc); ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt); +ssize_t qemu_sendv_packet_async(VLANClientState *vc, const struct iovec *iov, + int iovcnt, NetPacketSent *sent_cb); void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size); +ssize_t qemu_send_packet_async(VLANClientState *vc, const uint8_t *buf, + int size, NetPacketSent *sent_cb); +void qemu_flush_queued_packets(VLANClientState *vc); void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6]); void qemu_check_nic_model(NICInfo *nd, const char *model); void qemu_check_nic_model_list(NICInfo *nd, const char * const *models, From e19eb22486f258a421108ac22b8380a4e2f16b97 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 13:30:24 +0100 Subject: [PATCH 20/28] 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(-) 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) From 8aeff62d75b72263d855a0b5892b8d52ad6f09e0 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Wed, 29 Apr 2009 13:40:02 +0100 Subject: [PATCH 21/28] virtio-net: implement rx packet queueing If we don't have room to receive a packet, we return zero from virtio_net_receive() and call qemu_flush_queued_packets() as soon as space becomes available. Signed-off-by: Mark McLoughlin --- hw/virtio-net.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 6b34c5afc1..a3ba890312 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -269,6 +269,9 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) { + VirtIONet *n = to_virtio_net(vdev); + + qemu_flush_queued_packets(n->vc); } static int do_virtio_net_can_receive(VirtIONet *n, int bufsize) @@ -368,7 +371,7 @@ static ssize_t virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_ size_t hdr_len, offset, i; if (!do_virtio_net_can_receive(n, size)) - return -1; + return 0; if (!receive_filter(n, buf, size)) return size; From 6c042c16fc2453e147e8aed66510820302f50702 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Jun 2009 14:46:52 -0600 Subject: [PATCH 22/28] virtio-net: Add version_id 7 placeholder for vnet header support Signed-off-by: Alex Williamson Signed-off-by: Mark McLoughlin --- hw/virtio-net.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index a3ba890312..a77fdb29e0 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -16,7 +16,7 @@ #include "qemu-timer.h" #include "virtio-net.h" -#define VIRTIO_NET_VM_VERSION 6 +#define VIRTIO_NET_VM_VERSION 7 #define MAC_TABLE_ENTRIES 32 #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ @@ -528,6 +528,7 @@ static void virtio_net_save(QEMUFile *f, void *opaque) qemu_put_be32(f, n->mac_table.in_use); qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); + qemu_put_be32(f, 0); /* vnet-hdr placeholder */ } static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) @@ -567,6 +568,12 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) if (version_id >= 6) qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); + if (version_id >= 7 && qemu_get_be32(f)) { + fprintf(stderr, + "virtio-net: saved image requires vnet header support\n"); + exit(1); + } + if (n->tx_timer_active) { qemu_mod_timer(n->tx_timer, qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL); From f10c592e8d35e59a11cf7af1484ab1051acc3ef6 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Jun 2009 14:46:57 -0600 Subject: [PATCH 23/28] virtio-net: Use a byte to store RX mode flags There's no need to save 4 bytes for promisc and allmulti. Use one byte each just to avoid the overhead of a bitmap. Signed-off-by: Alex Williamson Signed-off-by: Mark McLoughlin --- hw/virtio-net.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index a77fdb29e0..13eb0d1f09 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -16,7 +16,7 @@ #include "qemu-timer.h" #include "virtio-net.h" -#define VIRTIO_NET_VM_VERSION 7 +#define VIRTIO_NET_VM_VERSION 8 #define MAC_TABLE_ENTRIES 32 #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ @@ -33,8 +33,8 @@ typedef struct VirtIONet QEMUTimer *tx_timer; int tx_timer_active; int mergeable_rx_bufs; - int promisc; - int allmulti; + uint8_t promisc; + uint8_t allmulti; struct { int in_use; uint8_t *macs; @@ -523,8 +523,8 @@ static void virtio_net_save(QEMUFile *f, void *opaque) qemu_put_be32(f, n->tx_timer_active); qemu_put_be32(f, n->mergeable_rx_bufs); qemu_put_be16(f, n->status); - qemu_put_be32(f, n->promisc); - qemu_put_be32(f, n->allmulti); + qemu_put_byte(f, n->promisc); + qemu_put_byte(f, n->allmulti); qemu_put_be32(f, n->mac_table.in_use); qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); @@ -548,8 +548,13 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) n->status = qemu_get_be16(f); if (version_id >= 4) { - n->promisc = qemu_get_be32(f); - n->allmulti = qemu_get_be32(f); + if (version_id < 8) { + n->promisc = qemu_get_be32(f); + n->allmulti = qemu_get_be32(f); + } else { + n->promisc = qemu_get_byte(f); + n->allmulti = qemu_get_byte(f); + } } if (version_id >= 5) { From bbe2f399b222f1f2fcf5cd2ea78e4f5c9a66c64e Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Jun 2009 14:47:02 -0600 Subject: [PATCH 24/28] virtio-net: reorganize receive_filter() Reorganize receive_filter to better handle the split between unicast and multicast filtering. This allows us to skip the broadcast check on unicast packets and leads to more opportunities for optimization. Signed-off-by: Alex Williamson Signed-off-by: Mark McLoughlin --- hw/virtio-net.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 13eb0d1f09..445976a41a 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -347,14 +347,17 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) return 0; } - if ((ptr[0] & 1) && n->allmulti) - return 1; - - if (!memcmp(ptr, bcast, sizeof(bcast))) - return 1; - - if (!memcmp(ptr, n->mac, ETH_ALEN)) - return 1; + if (ptr[0] & 1) { // multicast + if (!memcmp(ptr, bcast, sizeof(bcast))) { + return 1; + } else if (n->allmulti) { + return 1; + } + } else { // unicast + if (!memcmp(ptr, n->mac, ETH_ALEN)) { + return 1; + } + } for (i = 0; i < n->mac_table.in_use; i++) { if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) From 8fd2a2f1a9048b9e37a898c2a5e9ef59d0c1a095 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Jun 2009 14:47:08 -0600 Subject: [PATCH 25/28] virtio-net: Fix MAC filter overflow handling Overloading the promisc and allmulti flags for indicating filter table overflow makes it difficult to track the actual requested operating mode. Split these out into separate flags. Signed-off-by: Alex Williamson Signed-off-by: Mark McLoughlin --- hw/virtio-net.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 445976a41a..8c38454ae1 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -16,7 +16,7 @@ #include "qemu-timer.h" #include "virtio-net.h" -#define VIRTIO_NET_VM_VERSION 8 +#define VIRTIO_NET_VM_VERSION 9 #define MAC_TABLE_ENTRIES 32 #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ @@ -37,6 +37,8 @@ typedef struct VirtIONet uint8_t allmulti; struct { int in_use; + uint8_t multi_overflow; + uint8_t uni_overflow; uint8_t *macs; } mac_table; uint32_t *vlans; @@ -98,6 +100,8 @@ static void virtio_net_reset(VirtIODevice *vdev) /* Flush any MAC and VLAN filter table state */ n->mac_table.in_use = 0; + n->mac_table.multi_overflow = 0; + n->mac_table.uni_overflow = 0; memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); memset(n->vlans, 0, MAX_VLAN >> 3); } @@ -168,6 +172,8 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_ERR; n->mac_table.in_use = 0; + n->mac_table.uni_overflow = 0; + n->mac_table.multi_overflow = 0; memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base); @@ -181,8 +187,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, mac_data.entries * ETH_ALEN); n->mac_table.in_use += mac_data.entries; } else { - n->promisc = 1; - return VIRTIO_NET_OK; + n->mac_table.uni_overflow = 1; } mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base); @@ -197,8 +202,9 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, elem->out_sg[2].iov_base + sizeof(mac_data), mac_data.entries * ETH_ALEN); n->mac_table.in_use += mac_data.entries; - } else - n->allmulti = 1; + } else { + n->mac_table.multi_overflow = 1; + } } return VIRTIO_NET_OK; @@ -350,11 +356,13 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) if (ptr[0] & 1) { // multicast if (!memcmp(ptr, bcast, sizeof(bcast))) { return 1; - } else if (n->allmulti) { + } else if (n->allmulti || n->mac_table.multi_overflow) { return 1; } } else { // unicast - if (!memcmp(ptr, n->mac, ETH_ALEN)) { + if (n->mac_table.uni_overflow) { + return 1; + } else if (!memcmp(ptr, n->mac, ETH_ALEN)) { return 1; } } @@ -532,6 +540,8 @@ static void virtio_net_save(QEMUFile *f, void *opaque) qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); qemu_put_be32(f, 0); /* vnet-hdr placeholder */ + qemu_put_byte(f, n->mac_table.multi_overflow); + qemu_put_byte(f, n->mac_table.uni_overflow); } static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) @@ -568,7 +578,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) n->mac_table.in_use * ETH_ALEN); } else if (n->mac_table.in_use) { qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR); - n->promisc = 1; + n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1; n->mac_table.in_use = 0; } } @@ -582,6 +592,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) exit(1); } + if (version_id >= 9) { + n->mac_table.multi_overflow = qemu_get_byte(f); + n->mac_table.uni_overflow = qemu_get_byte(f); + } + if (n->tx_timer_active) { qemu_mod_timer(n->tx_timer, qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL); From 2d9aba3961dd6c18cdafecc8ce31b330b45e2723 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Jun 2009 14:47:13 -0600 Subject: [PATCH 26/28] virtio-net: MAC filter optimization The MAC filter table is received from the guest as two separate buffers, one with unicast entries, the other with multicast entries. If we track the index dividing the two sets, we can avoid searching the part of the table with the wrong type of entries. We could store this index as part of the save image, but its trivially easy to discover it on load. Signed-off-by: Alex Williamson Signed-off-by: Mark McLoughlin --- hw/virtio-net.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 8c38454ae1..7863d5ddbf 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -37,6 +37,7 @@ typedef struct VirtIONet uint8_t allmulti; struct { int in_use; + int first_multi; uint8_t multi_overflow; uint8_t uni_overflow; uint8_t *macs; @@ -100,6 +101,7 @@ static void virtio_net_reset(VirtIODevice *vdev) /* Flush any MAC and VLAN filter table state */ n->mac_table.in_use = 0; + n->mac_table.first_multi = 0; n->mac_table.multi_overflow = 0; n->mac_table.uni_overflow = 0; memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); @@ -172,6 +174,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_ERR; n->mac_table.in_use = 0; + n->mac_table.first_multi = 0; n->mac_table.uni_overflow = 0; n->mac_table.multi_overflow = 0; memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); @@ -190,6 +193,8 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, n->mac_table.uni_overflow = 1; } + n->mac_table.first_multi = n->mac_table.in_use; + mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base); if (sizeof(mac_data.entries) + @@ -359,17 +364,24 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) } else if (n->allmulti || n->mac_table.multi_overflow) { return 1; } + + for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) { + if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) { + return 1; + } + } } else { // unicast if (n->mac_table.uni_overflow) { return 1; } else if (!memcmp(ptr, n->mac, ETH_ALEN)) { return 1; } - } - for (i = 0; i < n->mac_table.in_use; i++) { - if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) - return 1; + for (i = 0; i < n->mac_table.first_multi; i++) { + if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) { + return 1; + } + } } return 0; @@ -547,6 +559,7 @@ static void virtio_net_save(QEMUFile *f, void *opaque) static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) { VirtIONet *n = opaque; + int i; if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) return -EINVAL; @@ -597,6 +610,14 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) n->mac_table.uni_overflow = qemu_get_byte(f); } + /* Find the first multicast entry in the saved MAC filter */ + for (i = 0; i < n->mac_table.in_use; i++) { + if (n->mac_table.macs[i * ETH_ALEN] & 1) { + break; + } + } + n->mac_table.first_multi = i; + if (n->tx_timer_active) { qemu_mod_timer(n->tx_timer, qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL); From 015cb16699199b7c062f02a0b89a869fdb18330f Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Jun 2009 14:47:18 -0600 Subject: [PATCH 27/28] virtio-net: Add new RX filter controls Add a few new RX modes to better control the receive_filter. These are all fairly obvious features that hardware could provide. Signed-off-by: Alex Williamson Signed-off-by: Mark McLoughlin --- hw/virtio-net.c | 40 ++++++++++++++++++++++++++++++++++++---- hw/virtio-net.h | 14 ++++++++++---- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 7863d5ddbf..a64244c1a2 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -16,7 +16,7 @@ #include "qemu-timer.h" #include "virtio-net.h" -#define VIRTIO_NET_VM_VERSION 9 +#define VIRTIO_NET_VM_VERSION 10 #define MAC_TABLE_ENTRIES 32 #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ @@ -35,6 +35,10 @@ typedef struct VirtIONet int mergeable_rx_bufs; uint8_t promisc; uint8_t allmulti; + uint8_t alluni; + uint8_t nomulti; + uint8_t nouni; + uint8_t nobcast; struct { int in_use; int first_multi; @@ -98,6 +102,10 @@ static void virtio_net_reset(VirtIODevice *vdev) /* Reset back to compatibility mode */ n->promisc = 1; n->allmulti = 0; + n->alluni = 0; + n->nomulti = 0; + n->nouni = 0; + n->nobcast = 0; /* Flush any MAC and VLAN filter table state */ n->mac_table.in_use = 0; @@ -114,7 +122,8 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev) (1 << VIRTIO_NET_F_STATUS) | (1 << VIRTIO_NET_F_CTRL_VQ) | (1 << VIRTIO_NET_F_CTRL_RX) | - (1 << VIRTIO_NET_F_CTRL_VLAN); + (1 << VIRTIO_NET_F_CTRL_VLAN) | + (1 << VIRTIO_NET_F_CTRL_RX_EXTRA); return features; } @@ -157,6 +166,14 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, n->promisc = on; else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI) n->allmulti = on; + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLUNI) + n->alluni = on; + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOMULTI) + n->nomulti = on; + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOUNI) + n->nouni = on; + else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOBCAST) + n->nobcast = on; else return VIRTIO_NET_ERR; @@ -360,7 +377,9 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) if (ptr[0] & 1) { // multicast if (!memcmp(ptr, bcast, sizeof(bcast))) { - return 1; + return !n->nobcast; + } else if (n->nomulti) { + return 0; } else if (n->allmulti || n->mac_table.multi_overflow) { return 1; } @@ -371,7 +390,9 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) } } } else { // unicast - if (n->mac_table.uni_overflow) { + if (n->nouni) { + return 0; + } else if (n->alluni || n->mac_table.uni_overflow) { return 1; } else if (!memcmp(ptr, n->mac, ETH_ALEN)) { return 1; @@ -554,6 +575,10 @@ static void virtio_net_save(QEMUFile *f, void *opaque) qemu_put_be32(f, 0); /* vnet-hdr placeholder */ qemu_put_byte(f, n->mac_table.multi_overflow); qemu_put_byte(f, n->mac_table.uni_overflow); + qemu_put_byte(f, n->alluni); + qemu_put_byte(f, n->nomulti); + qemu_put_byte(f, n->nouni); + qemu_put_byte(f, n->nobcast); } static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) @@ -610,6 +635,13 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) n->mac_table.uni_overflow = qemu_get_byte(f); } + if (version_id >= 10) { + n->alluni = qemu_get_byte(f); + n->nomulti = qemu_get_byte(f); + n->nouni = qemu_get_byte(f); + n->nobcast = qemu_get_byte(f); + } + /* Find the first multicast entry in the saved MAC filter */ for (i = 0; i < n->mac_table.in_use; i++) { if (n->mac_table.macs[i * ETH_ALEN] & 1) { diff --git a/hw/virtio-net.h b/hw/virtio-net.h index 390fe10224..2085181673 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -43,6 +43,7 @@ #define VIRTIO_NET_F_CTRL_VQ 17 /* Control channel available */ #define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support */ #define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */ +#define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */ #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ @@ -103,14 +104,19 @@ typedef uint8_t virtio_net_ctrl_ack; #define VIRTIO_NET_ERR 1 /* - * Control the RX mode, ie. promisucous and allmulti. PROMISC and - * ALLMULTI commands require an "out" sg entry containing a 1 byte - * state value, zero = disable, non-zero = enable. These commands - * are supported with the VIRTIO_NET_F_CTRL_RX feature. + * Control the RX mode, ie. promisucous, allmulti, etc... + * All commands require an "out" sg entry containing a 1 byte + * state value, zero = disable, non-zero = enable. Commands + * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature. + * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA. */ #define VIRTIO_NET_CTRL_RX_MODE 0 #define VIRTIO_NET_CTRL_RX_MODE_PROMISC 0 #define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI 1 + #define VIRTIO_NET_CTRL_RX_MODE_ALLUNI 2 + #define VIRTIO_NET_CTRL_RX_MODE_NOMULTI 3 + #define VIRTIO_NET_CTRL_RX_MODE_NOUNI 4 + #define VIRTIO_NET_CTRL_RX_MODE_NOBCAST 5 /* * Control the MAC filter table. From 4ffb17f5c3244e405198ae285ffbb20a62e0d4b3 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Jun 2009 14:47:23 -0600 Subject: [PATCH 28/28] virtio-net: Increase filter and control limits Increase the size of the perfect filter table and control queue depth. This should give us more headroom in the MAC filter and is known to be needed by at least one guest user. Increasing the control queue depth allows a guest to feed several commands back to back if they so desire rather than using the send and wait approach Linux uses. Signed-off-by: Alex Williamson Signed-off-by: Mark McLoughlin --- hw/virtio-net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index a64244c1a2..d584287a51 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -18,7 +18,7 @@ #define VIRTIO_NET_VM_VERSION 10 -#define MAC_TABLE_ENTRIES 32 +#define MAC_TABLE_ENTRIES 64 #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ typedef struct VirtIONet @@ -690,7 +690,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev) n->vdev.reset = virtio_net_reset; n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx); - n->ctrl_vq = virtio_add_queue(&n->vdev, 16, virtio_net_handle_ctrl); + n->ctrl_vq = virtio_add_queue(&n->vdev, 64, virtio_net_handle_ctrl); qdev_get_macaddr(dev, n->mac); n->status = VIRTIO_NET_S_LINK_UP; n->vc = qdev_get_vlan_client(dev,