From 11196e95f0521fa6ba689c15f874ad9a2d99e158 Mon Sep 17 00:00:00 2001 From: Zhou Jie Date: Tue, 26 Apr 2016 09:26:01 +0800 Subject: net/tap: Allocating Large sized arrays to heap net_init_tap has a huge stack usage of 8192 bytes approx. Moving large arrays to heap to reduce stack usage. Signed-off-by: Zhou Jie Signed-off-by: Jason Wang --- net/tap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/tap.c b/net/tap.c index 740e8a2613..49817c70c1 100644 --- a/net/tap.c +++ b/net/tap.c @@ -769,8 +769,8 @@ int net_init_tap(const NetClientOptions *opts, const char *name, return -1; } } else if (tap->has_fds) { - char *fds[MAX_TAP_QUEUES]; - char *vhost_fds[MAX_TAP_QUEUES]; + char **fds = g_new(char *, MAX_TAP_QUEUES); + char **vhost_fds = g_new(char *, MAX_TAP_QUEUES); int nfds, nvhosts; if (tap->has_ifname || tap->has_script || tap->has_downscript || @@ -818,6 +818,8 @@ int net_init_tap(const NetClientOptions *opts, const char *name, return -1; } } + g_free(fds); + g_free(vhost_fds); } else if (tap->has_helper) { if (tap->has_ifname || tap->has_script || tap->has_downscript || tap->has_vnet_hdr || tap->has_queues || tap->has_vhostfds) { -- cgit v1.2.3 From d30300f771bffc3964e86472e0c21607521a2e24 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 12 May 2016 11:17:16 -0300 Subject: net: vl: Move default_net to vl.c All handling of defaults (default_* variables) is inside vl.c, move default_net there too, so we can more easily refactor that code later. Reviewed-by: Paolo Bonzini Signed-off-by: Eduardo Habkost Signed-off-by: Jason Wang --- net/net.c | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'net') diff --git a/net/net.c b/net/net.c index 0ad6217cb9..1680b680e1 100644 --- a/net/net.c +++ b/net/net.c @@ -76,8 +76,6 @@ const char *host_net_devices[] = { NULL, }; -int default_net = 1; - /***********************************************************/ /* network device redirectors */ @@ -1415,18 +1413,6 @@ void net_check_clients(void) NetClientState *nc; int i; - /* Don't warn about the default network setup that you get if - * no command line -net or -netdev options are specified. There - * are two cases that we would otherwise complain about: - * (1) board doesn't support a NIC but the implicit "-net nic" - * requested one - * (2) CONFIG_SLIRP not set, in which case the implicit "-net nic" - * sets up a nic that isn't connected to anything. - */ - if (default_net) { - return; - } - net_hub_check_clients(); QTAILQ_FOREACH(nc, &net_clients, next) { @@ -1483,14 +1469,6 @@ int net_init_clients(void) { QemuOptsList *net = qemu_find_opts("net"); - if (default_net) { - /* if no clients, we use a default config */ - qemu_opts_set(net, NULL, "type", "nic", &error_abort); -#ifdef CONFIG_SLIRP - qemu_opts_set(net, NULL, "type", "user", &error_abort); -#endif - } - net_change_state_entry = qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL); @@ -1521,7 +1499,6 @@ int net_client_parse(QemuOptsList *opts_list, const char *optarg) return -1; } - default_net = 0; return 0; } -- cgit v1.2.3 From 16a3df403b10c4ac347159e39005fd520b2648bb Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Fri, 13 May 2016 15:35:19 +0800 Subject: net/net: Add SocketReadState for reuse codes This function is from net/socket.c, move it to net.c and net.h. Add SocketReadState to make others reuse net_fill_rstate(). suggestion from jason. v4: - move 'rs->finalize = finalize' to rs_init() v3: - remove SocketReadState init callback - put finalize callback to net_fill_rstate() v2: - rename ReadState to SocketReadState - add SocketReadState init and finalize callback v1: - init patch Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Wen Congyang Signed-off-by: Jason Wang --- net/filter-mirror.c | 66 +++++++++++---------------------------------- net/net.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ net/socket.c | 77 +++++++++++++++-------------------------------------- 3 files changed, 108 insertions(+), 105 deletions(-) (limited to 'net') diff --git a/net/filter-mirror.c b/net/filter-mirror.c index c0c4dc60b6..35df37451d 100644 --- a/net/filter-mirror.c +++ b/net/filter-mirror.c @@ -40,10 +40,7 @@ typedef struct MirrorState { char *outdev; CharDriverState *chr_in; CharDriverState *chr_out; - int state; /* 0 = getting length, 1 = getting data */ - unsigned int index; - unsigned int packet_len; - uint8_t buf[REDIRECTOR_MAX_LEN]; + SocketReadState rs; } MirrorState; static int filter_mirror_send(CharDriverState *chr_out, @@ -108,51 +105,12 @@ static void redirector_chr_read(void *opaque, const uint8_t *buf, int size) { NetFilterState *nf = opaque; MirrorState *s = FILTER_REDIRECTOR(nf); - unsigned int l; - - while (size > 0) { - /* reassemble a packet from the network */ - switch (s->state) { /* 0 = getting length, 1 = getting data */ - case 0: - l = 4 - s->index; - if (l > size) { - l = size; - } - memcpy(s->buf + s->index, buf, l); - buf += l; - size -= l; - s->index += l; - if (s->index == 4) { - /* got length */ - s->packet_len = ntohl(*(uint32_t *)s->buf); - s->index = 0; - s->state = 1; - } - break; - case 1: - l = s->packet_len - s->index; - if (l > size) { - l = size; - } - if (s->index + l <= sizeof(s->buf)) { - memcpy(s->buf + s->index, buf, l); - } else { - error_report("serious error: oversized packet received."); - s->index = s->state = 0; - qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL); - return; - } - - s->index += l; - buf += l; - size -= l; - if (s->index >= s->packet_len) { - s->index = 0; - s->state = 0; - redirector_to_filter(nf, s->buf, s->packet_len); - } - break; - } + int ret; + + ret = net_fill_rstate(&s->rs, buf, size); + + if (ret == -1) { + qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL); } } @@ -258,6 +216,14 @@ static void filter_mirror_setup(NetFilterState *nf, Error **errp) } } +static void redirector_rs_finalize(SocketReadState *rs) +{ + MirrorState *s = container_of(rs, MirrorState, rs); + NetFilterState *nf = NETFILTER(s); + + redirector_to_filter(nf, rs->buf, rs->packet_len); +} + static void filter_redirector_setup(NetFilterState *nf, Error **errp) { MirrorState *s = FILTER_REDIRECTOR(nf); @@ -274,7 +240,7 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp) } } - s->state = s->index = 0; + net_socket_rs_init(&s->rs, redirector_rs_finalize); if (s->indev) { s->chr_in = qemu_chr_find(s->indev); diff --git a/net/net.c b/net/net.c index 1680b680e1..5f3e5a9ff5 100644 --- a/net/net.c +++ b/net/net.c @@ -1550,3 +1550,73 @@ QemuOptsList qemu_net_opts = { { /* end of list */ } }, }; + +void net_socket_rs_init(SocketReadState *rs, + SocketReadStateFinalize *finalize) +{ + rs->state = 0; + rs->index = 0; + rs->packet_len = 0; + memset(rs->buf, 0, sizeof(rs->buf)); + rs->finalize = finalize; +} + +/* + * Returns + * 0: SocketReadState is not ready + * 1: SocketReadState is ready + * otherwise error occurs + */ +int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size) +{ + unsigned int l; + + while (size > 0) { + /* reassemble a packet from the network */ + switch (rs->state) { /* 0 = getting length, 1 = getting data */ + case 0: + l = 4 - rs->index; + if (l > size) { + l = size; + } + memcpy(rs->buf + rs->index, buf, l); + buf += l; + size -= l; + rs->index += l; + if (rs->index == 4) { + /* got length */ + rs->packet_len = ntohl(*(uint32_t *)rs->buf); + rs->index = 0; + rs->state = 1; + } + break; + case 1: + l = rs->packet_len - rs->index; + if (l > size) { + l = size; + } + if (rs->index + l <= sizeof(rs->buf)) { + memcpy(rs->buf + rs->index, buf, l); + } else { + fprintf(stderr, "serious error: oversized packet received," + "connection terminated.\n"); + rs->index = rs->state = 0; + return -1; + } + + rs->index += l; + buf += l; + size -= l; + if (rs->index >= rs->packet_len) { + rs->index = 0; + rs->state = 0; + if (rs->finalize) { + rs->finalize(rs); + } + return 1; + } + break; + } + } + return 0; +} diff --git a/net/socket.c b/net/socket.c index 9fa2cd8d51..333fb9ecfa 100644 --- a/net/socket.c +++ b/net/socket.c @@ -38,11 +38,8 @@ typedef struct NetSocketState { NetClientState nc; int listen_fd; int fd; - int state; /* 0 = getting length, 1 = getting data */ - unsigned int index; - unsigned int packet_len; + SocketReadState rs; unsigned int send_index; /* number of bytes sent (only SOCK_STREAM) */ - uint8_t buf[NET_BUFSIZE]; struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ IOHandler *send_fn; /* differs between SOCK_STREAM/SOCK_DGRAM */ bool read_poll; /* waiting to receive data? */ @@ -143,11 +140,22 @@ static void net_socket_send_completed(NetClientState *nc, ssize_t len) } } +static void net_socket_rs_finalize(SocketReadState *rs) +{ + NetSocketState *s = container_of(rs, NetSocketState, rs); + + if (qemu_send_packet_async(&s->nc, rs->buf, + rs->packet_len, + net_socket_send_completed) == 0) { + net_socket_read_poll(s, false); + } +} + static void net_socket_send(void *opaque) { NetSocketState *s = opaque; int size; - unsigned l; + int ret; uint8_t buf1[NET_BUFSIZE]; const uint8_t *buf; @@ -166,61 +174,18 @@ static void net_socket_send(void *opaque) closesocket(s->fd); s->fd = -1; - s->state = 0; - s->index = 0; - s->packet_len = 0; + net_socket_rs_init(&s->rs, net_socket_rs_finalize); s->nc.link_down = true; - memset(s->buf, 0, sizeof(s->buf)); memset(s->nc.info_str, 0, sizeof(s->nc.info_str)); return; } buf = buf1; - while (size > 0) { - /* reassemble a packet from the network */ - switch(s->state) { - case 0: - l = 4 - s->index; - if (l > size) - l = size; - memcpy(s->buf + s->index, buf, l); - buf += l; - size -= l; - s->index += l; - if (s->index == 4) { - /* got length */ - s->packet_len = ntohl(*(uint32_t *)s->buf); - s->index = 0; - s->state = 1; - } - break; - case 1: - l = s->packet_len - s->index; - if (l > size) - l = size; - if (s->index + l <= sizeof(s->buf)) { - memcpy(s->buf + s->index, buf, l); - } else { - fprintf(stderr, "serious error: oversized packet received," - "connection terminated.\n"); - s->state = 0; - goto eoc; - } - s->index += l; - buf += l; - size -= l; - if (s->index >= s->packet_len) { - s->index = 0; - s->state = 0; - if (qemu_send_packet_async(&s->nc, s->buf, s->packet_len, - net_socket_send_completed) == 0) { - net_socket_read_poll(s, false); - break; - } - } - break; - } + ret = net_fill_rstate(&s->rs, buf, size); + + if (ret == -1) { + goto eoc; } } @@ -229,7 +194,7 @@ static void net_socket_send_dgram(void *opaque) NetSocketState *s = opaque; int size; - size = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0); + size = qemu_recv(s->fd, s->rs.buf, sizeof(s->rs.buf), 0); if (size < 0) return; if (size == 0) { @@ -238,7 +203,7 @@ static void net_socket_send_dgram(void *opaque) net_socket_write_poll(s, false); return; } - if (qemu_send_packet_async(&s->nc, s->buf, size, + if (qemu_send_packet_async(&s->nc, s->rs.buf, size, net_socket_send_completed) == 0) { net_socket_read_poll(s, false); } @@ -401,6 +366,7 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, s->fd = fd; s->listen_fd = -1; s->send_fn = net_socket_send_dgram; + net_socket_rs_init(&s->rs, net_socket_rs_finalize); net_socket_read_poll(s, true); /* mcast: save bound address as dst */ @@ -451,6 +417,7 @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer, s->fd = fd; s->listen_fd = -1; + net_socket_rs_init(&s->rs, net_socket_rs_finalize); /* Disable Nagle algorithm on TCP sockets to reduce latency */ socket_set_nodelay(fd); -- cgit v1.2.3 From eb700029c7836798046191d62d595363d92c84d4 Mon Sep 17 00:00:00 2001 From: Dmitry Fleytman Date: Wed, 1 Jun 2016 11:23:41 +0300 Subject: net_pkt: Extend packet abstraction as required by e1000e functionality This patch extends the TX/RX packet abstractions with features that will be used by the e1000e device implementation. Changes are: 1. Support iovec lists for RX buffers 2. Deeper RX packets parsing 3. Loopback option for TX packets 4. Extended VLAN headers handling 5. RSS processing for RX packets Signed-off-by: Dmitry Fleytman Signed-off-by: Leonid Bloch Reviewed-by: Michael S. Tsirkin Signed-off-by: Jason Wang --- net/checksum.c | 7 +- net/eth.c | 410 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 373 insertions(+), 44 deletions(-) (limited to 'net') diff --git a/net/checksum.c b/net/checksum.c index d0fa424cc1..196aaa3459 100644 --- a/net/checksum.c +++ b/net/checksum.c @@ -95,12 +95,11 @@ void net_checksum_calculate(uint8_t *data, int length) uint32_t net_checksum_add_iov(const struct iovec *iov, const unsigned int iov_cnt, - uint32_t iov_off, uint32_t size) + uint32_t iov_off, uint32_t size, uint32_t csum_offset) { size_t iovec_off, buf_off; unsigned int i; uint32_t res = 0; - uint32_t seq = 0; iovec_off = 0; buf_off = 0; @@ -109,8 +108,8 @@ net_checksum_add_iov(const struct iovec *iov, const unsigned int iov_cnt, size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size); void *chunk_buf = iov[i].iov_base + (iov_off - iovec_off); - res += net_checksum_add_cont(len, chunk_buf, seq); - seq += len; + res += net_checksum_add_cont(len, chunk_buf, csum_offset); + csum_offset += len; buf_off += len; iov_off += len; diff --git a/net/eth.c b/net/eth.c index 7e32d274c7..95fe15c23f 100644 --- a/net/eth.c +++ b/net/eth.c @@ -21,8 +21,8 @@ #include "qemu-common.h" #include "net/tap.h" -void eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag, - bool *is_new) +void eth_setup_vlan_headers_ex(struct eth_header *ehdr, uint16_t vlan_tag, + uint16_t vlan_ethtype, bool *is_new) { struct vlan_header *vhdr = PKT_GET_VLAN_HDR(ehdr); @@ -36,7 +36,7 @@ void eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag, default: /* No VLAN header, put a new one */ vhdr->h_proto = ehdr->h_proto; - ehdr->h_proto = cpu_to_be16(ETH_P_VLAN); + ehdr->h_proto = cpu_to_be16(vlan_ethtype); *is_new = true; break; } @@ -79,26 +79,100 @@ eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto) return VIRTIO_NET_HDR_GSO_NONE | ecn_state; } -void eth_get_protocols(const uint8_t *headers, - uint32_t hdr_length, +uint16_t +eth_get_l3_proto(const struct iovec *l2hdr_iov, int iovcnt, size_t l2hdr_len) +{ + uint16_t proto; + size_t copied; + size_t size = iov_size(l2hdr_iov, iovcnt); + size_t proto_offset = l2hdr_len - sizeof(proto); + + if (size < proto_offset) { + return ETH_P_UNKNOWN; + } + + copied = iov_to_buf(l2hdr_iov, iovcnt, proto_offset, + &proto, sizeof(proto)); + + return (copied == sizeof(proto)) ? be16_to_cpu(proto) : ETH_P_UNKNOWN; +} + +static bool +_eth_copy_chunk(size_t input_size, + const struct iovec *iov, int iovcnt, + size_t offset, size_t length, + void *buffer) +{ + size_t copied; + + if (input_size < offset) { + return false; + } + + copied = iov_to_buf(iov, iovcnt, offset, buffer, length); + + if (copied < length) { + return false; + } + + return true; +} + +static bool +_eth_tcp_has_data(bool is_ip4, + const struct ip_header *ip4_hdr, + const struct ip6_header *ip6_hdr, + size_t full_ip6hdr_len, + const struct tcp_header *tcp) +{ + uint32_t l4len; + + if (is_ip4) { + l4len = be16_to_cpu(ip4_hdr->ip_len) - IP_HDR_GET_LEN(ip4_hdr); + } else { + size_t opts_len = full_ip6hdr_len - sizeof(struct ip6_header); + l4len = be16_to_cpu(ip6_hdr->ip6_ctlun.ip6_un1.ip6_un1_plen) - opts_len; + } + + return l4len > TCP_HEADER_DATA_OFFSET(tcp); +} + +void eth_get_protocols(const struct iovec *iov, int iovcnt, bool *isip4, bool *isip6, - bool *isudp, bool *istcp) + bool *isudp, bool *istcp, + size_t *l3hdr_off, + size_t *l4hdr_off, + size_t *l5hdr_off, + eth_ip6_hdr_info *ip6hdr_info, + eth_ip4_hdr_info *ip4hdr_info, + eth_l4_hdr_info *l4hdr_info) { int proto; - size_t l2hdr_len = eth_get_l2_hdr_length(headers); - assert(hdr_length >= eth_get_l2_hdr_length(headers)); + bool fragment = false; + size_t l2hdr_len = eth_get_l2_hdr_length_iov(iov, iovcnt); + size_t input_size = iov_size(iov, iovcnt); + size_t copied; + *isip4 = *isip6 = *isudp = *istcp = false; - proto = eth_get_l3_proto(headers, l2hdr_len); + proto = eth_get_l3_proto(iov, iovcnt, l2hdr_len); + + *l3hdr_off = l2hdr_len; + if (proto == ETH_P_IP) { - *isip4 = true; + struct ip_header *iphdr = &ip4hdr_info->ip4_hdr; - struct ip_header *iphdr; + if (input_size < l2hdr_len) { + return; + } + + copied = iov_to_buf(iov, iovcnt, l2hdr_len, iphdr, sizeof(*iphdr)); - assert(hdr_length >= - eth_get_l2_hdr_length(headers) + sizeof(struct ip_header)); + *isip4 = true; - iphdr = PKT_GET_IP_HDR(headers); + if (copied < sizeof(*iphdr)) { + return; + } if (IP_HEADER_VERSION(iphdr) == IP_HEADER_VERSION_4) { if (iphdr->ip_p == IP_PROTO_TCP) { @@ -107,24 +181,135 @@ void eth_get_protocols(const uint8_t *headers, *isudp = true; } } - } else if (proto == ETH_P_IPV6) { - uint8_t l4proto; - size_t full_ip6hdr_len; - struct iovec hdr_vec; - hdr_vec.iov_base = (void *) headers; - hdr_vec.iov_len = hdr_length; + ip4hdr_info->fragment = IP4_IS_FRAGMENT(iphdr); + *l4hdr_off = l2hdr_len + IP_HDR_GET_LEN(iphdr); + + fragment = ip4hdr_info->fragment; + } else if (proto == ETH_P_IPV6) { *isip6 = true; - if (eth_parse_ipv6_hdr(&hdr_vec, 1, l2hdr_len, - &l4proto, &full_ip6hdr_len)) { - if (l4proto == IP_PROTO_TCP) { + if (eth_parse_ipv6_hdr(iov, iovcnt, l2hdr_len, + ip6hdr_info)) { + if (ip6hdr_info->l4proto == IP_PROTO_TCP) { *istcp = true; - } else if (l4proto == IP_PROTO_UDP) { + } else if (ip6hdr_info->l4proto == IP_PROTO_UDP) { *isudp = true; } + } else { + return; + } + + *l4hdr_off = l2hdr_len + ip6hdr_info->full_hdr_len; + fragment = ip6hdr_info->fragment; + } + + if (!fragment) { + if (*istcp) { + *istcp = _eth_copy_chunk(input_size, + iov, iovcnt, + *l4hdr_off, sizeof(l4hdr_info->hdr.tcp), + &l4hdr_info->hdr.tcp); + + if (istcp) { + *l5hdr_off = *l4hdr_off + + TCP_HEADER_DATA_OFFSET(&l4hdr_info->hdr.tcp); + + l4hdr_info->has_tcp_data = + _eth_tcp_has_data(proto == ETH_P_IP, + &ip4hdr_info->ip4_hdr, + &ip6hdr_info->ip6_hdr, + *l4hdr_off - *l3hdr_off, + &l4hdr_info->hdr.tcp); + } + } else if (*isudp) { + *isudp = _eth_copy_chunk(input_size, + iov, iovcnt, + *l4hdr_off, sizeof(l4hdr_info->hdr.udp), + &l4hdr_info->hdr.udp); + *l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp); + } + } +} + +bool +eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff, + uint8_t *new_ehdr_buf, + uint16_t *payload_offset, uint16_t *tci) +{ + struct vlan_header vlan_hdr; + struct eth_header *new_ehdr = (struct eth_header *) new_ehdr_buf; + + size_t copied = iov_to_buf(iov, iovcnt, iovoff, + new_ehdr, sizeof(*new_ehdr)); + + if (copied < sizeof(*new_ehdr)) { + return false; + } + + switch (be16_to_cpu(new_ehdr->h_proto)) { + case ETH_P_VLAN: + case ETH_P_DVLAN: + copied = iov_to_buf(iov, iovcnt, iovoff + sizeof(*new_ehdr), + &vlan_hdr, sizeof(vlan_hdr)); + + if (copied < sizeof(vlan_hdr)) { + return false; + } + + new_ehdr->h_proto = vlan_hdr.h_proto; + + *tci = be16_to_cpu(vlan_hdr.h_tci); + *payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr); + + if (be16_to_cpu(new_ehdr->h_proto) == ETH_P_VLAN) { + + copied = iov_to_buf(iov, iovcnt, *payload_offset, + PKT_GET_VLAN_HDR(new_ehdr), sizeof(vlan_hdr)); + + if (copied < sizeof(vlan_hdr)) { + return false; + } + + *payload_offset += sizeof(vlan_hdr); + } + return true; + default: + return false; + } +} + +bool +eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, + uint16_t vet, uint8_t *new_ehdr_buf, + uint16_t *payload_offset, uint16_t *tci) +{ + struct vlan_header vlan_hdr; + struct eth_header *new_ehdr = (struct eth_header *) new_ehdr_buf; + + size_t copied = iov_to_buf(iov, iovcnt, iovoff, + new_ehdr, sizeof(*new_ehdr)); + + if (copied < sizeof(*new_ehdr)) { + return false; + } + + if (be16_to_cpu(new_ehdr->h_proto) == vet) { + copied = iov_to_buf(iov, iovcnt, iovoff + sizeof(*new_ehdr), + &vlan_hdr, sizeof(vlan_hdr)); + + if (copied < sizeof(vlan_hdr)) { + return false; } + + new_ehdr->h_proto = vlan_hdr.h_proto; + + *tci = be16_to_cpu(vlan_hdr.h_tci); + *payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr); + return true; } + + return false; } void @@ -133,7 +318,12 @@ eth_setup_ip4_fragmentation(const void *l2hdr, size_t l2hdr_len, size_t l3payload_len, size_t frag_offset, bool more_frags) { - if (eth_get_l3_proto(l2hdr, l2hdr_len) == ETH_P_IP) { + const struct iovec l2vec = { + .iov_base = (void *) l2hdr, + .iov_len = l2hdr_len + }; + + if (eth_get_l3_proto(&l2vec, 1, l2hdr_len) == ETH_P_IP) { uint16_t orig_flags; struct ip_header *iphdr = (struct ip_header *) l3hdr; uint16_t frag_off_units = frag_offset / IP_FRAG_UNIT_SIZE; @@ -158,7 +348,9 @@ eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len) } uint32_t -eth_calc_pseudo_hdr_csum(struct ip_header *iphdr, uint16_t csl) +eth_calc_ip4_pseudo_hdr_csum(struct ip_header *iphdr, + uint16_t csl, + uint32_t *cso) { struct ip_pseudo_header ipph; ipph.ip_src = iphdr->ip_src; @@ -166,7 +358,26 @@ eth_calc_pseudo_hdr_csum(struct ip_header *iphdr, uint16_t csl) ipph.ip_payload = cpu_to_be16(csl); ipph.ip_proto = iphdr->ip_p; ipph.zeros = 0; - return net_checksum_add(sizeof(ipph), (uint8_t *) &ipph); + *cso = sizeof(ipph); + return net_checksum_add(*cso, (uint8_t *) &ipph); +} + +uint32_t +eth_calc_ip6_pseudo_hdr_csum(struct ip6_header *iphdr, + uint16_t csl, + uint8_t l4_proto, + uint32_t *cso) +{ + struct ip6_pseudo_header ipph; + ipph.ip6_src = iphdr->ip6_src; + ipph.ip6_dst = iphdr->ip6_dst; + ipph.len = cpu_to_be16(csl); + ipph.zero[0] = 0; + ipph.zero[1] = 0; + ipph.zero[2] = 0; + ipph.next_hdr = l4_proto; + *cso = sizeof(ipph); + return net_checksum_add(*cso, (uint8_t *)&ipph); } static bool @@ -186,33 +397,152 @@ eth_is_ip6_extension_header_type(uint8_t hdr_type) } } -bool eth_parse_ipv6_hdr(struct iovec *pkt, int pkt_frags, - size_t ip6hdr_off, uint8_t *l4proto, - size_t *full_hdr_len) +static bool +_eth_get_rss_ex_dst_addr(const struct iovec *pkt, int pkt_frags, + size_t rthdr_offset, + struct ip6_ext_hdr *ext_hdr, + struct in6_address *dst_addr) +{ + struct ip6_ext_hdr_routing *rthdr = (struct ip6_ext_hdr_routing *) ext_hdr; + + if ((rthdr->rtype == 2) && + (rthdr->len == sizeof(struct in6_address) / 8) && + (rthdr->segleft == 1)) { + + size_t input_size = iov_size(pkt, pkt_frags); + size_t bytes_read; + + if (input_size < rthdr_offset + sizeof(*ext_hdr)) { + return false; + } + + bytes_read = iov_to_buf(pkt, pkt_frags, + rthdr_offset + sizeof(*ext_hdr), + dst_addr, sizeof(dst_addr)); + + return bytes_read == sizeof(dst_addr); + } + + return false; +} + +static bool +_eth_get_rss_ex_src_addr(const struct iovec *pkt, int pkt_frags, + size_t dsthdr_offset, + struct ip6_ext_hdr *ext_hdr, + struct in6_address *src_addr) +{ + size_t bytes_left = (ext_hdr->ip6r_len + 1) * 8 - sizeof(*ext_hdr); + struct ip6_option_hdr opthdr; + size_t opt_offset = dsthdr_offset + sizeof(*ext_hdr); + + while (bytes_left > sizeof(opthdr)) { + size_t input_size = iov_size(pkt, pkt_frags); + size_t bytes_read, optlen; + + if (input_size < opt_offset) { + return false; + } + + bytes_read = iov_to_buf(pkt, pkt_frags, opt_offset, + &opthdr, sizeof(opthdr)); + + if (bytes_read != sizeof(opthdr)) { + return false; + } + + optlen = (opthdr.type == IP6_OPT_PAD1) ? 1 + : (opthdr.len + sizeof(opthdr)); + + if (optlen > bytes_left) { + return false; + } + + if (opthdr.type == IP6_OPT_HOME) { + size_t input_size = iov_size(pkt, pkt_frags); + + if (input_size < opt_offset + sizeof(opthdr)) { + return false; + } + + bytes_read = iov_to_buf(pkt, pkt_frags, + opt_offset + sizeof(opthdr), + src_addr, sizeof(src_addr)); + + return bytes_read == sizeof(src_addr); + } + + opt_offset += optlen; + bytes_left -= optlen; + } + + return false; +} + +bool eth_parse_ipv6_hdr(const struct iovec *pkt, int pkt_frags, + size_t ip6hdr_off, eth_ip6_hdr_info *info) { - struct ip6_header ip6_hdr; struct ip6_ext_hdr ext_hdr; size_t bytes_read; + uint8_t curr_ext_hdr_type; + size_t input_size = iov_size(pkt, pkt_frags); + + info->rss_ex_dst_valid = false; + info->rss_ex_src_valid = false; + info->fragment = false; + + if (input_size < ip6hdr_off) { + return false; + } bytes_read = iov_to_buf(pkt, pkt_frags, ip6hdr_off, - &ip6_hdr, sizeof(ip6_hdr)); - if (bytes_read < sizeof(ip6_hdr)) { + &info->ip6_hdr, sizeof(info->ip6_hdr)); + if (bytes_read < sizeof(info->ip6_hdr)) { return false; } - *full_hdr_len = sizeof(struct ip6_header); + info->full_hdr_len = sizeof(struct ip6_header); + + curr_ext_hdr_type = info->ip6_hdr.ip6_nxt; - if (!eth_is_ip6_extension_header_type(ip6_hdr.ip6_nxt)) { - *l4proto = ip6_hdr.ip6_nxt; + if (!eth_is_ip6_extension_header_type(curr_ext_hdr_type)) { + info->l4proto = info->ip6_hdr.ip6_nxt; + info->has_ext_hdrs = false; return true; } + info->has_ext_hdrs = true; + do { - bytes_read = iov_to_buf(pkt, pkt_frags, ip6hdr_off + *full_hdr_len, + if (input_size < ip6hdr_off + info->full_hdr_len) { + return false; + } + + bytes_read = iov_to_buf(pkt, pkt_frags, ip6hdr_off + info->full_hdr_len, &ext_hdr, sizeof(ext_hdr)); - *full_hdr_len += (ext_hdr.ip6r_len + 1) * IP6_EXT_GRANULARITY; - } while (eth_is_ip6_extension_header_type(ext_hdr.ip6r_nxt)); - *l4proto = ext_hdr.ip6r_nxt; + if (bytes_read < sizeof(ext_hdr)) { + return false; + } + + if (curr_ext_hdr_type == IP6_ROUTING) { + info->rss_ex_dst_valid = + _eth_get_rss_ex_dst_addr(pkt, pkt_frags, + ip6hdr_off + info->full_hdr_len, + &ext_hdr, &info->rss_ex_dst); + } else if (curr_ext_hdr_type == IP6_DESTINATON) { + info->rss_ex_src_valid = + _eth_get_rss_ex_src_addr(pkt, pkt_frags, + ip6hdr_off + info->full_hdr_len, + &ext_hdr, &info->rss_ex_src); + } else if (curr_ext_hdr_type == IP6_FRAGMENT) { + info->fragment = true; + } + + info->full_hdr_len += (ext_hdr.ip6r_len + 1) * IP6_EXT_GRANULARITY; + curr_ext_hdr_type = ext_hdr.ip6r_nxt; + } while (eth_is_ip6_extension_header_type(curr_ext_hdr_type)); + + info->l4proto = ext_hdr.ip6r_nxt; return true; } -- cgit v1.2.3 From 50dbce6538d10c8ec9c346fdc0ff76906ae48ebe Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Mon, 30 May 2016 19:25:46 +0200 Subject: net: improve UDP/TCP checksum computation. * based on Eth, UDP, TCP struct present in eth.h instead of hardcoded indexes and sizes. * based on various macros present in eth.h. Signed-off-by: Jean-Christophe Dubois Signed-off-by: Jason Wang --- net/checksum.c | 94 +++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/net/checksum.c b/net/checksum.c index 196aaa3459..39ad73f4b4 100644 --- a/net/checksum.c +++ b/net/checksum.c @@ -18,9 +18,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "net/checksum.h" - -#define PROTO_TCP 6 -#define PROTO_UDP 17 +#include "net/eth.h" uint32_t net_checksum_add_cont(int len, uint8_t *buf, int seq) { @@ -57,40 +55,82 @@ uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto, void net_checksum_calculate(uint8_t *data, int length) { - int hlen, plen, proto, csum_offset; - uint16_t csum; + int ip_len; + struct ip_header *ip; + + /* + * Note: We cannot assume "data" is aligned, so the all code uses + * some macros that take care of possible unaligned access for + * struct members (just in case). + */ /* Ensure data has complete L2 & L3 headers. */ - if (length < 14 + 20) { + if (length < (sizeof(struct eth_header) + sizeof(struct ip_header))) { return; } - if ((data[14] & 0xf0) != 0x40) - return; /* not IPv4 */ - hlen = (data[14] & 0x0f) * 4; - plen = (data[16] << 8 | data[17]) - hlen; - proto = data[23]; - - switch (proto) { - case PROTO_TCP: - csum_offset = 16; - break; - case PROTO_UDP: - csum_offset = 6; - break; - default: - return; + ip = (struct ip_header *)(data + sizeof(struct eth_header)); + + if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { + return; /* not IPv4 */ } - if (plen < csum_offset + 2 || 14 + hlen + plen > length) { + ip_len = lduw_be_p(&ip->ip_len); + + /* Last, check that we have enough data for the all IP frame */ + if (length < ip_len) { return; } - data[14+hlen+csum_offset] = 0; - data[14+hlen+csum_offset+1] = 0; - csum = net_checksum_tcpudp(plen, proto, data+14+12, data+14+hlen); - data[14+hlen+csum_offset] = csum >> 8; - data[14+hlen+csum_offset+1] = csum & 0xff; + ip_len -= IP_HDR_GET_LEN(ip); + + switch (ip->ip_p) { + case IP_PROTO_TCP: + { + uint16_t csum; + tcp_header *tcp = (tcp_header *)(ip + 1); + + if (ip_len < sizeof(tcp_header)) { + return; + } + + /* Set csum to 0 */ + stw_he_p(&tcp->th_sum, 0); + + csum = net_checksum_tcpudp(ip_len, ip->ip_p, + (uint8_t *)&ip->ip_src, + (uint8_t *)tcp); + + /* Store computed csum */ + stw_be_p(&tcp->th_sum, csum); + + break; + } + case IP_PROTO_UDP: + { + uint16_t csum; + udp_header *udp = (udp_header *)(ip + 1); + + if (ip_len < sizeof(udp_header)) { + return; + } + + /* Set csum to 0 */ + stw_he_p(&udp->uh_sum, 0); + + csum = net_checksum_tcpudp(ip_len, ip->ip_p, + (uint8_t *)&ip->ip_src, + (uint8_t *)udp); + + /* Store computed csum */ + stw_be_p(&udp->uh_sum, csum); + + break; + } + default: + /* Can't handle any other protocol */ + break; + } } uint32_t -- cgit v1.2.3 From ade6bad111f74e0e0a8f48de8c8955e7b70be7e3 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Mon, 30 May 2016 19:25:48 +0200 Subject: net: handle optional VLAN header in checksum computation. Signed-off-by: Jean-Christophe Dubois Signed-off-by: Jason Wang --- net/checksum.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/checksum.c b/net/checksum.c index 39ad73f4b4..23323b0760 100644 --- a/net/checksum.c +++ b/net/checksum.c @@ -55,7 +55,7 @@ uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto, void net_checksum_calculate(uint8_t *data, int length) { - int ip_len; + int mac_hdr_len, ip_len; struct ip_header *ip; /* @@ -64,12 +64,39 @@ void net_checksum_calculate(uint8_t *data, int length) * struct members (just in case). */ - /* Ensure data has complete L2 & L3 headers. */ - if (length < (sizeof(struct eth_header) + sizeof(struct ip_header))) { + /* Ensure we have at least an Eth header */ + if (length < sizeof(struct eth_header)) { return; } - ip = (struct ip_header *)(data + sizeof(struct eth_header)); + /* Handle the optionnal VLAN headers */ + switch (lduw_be_p(&PKT_GET_ETH_HDR(data)->h_proto)) { + case ETH_P_VLAN: + mac_hdr_len = sizeof(struct eth_header) + + sizeof(struct vlan_header); + break; + case ETH_P_DVLAN: + if (lduw_be_p(&PKT_GET_VLAN_HDR(data)->h_proto) == ETH_P_VLAN) { + mac_hdr_len = sizeof(struct eth_header) + + 2 * sizeof(struct vlan_header); + } else { + mac_hdr_len = sizeof(struct eth_header) + + sizeof(struct vlan_header); + } + break; + default: + mac_hdr_len = sizeof(struct eth_header); + break; + } + + length -= mac_hdr_len; + + /* Now check we have an IP header (with an optionnal VLAN header) */ + if (length < sizeof(struct ip_header)) { + return; + } + + ip = (struct ip_header *)(data + mac_hdr_len); if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { return; /* not IPv4 */ -- cgit v1.2.3 From 02d0e095031b7fda77de8b558465a57659ea79cb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 6 Jun 2016 13:57:39 +0200 Subject: os-posix: include sys/mman.h qemu/osdep.h checks whether MAP_ANONYMOUS is defined, but this check is bogus without a previous inclusion of sys/mman.h. Include it in sysemu/os-posix.h and remove it from everywhere else. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- net/netmap.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/netmap.c b/net/netmap.c index 6cc0db5ee1..64967b947e 100644 --- a/net/netmap.c +++ b/net/netmap.c @@ -26,7 +26,6 @@ #include "qemu/osdep.h" #include #include -#include #define NETMAP_WITH_LIBS #include #include -- cgit v1.2.3 From a6553598be42e3be899acdb153fd615cd6c3eab8 Mon Sep 17 00:00:00 2001 From: Tetsuya Mukawa Date: Mon, 6 Jun 2016 18:44:59 +0200 Subject: vhost-user: add ability to know vhost-user backend disconnection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current QEMU cannot detect vhost-user backend disconnection. The patch adds ability to know it. To know disconnection, add watcher to detect G_IO_HUP event. When G_IO_HUP event is detected, the disconnected socket will be read to cause a CHR_EVENT_CLOSED. Signed-off-by: Tetsuya Mukawa Reviewed-by: Marc-André Lureau Tested-by: Yuanhan Liu Reviewed-by: Yuanhan Liu Reviewed-by: Victor Kaplansky Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-user.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'net') diff --git a/net/vhost-user.c b/net/vhost-user.c index 1b9e73a2dc..4a7fd5fbd5 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -22,6 +22,7 @@ typedef struct VhostUserState { NetClientState nc; CharDriverState *chr; VHostNetState *vhost_net; + int watch; } VhostUserState; typedef struct VhostUserChardevProps { @@ -167,6 +168,20 @@ static NetClientInfo net_vhost_user_info = { .has_ufo = vhost_user_has_ufo, }; +static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond, + void *opaque) +{ + VhostUserState *s = opaque; + uint8_t buf[1]; + + /* We don't actually want to read anything, but CHR_EVENT_CLOSED will be + * raised as a side-effect of the read. + */ + qemu_chr_fe_read_all(s->chr, buf, sizeof(buf)); + + return FALSE; +} + static void net_vhost_user_event(void *opaque, int event) { const char *name = opaque; @@ -184,6 +199,8 @@ static void net_vhost_user_event(void *opaque, int event) trace_vhost_user_event(s->chr->label, event); switch (event) { case CHR_EVENT_OPENED: + s->watch = qemu_chr_fe_add_watch(s->chr, G_IO_HUP, + net_vhost_user_watch, s); if (vhost_user_start(queues, ncs) < 0) { exit(1); } @@ -192,6 +209,8 @@ static void net_vhost_user_event(void *opaque, int event) case CHR_EVENT_CLOSED: qmp_set_link(name, false, &err); vhost_user_stop(queues, ncs); + g_source_remove(s->watch); + s->watch = 0; break; } -- cgit v1.2.3 From 0d572afd5266d1d67d132d06ea45d7246bcd6105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Jun 2016 18:45:03 +0200 Subject: vhost-user: disconnect on start failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the backend failed to start (for example feature negociation failed), do not exit, but disconnect the char device instead. Slightly more robust for reconnect case. Signed-off-by: Marc-André Lureau Tested-by: Yuanhan Liu Reviewed-by: Yuanhan Liu Reviewed-by: Victor Kaplansky Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-user.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/vhost-user.c b/net/vhost-user.c index 4a7fd5fbd5..41ddb4b9ca 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -202,7 +202,8 @@ static void net_vhost_user_event(void *opaque, int event) s->watch = qemu_chr_fe_add_watch(s->chr, G_IO_HUP, net_vhost_user_watch, s); if (vhost_user_start(queues, ncs) < 0) { - exit(1); + qemu_chr_disconnect(s->chr); + return; } qmp_set_link(name, true, &err); break; -- cgit v1.2.3 From a463215b087c41d7ca94e51aa347cde523831873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Jun 2016 18:45:05 +0200 Subject: vhost-net: save & restore vhost-user acked features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The initial vhost-user connection sets the features to be negotiated with the driver. Renegotiation isn't possible without device reset. To handle reconnection of vhost-user backend, ensure the same set of features are provided, and reuse already acked features. Signed-off-by: Marc-André Lureau Tested-by: Yuanhan Liu Reviewed-by: Yuanhan Liu Reviewed-by: Victor Kaplansky Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-user.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'net') diff --git a/net/vhost-user.c b/net/vhost-user.c index 41ddb4b9ca..d72ce9b490 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -23,6 +23,7 @@ typedef struct VhostUserState { CharDriverState *chr; VHostNetState *vhost_net; int watch; + uint64_t acked_features; } VhostUserState; typedef struct VhostUserChardevProps { @@ -37,6 +38,13 @@ VHostNetState *vhost_user_get_vhost_net(NetClientState *nc) return s->vhost_net; } +uint64_t vhost_user_get_acked_features(NetClientState *nc) +{ + VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); + assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); + return s->acked_features; +} + static int vhost_user_running(VhostUserState *s) { return (s->vhost_net) ? 1 : 0; @@ -56,6 +64,8 @@ static void vhost_user_stop(int queues, NetClientState *ncs[]) } if (s->vhost_net) { + /* save acked features */ + s->acked_features = vhost_net_get_acked_features(s->vhost_net); vhost_net_cleanup(s->vhost_net); s->vhost_net = NULL; } -- cgit v1.2.3 From f3b0163b180b43b2212b0ee680d62142069c8888 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 16 Jun 2016 09:40:21 +0100 Subject: trace: split out trace events for net/ directory Move all trace-events for files in the net/ directory to their own file. Signed-off-by: Daniel P. Berrange Message-id: 1466066426-16657-36-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi --- net/trace-events | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 net/trace-events (limited to 'net') diff --git a/net/trace-events b/net/trace-events new file mode 100644 index 0000000000..32a0a8abb9 --- /dev/null +++ b/net/trace-events @@ -0,0 +1,4 @@ +# See docs/trace-events.txt for syntax documentation. + +# net/vhost-user.c +vhost_user_event(const char *chr, int event) "chr: %s got event: %d" -- cgit v1.2.3 From ca1ee3d6b546e841a1b9db413eb8fa09f13a061b Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Thu, 9 Jun 2016 11:39:27 +0200 Subject: net: fix qemu_announce_self not emitting packets commit fefe2a78 accidently dropped the code path for injecting raw packets. This feature is needed for sending gratuitous ARPs after an incoming migration has completed. The result is increased network downtime for vservers where the network card is not virtio-net with the VIRTIO_NET_F_GUEST_ANNOUNCE feature. Fixes: fefe2a78abde932e0f340b21bded2c86def1d242 Cc: qemu-stable@nongnu.org Cc: hongyang.yang@easystack.cn Signed-off-by: Peter Lieven Signed-off-by: Jason Wang --- net/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/net.c b/net/net.c index 5f3e5a9ff5..75bb1770f9 100644 --- a/net/net.c +++ b/net/net.c @@ -722,7 +722,7 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender, return 0; } - if (nc->info->receive_iov) { + if (nc->info->receive_iov && !(flags & QEMU_NET_PACKET_FLAG_RAW)) { ret = nc->info->receive_iov(nc, iov, iovcnt); } else { ret = nc_sendv_compat(nc, iov, iovcnt, flags); -- cgit v1.2.3 From 7e8449594c92992342512061160bc846c922016d Mon Sep 17 00:00:00 2001 From: Ashijeet Acharya Date: Sat, 18 Jun 2016 13:24:02 +0530 Subject: Change net/socket.c to use socket_*() functions Use socket_*() functions from include/qemu/sockets.h instead of listen()/bind()/connect()/parse_host_port(). socket_*() fucntions are QAPI based and this patch performs this api conversion since everything will be using QAPI based sockets in the future. Also add a helper function socket_address_to_string() in util/qemu-sockets.c which returns the string representation of socket address. Thetask was listed on http://wiki.qemu.org/BiteSizedTasks page. Signed-off-by: Ashijeet Acharya Reviewed-by: Paolo Bonzini Signed-off-by: Jason Wang --- net/socket.c | 55 +++++++++++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index 333fb9ecfa..ae6f92101d 100644 --- a/net/socket.c +++ b/net/socket.c @@ -489,41 +489,30 @@ static int net_socket_listen_init(NetClientState *peer, { NetClientState *nc; NetSocketState *s; - struct sockaddr_in saddr; - int fd, ret; + SocketAddress *saddr; + int ret; + Error *local_error = NULL; - if (parse_host_port(&saddr, host_str) < 0) - return -1; - - fd = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); + saddr = socket_parse(host_str, &local_error); + if (saddr == NULL) { + error_report_err(local_error); return -1; } - qemu_set_nonblock(fd); - socket_set_fast_reuse(fd); - - ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + ret = socket_listen(saddr, &local_error); if (ret < 0) { - perror("bind"); - closesocket(fd); - return -1; - } - ret = listen(fd, 0); - if (ret < 0) { - perror("listen"); - closesocket(fd); + error_report_err(local_error); return -1; } nc = qemu_new_net_client(&net_socket_info, peer, model, name); s = DO_UPCAST(NetSocketState, nc, nc); s->fd = -1; - s->listen_fd = fd; + s->listen_fd = ret; s->nc.link_down = true; qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); + qapi_free_SocketAddress(saddr); return 0; } @@ -534,10 +523,15 @@ static int net_socket_connect_init(NetClientState *peer, { NetSocketState *s; int fd, connected, ret; - struct sockaddr_in saddr; + char *addr_str; + SocketAddress *saddr; + Error *local_error = NULL; - if (parse_host_port(&saddr, host_str) < 0) + saddr = socket_parse(host_str, &local_error); + if (saddr == NULL) { + error_report_err(local_error); return -1; + } fd = qemu_socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { @@ -545,10 +539,9 @@ static int net_socket_connect_init(NetClientState *peer, return -1; } qemu_set_nonblock(fd); - connected = 0; for(;;) { - ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); + ret = socket_connect(saddr, &local_error, NULL, NULL); if (ret < 0) { if (errno == EINTR || errno == EWOULDBLOCK) { /* continue */ @@ -557,7 +550,7 @@ static int net_socket_connect_init(NetClientState *peer, errno == EINVAL) { break; } else { - perror("connect"); + error_report_err(local_error); closesocket(fd); return -1; } @@ -569,9 +562,15 @@ static int net_socket_connect_init(NetClientState *peer, s = net_socket_fd_init(peer, model, name, fd, connected); if (!s) return -1; + + addr_str = socket_address_to_string(saddr, &local_error); + if (addr_str == NULL) + return -1; + snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: connect to %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + "socket: connect to %s", addr_str); + qapi_free_SocketAddress(saddr); + g_free(addr_str); return 0; } -- cgit v1.2.3 From 6f1de6b70d857d5e316ae6fd908f52818b827b08 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 20 Jun 2016 15:02:40 +0200 Subject: char: change qemu_chr_fe_add_watch to return unsigned g_source_attach can return any value between 1 and UINT_MAX if you let QEMU run long enough. However, qemu_chr_fe_add_watch can also return a negative errno value when the device is disconnected or does not support chr_add_watch. Change it to return zero to avoid overloading these values. Fix the cadence_uart which asserts in this case (easily obtained with "-serial pty"). Tested-by: Bret Ketchum Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Paolo Bonzini --- net/vhost-user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/vhost-user.c b/net/vhost-user.c index d72ce9b490..636899a877 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -22,7 +22,7 @@ typedef struct VhostUserState { NetClientState nc; CharDriverState *chr; VHostNetState *vhost_net; - int watch; + guint watch; uint64_t acked_features; } VhostUserState; -- cgit v1.2.3 From 25f0d2aa5e3d21caa1bc622b21368cc2e383f02c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 29 Jun 2016 15:15:33 +0200 Subject: vhost-user: disable chardev handlers on close MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This otherwise causes a use-after-free if network backend cleanup is performed before character device cleanup. Cc: Marc-André Lureau Signed-off-by: Paolo Bonzini --- net/vhost-user.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net') diff --git a/net/vhost-user.c b/net/vhost-user.c index 636899a877..92f4cfd1b1 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -151,6 +151,11 @@ static void vhost_user_cleanup(NetClientState *nc) vhost_net_cleanup(s->vhost_net); s->vhost_net = NULL; } + if (s->chr) { + qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL); + qemu_chr_fe_release(s->chr); + s->chr = NULL; + } qemu_purge_queued_packets(nc); } -- cgit v1.2.3 From 09204eac9bb513e56992c00c75f32f9d4766256b Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 9 Jun 2016 10:48:36 -0600 Subject: opts-visitor: Favor new visit_free() function Now that we have a polymorphic visit_free(), we no longer need opts_visitor_cleanup(); which in turn means we no longer need to return a subtype from opts_visitor_new() nor a public upcast function. Signed-off-by: Eric Blake Message-Id: <1465490926-28625-6-git-send-email-eblake@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- net/net.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/net.c b/net/net.c index 75bb1770f9..d25f80232a 100644 --- a/net/net.c +++ b/net/net.c @@ -1024,8 +1024,7 @@ int net_client_init(QemuOpts *opts, int is_netdev, Error **errp) void *object = NULL; Error *err = NULL; int ret = -1; - OptsVisitor *ov = opts_visitor_new(opts); - Visitor *v = opts_get_visitor(ov); + Visitor *v = opts_visitor_new(opts); { /* Parse convenience option format ip6-net=fec0::0[/64] */ @@ -1075,7 +1074,7 @@ int net_client_init(QemuOpts *opts, int is_netdev, Error **errp) } error_propagate(errp, err); - opts_visitor_cleanup(ov); + visit_free(v); return ret; } -- cgit v1.2.3 From e7ca56562990991bc614a43b9351ee0737f3045d Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 9 Jun 2016 10:48:39 -0600 Subject: string-output-visitor: Favor new visit_free() function Now that we have a polymorphic visit_free(), we no longer need string_output_visitor_cleanup(); however, we still need to expose the subtype for string_output_get_string(). Signed-off-by: Eric Blake Message-Id: <1465490926-28625-9-git-send-email-eblake@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- net/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/net.c b/net/net.c index d25f80232a..336469f9cc 100644 --- a/net/net.c +++ b/net/net.c @@ -1210,7 +1210,7 @@ static void netfilter_print_info(Monitor *mon, NetFilterState *nf) object_property_get(OBJECT(nf), string_output_get_visitor(ov), prop->name, NULL); str = string_output_get_string(ov); - string_output_visitor_cleanup(ov); + visit_free(string_output_get_visitor(ov)); monitor_printf(mon, ",%s=%s", prop->name, str); g_free(str); } -- cgit v1.2.3 From 3b098d56979d2f7fd707c5be85555d114353a28d Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Thu, 9 Jun 2016 10:48:43 -0600 Subject: qapi: Add new visit_complete() function Making each output visitor provide its own output collection function was the only remaining reason for exposing visitor sub-types to the rest of the code base. Add a polymorphic visit_complete() function which is a no-op for input visitors, and which populates an opaque pointer for output visitors. For maximum type-safety, also add a parameter to the output visitor constructors with a type-correct version of the output pointer, and assert that the two uses match. This approach was considered superior to either passing the output parameter only during construction (action at a distance during visit_free() feels awkward) or only during visit_complete() (defeating type safety makes it easier to use incorrectly). Most callers were function-local, and therefore a mechanical conversion; the testsuite was a bit trickier, but the previous cleanup patch minimized the churn here. The visit_complete() function may be called at most once; doing so lets us use transfer semantics rather than duplication or ref-count semantics to get the just-built output back to the caller, even though it means our behavior is not idempotent. Generated code is simplified as follows for events: |@@ -26,7 +26,7 @@ void qapi_event_send_acpi_device_ost(ACP | QDict *qmp; | Error *err = NULL; | QMPEventFuncEmit emit; |- QmpOutputVisitor *qov; |+ QObject *obj; | Visitor *v; | q_obj_ACPI_DEVICE_OST_arg param = { | info |@@ -39,8 +39,7 @@ void qapi_event_send_acpi_device_ost(ACP | | qmp = qmp_event_build_dict("ACPI_DEVICE_OST"); | |- qov = qmp_output_visitor_new(); |- v = qmp_output_get_visitor(qov); |+ v = qmp_output_visitor_new(&obj); | | visit_start_struct(v, "ACPI_DEVICE_OST", NULL, 0, &err); | if (err) { |@@ -55,7 +54,8 @@ void qapi_event_send_acpi_device_ost(ACP | goto out; | } | |- qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov)); |+ visit_complete(v, &obj); |+ qdict_put_obj(qmp, "data", obj); | emit(QAPI_EVENT_ACPI_DEVICE_OST, qmp, &err); and for commands: | { | Error *err = NULL; |- QmpOutputVisitor *qov = qmp_output_visitor_new(); | Visitor *v; | |- v = qmp_output_get_visitor(qov); |+ v = qmp_output_visitor_new(ret_out); | visit_type_AddfdInfo(v, "unused", &ret_in, &err); |- if (err) { |- goto out; |+ if (!err) { |+ visit_complete(v, ret_out); | } |- *ret_out = qmp_output_get_qobject(qov); |- |-out: | error_propagate(errp, err); Signed-off-by: Eric Blake Message-Id: <1465490926-28625-13-git-send-email-eblake@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- net/net.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/net.c b/net/net.c index 336469f9cc..019aaad0fc 100644 --- a/net/net.c +++ b/net/net.c @@ -1198,7 +1198,7 @@ static void netfilter_print_info(Monitor *mon, NetFilterState *nf) char *str; ObjectProperty *prop; ObjectPropertyIterator iter; - StringOutputVisitor *ov; + Visitor *v; /* generate info str */ object_property_iter_init(&iter, OBJECT(nf)); @@ -1206,11 +1206,10 @@ static void netfilter_print_info(Monitor *mon, NetFilterState *nf) if (!strcmp(prop->name, "type")) { continue; } - ov = string_output_visitor_new(false); - object_property_get(OBJECT(nf), string_output_get_visitor(ov), - prop->name, NULL); - str = string_output_get_string(ov); - visit_free(string_output_get_visitor(ov)); + v = string_output_visitor_new(false, &str); + object_property_get(OBJECT(nf), v, prop->name, NULL); + visit_complete(v, &str); + visit_free(v); monitor_printf(mon, ",%s=%s", prop->name, str); g_free(str); } -- cgit v1.2.3 From 69e87b32680a41d9761191443587c595b6f5fc3f Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 6 Jul 2016 09:57:55 +0800 Subject: tap: vhost busy polling support This patch add the capability of basic vhost net busy polling which is supported by recent kernel. User could configure the maximum number of us that could be spent on busy polling through a new property of tap "poll-us". Cc: Greg Kurz Reviewed-by: Michael S. Tsirkin Signed-off-by: Jason Wang --- net/tap.c | 7 ++++++- net/vhost-user.c | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/tap.c b/net/tap.c index 49817c70c1..676bad4e11 100644 --- a/net/tap.c +++ b/net/tap.c @@ -663,6 +663,11 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, options.backend_type = VHOST_BACKEND_TYPE_KERNEL; options.net_backend = &s->nc; + if (tap->has_poll_us) { + options.busyloop_timeout = tap->poll_us; + } else { + options.busyloop_timeout = 0; + } if (vhostfdname) { vhostfd = monitor_fd_param(cur_mon, vhostfdname, &err); @@ -687,7 +692,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, return; } } else if (vhostfdname) { - error_setg(errp, "vhostfd= is not valid without vhost"); + error_setg(errp, "vhostfd(s)= is not valid without vhost"); } } diff --git a/net/vhost-user.c b/net/vhost-user.c index 92f4cfd1b1..a88dfe0655 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -91,6 +91,7 @@ static int vhost_user_start(int queues, NetClientState *ncs[]) options.net_backend = ncs[i]; options.opaque = s->chr; + options.busyloop_timeout = 0; s->vhost_net = vhost_net_init(&options); if (!s->vhost_net) { error_report("failed to init vhost_net for queue %d", i); -- cgit v1.2.3 From 121d07125bb6d7079c7ebafdd3efe8c3a01cc440 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 29 Jun 2016 10:12:57 +0200 Subject: Clean up header guards that don't match their file name Header guard symbols should match their file name to make guard collisions less likely. Offenders found with scripts/clean-header-guards.pl -vn. Cleaned up with scripts/clean-header-guards.pl, followed by some renaming of new guard symbols picked by the script to better ones. Signed-off-by: Markus Armbruster Reviewed-by: Richard Henderson --- net/tap_int.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/tap_int.h b/net/tap_int.h index 2378021c45..ae6888f74a 100644 --- a/net/tap_int.h +++ b/net/tap_int.h @@ -23,8 +23,8 @@ * THE SOFTWARE. */ -#ifndef QEMU_TAP_H -#define QEMU_TAP_H +#ifndef NET_TAP_INT_H +#define NET_TAP_INT_H #include "qemu-common.h" #include "qapi-types.h" @@ -46,4 +46,4 @@ int tap_fd_enable(int fd); int tap_fd_disable(int fd); int tap_fd_get_ifname(int fd, char *ifname); -#endif /* QEMU_TAP_H */ +#endif /* NET_TAP_INT_H */ -- cgit v1.2.3 From 175de52487ce0b0c78daa4cdf41a5a465a168a25 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 29 Jun 2016 15:29:06 +0200 Subject: Clean up decorations and whitespace around header guards Cleaned up with scripts/clean-header-guards.pl. Signed-off-by: Markus Armbruster Reviewed-by: Richard Henderson --- net/tap-linux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/tap-linux.h b/net/tap-linux.h index 1dc3a9f279..2f36d100fc 100644 --- a/net/tap-linux.h +++ b/net/tap-linux.h @@ -50,4 +50,4 @@ #define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */ #define TUN_F_UFO 0x10 /* I can handle UFO packets */ -#endif /* QEMU_TAP_H */ +#endif /* QEMU_TAP_LINUX_H */ -- cgit v1.2.3 From 9e32ff32995f8c18f85f20e28ef09bae4ff2e48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 11 Jul 2016 16:48:47 +0200 Subject: tap: use an exit notifier to call down_script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We would like to move back net_cleanup() at the end of main function, like it used to be until f30dbae63a46f23116715dff8d130c, but minimum tap cleanup is necessary regarless at exit() time. Use an exit notifier to call TAP down_script. If net_cleanup() is called first, then remove the exit notifier as it will become a dangling pointer otherwise. Signed-off-by: Marc-André Lureau Suggested-by: Paolo Bonzini Message-Id: <20160711144847.16651-1-marcandre.lureau@redhat.com> Reviewed-by: Jason Wang Signed-off-by: Paolo Bonzini --- net/tap.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/tap.c b/net/tap.c index 676bad4e11..e9c32f3a44 100644 --- a/net/tap.c +++ b/net/tap.c @@ -58,6 +58,7 @@ typedef struct TAPState { bool enabled; VHostNetState *vhost_net; unsigned host_vnet_hdr_len; + Notifier exit; } TAPState; static void launch_script(const char *setup_script, const char *ifname, @@ -292,10 +293,22 @@ static void tap_set_offload(NetClientState *nc, int csum, int tso4, tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo); } +static void tap_exit_notify(Notifier *notifier, void *data) +{ + TAPState *s = container_of(notifier, TAPState, exit); + Error *err = NULL; + + if (s->down_script[0]) { + launch_script(s->down_script, s->down_script_arg, s->fd, &err); + if (err) { + error_report_err(err); + } + } +} + static void tap_cleanup(NetClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - Error *err = NULL; if (s->vhost_net) { vhost_net_cleanup(s->vhost_net); @@ -304,12 +317,8 @@ static void tap_cleanup(NetClientState *nc) qemu_purge_queued_packets(nc); - if (s->down_script[0]) { - launch_script(s->down_script, s->down_script_arg, s->fd, &err); - if (err) { - error_report_err(err); - } - } + tap_exit_notify(&s->exit, NULL); + qemu_remove_exit_notifier(&s->exit); tap_read_poll(s, false); tap_write_poll(s, false); @@ -379,6 +388,10 @@ static TAPState *net_tap_fd_init(NetClientState *peer, } tap_read_poll(s, true); s->vhost_net = NULL; + + s->exit.notify = tap_exit_notify; + qemu_add_exit_notifier(&s->exit); + return s; } -- cgit v1.2.3 From f6c2e66ae8c8a03d3044dc9054aa7c16e7f817ee Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 12 Jul 2016 09:57:12 +0200 Subject: slirp: use exit notifier for slirp_smb_cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We would like to move back net_cleanup() at the end of main function, like it used to be until f30dbae63a46f23116715dff8d130c, but minimum cleanup is needed regardless at exit() time for slirp's SMB functionality. Use an exit notifier to call slirp_smb_cleanup. If net_cleanup() is called first, then remove the exit notifier as it will become a dangling pointer otherwise. Reviewed-by: Marc-André Lureau Reviewed-by: Jason Wang Signed-off-by: Paolo Bonzini --- net/slirp.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'net') diff --git a/net/slirp.c b/net/slirp.c index 31630f005c..28207b6614 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -38,6 +38,7 @@ #include "slirp/libslirp.h" #include "slirp/ip6.h" #include "sysemu/char.h" +#include "sysemu/sysemu.h" #include "qemu/cutils.h" static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) @@ -76,6 +77,7 @@ typedef struct SlirpState { NetClientState nc; QTAILQ_ENTRY(SlirpState) entry; Slirp *slirp; + Notifier exit_notifier; #ifndef _WIN32 char smb_dir[128]; #endif @@ -118,11 +120,18 @@ static ssize_t net_slirp_receive(NetClientState *nc, const uint8_t *buf, size_t return size; } +static void slirp_smb_exit(Notifier *n, void *data) +{ + SlirpState *s = container_of(n, SlirpState, exit_notifier); + slirp_smb_cleanup(s); +} + static void net_slirp_cleanup(NetClientState *nc) { SlirpState *s = DO_UPCAST(SlirpState, nc, nc); slirp_cleanup(s->slirp); + qemu_remove_exit_notifier(&s->exit_notifier); slirp_smb_cleanup(s); QTAILQ_REMOVE(&slirp_stacks, s, entry); } @@ -349,6 +358,8 @@ static int net_slirp_init(NetClientState *peer, const char *model, } #endif + s->exit_notifier.notify = slirp_smb_exit; + qemu_add_exit_notifier(&s->exit_notifier); return 0; error: -- cgit v1.2.3 From 2c5e564f4d8309ee0f47029ab461c4c4459f43c4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 15 Jul 2016 10:43:32 +0200 Subject: net: fix incorrect access to pointer This is not dereferencing the pointer, and instead checking only the value of the pointer. Signed-off-by: Paolo Bonzini Signed-off-by: Jason Wang --- net/eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/eth.c b/net/eth.c index 95fe15c23f..c147c2ebb3 100644 --- a/net/eth.c +++ b/net/eth.c @@ -211,7 +211,7 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt, *l4hdr_off, sizeof(l4hdr_info->hdr.tcp), &l4hdr_info->hdr.tcp); - if (istcp) { + if (*istcp) { *l5hdr_off = *l4hdr_off + TCP_HEADER_DATA_OFFSET(&l4hdr_info->hdr.tcp); -- cgit v1.2.3 From 4555ca6816c7868323ce2f0138c83e8f9b696622 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 15 Jul 2016 10:41:47 +0200 Subject: net: fix incorrect argument to iov_to_buf Coverity reports a "suspicious sizeof" which is indeed wrong. Signed-off-by: Paolo Bonzini Signed-off-by: Jason Wang --- net/eth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/eth.c b/net/eth.c index c147c2ebb3..df81efb676 100644 --- a/net/eth.c +++ b/net/eth.c @@ -418,7 +418,7 @@ _eth_get_rss_ex_dst_addr(const struct iovec *pkt, int pkt_frags, bytes_read = iov_to_buf(pkt, pkt_frags, rthdr_offset + sizeof(*ext_hdr), - dst_addr, sizeof(dst_addr)); + dst_addr, sizeof(*dst_addr)); return bytes_read == sizeof(dst_addr); } @@ -467,7 +467,7 @@ _eth_get_rss_ex_src_addr(const struct iovec *pkt, int pkt_frags, bytes_read = iov_to_buf(pkt, pkt_frags, opt_offset + sizeof(opthdr), - src_addr, sizeof(src_addr)); + src_addr, sizeof(*src_addr)); return bytes_read == sizeof(src_addr); } -- cgit v1.2.3 From 091a6b2acfea84c81154ce30e67689cbd731edf1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 15 Jul 2016 10:56:07 +0200 Subject: tap: fix memory leak on failure to create a multiqueue tap device Reported by Coverity. Signed-off-by: Paolo Bonzini Signed-off-by: Jason Wang --- net/tap.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/tap.c b/net/tap.c index e9c32f3a44..6a2cedcfb1 100644 --- a/net/tap.c +++ b/net/tap.c @@ -787,8 +787,8 @@ int net_init_tap(const NetClientOptions *opts, const char *name, return -1; } } else if (tap->has_fds) { - char **fds = g_new(char *, MAX_TAP_QUEUES); - char **vhost_fds = g_new(char *, MAX_TAP_QUEUES); + char **fds = g_new0(char *, MAX_TAP_QUEUES); + char **vhost_fds = g_new0(char *, MAX_TAP_QUEUES); int nfds, nvhosts; if (tap->has_ifname || tap->has_script || tap->has_downscript || @@ -806,7 +806,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name, if (nfds != nvhosts) { error_setg(errp, "The number of fds passed does not match " "the number of vhostfds passed"); - return -1; + goto free_fail; } } @@ -814,7 +814,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name, fd = monitor_fd_param(cur_mon, fds[i], &err); if (fd == -1) { error_propagate(errp, err); - return -1; + goto free_fail; } fcntl(fd, F_SETFL, O_NONBLOCK); @@ -824,7 +824,7 @@ int net_init_tap(const NetClientOptions *opts, const char *name, } else if (vnet_hdr != tap_probe_vnet_hdr(fd)) { error_setg(errp, "vnet_hdr not consistent across given tap fds"); - return -1; + goto free_fail; } net_init_tap_one(tap, peer, "tap", name, ifname, @@ -833,11 +833,21 @@ int net_init_tap(const NetClientOptions *opts, const char *name, vnet_hdr, fd, &err); if (err) { error_propagate(errp, err); - return -1; + goto free_fail; } } g_free(fds); g_free(vhost_fds); + return 0; + +free_fail: + for (i = 0; i < nfds; i++) { + g_free(fds[i]); + g_free(vhost_fds[i]); + } + g_free(fds); + g_free(vhost_fds); + return -1; } else if (tap->has_helper) { if (tap->has_ifname || tap->has_script || tap->has_downscript || tap->has_vnet_hdr || tap->has_queues || tap->has_vhostfds) { -- cgit v1.2.3 From cebea510579ed43724156cc596a8ff14ba208740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?= Date: Wed, 13 Jul 2016 21:50:12 -0600 Subject: net: use Netdev instead of NetClientOptions in client init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way we no longer need NetClientOptions and can convert Netdev into a flat union. Signed-off-by: Kővágó, Zoltán Reviewed-by: Eric Blake Message-Id: <93ffdfed7054529635e6acb935150d95dc173a12.1441627176.git.DirtY.iCE.hu@gmail.com> [rework net_client_init1() to pass Netdev by copying from NetdevLegacy, rather than merging the two types - which means that we still need NetClientOptions after all. Rebase to qapi changes. The bulk of the patch is mechanical, replacing 'opts' by 'netdev->opts', while net_client_init1() takes care of converting between legacy and modern types.] Signed-off-by: Eric Blake Message-Id: <1468468228-27827-2-git-send-email-eblake@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- net/clients.h | 20 ++++++++++---------- net/dump.c | 6 +++--- net/hub.c | 6 +++--- net/l2tpv3.c | 6 +++--- net/net.c | 18 +++++++++++------- net/netmap.c | 4 ++-- net/slirp.c | 6 +++--- net/socket.c | 6 +++--- net/tap-win32.c | 6 +++--- net/tap.c | 12 ++++++------ net/vde.c | 6 +++--- net/vhost-user.c | 6 +++--- 12 files changed, 53 insertions(+), 49 deletions(-) (limited to 'net') diff --git a/net/clients.h b/net/clients.h index d47530e82f..5cae479730 100644 --- a/net/clients.h +++ b/net/clients.h @@ -27,39 +27,39 @@ #include "net/net.h" #include "qapi-types.h" -int net_init_dump(const NetClientOptions *opts, const char *name, +int net_init_dump(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); #ifdef CONFIG_SLIRP -int net_init_slirp(const NetClientOptions *opts, const char *name, +int net_init_slirp(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); #endif -int net_init_hubport(const NetClientOptions *opts, const char *name, +int net_init_hubport(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); -int net_init_socket(const NetClientOptions *opts, const char *name, +int net_init_socket(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); -int net_init_tap(const NetClientOptions *opts, const char *name, +int net_init_tap(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); -int net_init_bridge(const NetClientOptions *opts, const char *name, +int net_init_bridge(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); -int net_init_l2tpv3(const NetClientOptions *opts, const char *name, +int net_init_l2tpv3(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); #ifdef CONFIG_VDE -int net_init_vde(const NetClientOptions *opts, const char *name, +int net_init_vde(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); #endif #ifdef CONFIG_NETMAP -int net_init_netmap(const NetClientOptions *opts, const char *name, +int net_init_netmap(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); #endif -int net_init_vhost_user(const NetClientOptions *opts, const char *name, +int net_init_vhost_user(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); #endif /* QEMU_NET_CLIENTS_H */ diff --git a/net/dump.c b/net/dump.c index 41f7673efd..f8a500f715 100644 --- a/net/dump.c +++ b/net/dump.c @@ -179,7 +179,7 @@ static NetClientInfo net_dump_info = { .cleanup = dumpclient_cleanup, }; -int net_init_dump(const NetClientOptions *opts, const char *name, +int net_init_dump(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { int len, rc; @@ -189,8 +189,8 @@ int net_init_dump(const NetClientOptions *opts, const char *name, NetClientState *nc; DumpNetClient *dnc; - assert(opts->type == NET_CLIENT_OPTIONS_KIND_DUMP); - dump = opts->u.dump.data; + assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_DUMP); + dump = netdev->opts->u.dump.data; assert(peer); diff --git a/net/hub.c b/net/hub.c index 6d90c6ee67..ec4626f2c0 100644 --- a/net/hub.c +++ b/net/hub.c @@ -281,14 +281,14 @@ int net_hub_id_for_client(NetClientState *nc, int *id) return 0; } -int net_init_hubport(const NetClientOptions *opts, const char *name, +int net_init_hubport(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { const NetdevHubPortOptions *hubport; - assert(opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT); + assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT); assert(!peer); - hubport = opts->u.hubport.data; + hubport = netdev->opts->u.hubport.data; net_hub_add_port(hubport->hubid, name); return 0; diff --git a/net/l2tpv3.c b/net/l2tpv3.c index 5c668f7376..df02f5bdcc 100644 --- a/net/l2tpv3.c +++ b/net/l2tpv3.c @@ -524,7 +524,7 @@ static NetClientInfo net_l2tpv3_info = { .cleanup = net_l2tpv3_cleanup, }; -int net_init_l2tpv3(const NetClientOptions *opts, +int net_init_l2tpv3(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { @@ -545,8 +545,8 @@ int net_init_l2tpv3(const NetClientOptions *opts, s->queue_tail = 0; s->header_mismatch = false; - assert(opts->type == NET_CLIENT_OPTIONS_KIND_L2TPV3); - l2tpv3 = opts->u.l2tpv3.data; + assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_L2TPV3); + l2tpv3 = netdev->opts->u.l2tpv3.data; if (l2tpv3->has_ipv6 && l2tpv3->ipv6) { s->ipv6 = l2tpv3->ipv6; diff --git a/net/net.c b/net/net.c index 019aaad0fc..d80fd82210 100644 --- a/net/net.c +++ b/net/net.c @@ -862,15 +862,15 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models, return -1; } -static int net_init_nic(const NetClientOptions *opts, const char *name, +static int net_init_nic(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { int idx; NICInfo *nd; const NetLegacyNicOptions *nic; - assert(opts->type == NET_CLIENT_OPTIONS_KIND_NIC); - nic = opts->u.nic.data; + assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_NIC); + nic = netdev->opts->u.nic.data; idx = nic_get_free_idx(); if (idx == -1 || nb_nics >= MAX_NICS) { @@ -931,7 +931,7 @@ static int net_init_nic(const NetClientOptions *opts, const char *name, static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND__MAX])( - const NetClientOptions *opts, + const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) = { [NET_CLIENT_OPTIONS_KIND_NIC] = net_init_nic, @@ -963,11 +963,13 @@ static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND__MAX])( static int net_client_init1(const void *object, int is_netdev, Error **errp) { const NetClientOptions *opts; + Netdev legacy = {0}; + const Netdev *netdev; const char *name; NetClientState *peer = NULL; if (is_netdev) { - const Netdev *netdev = object; + netdev = object; opts = netdev->opts; name = netdev->id; @@ -980,7 +982,9 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp) } } else { const NetLegacy *net = object; - opts = net->opts; + legacy.id = net->id; + opts = legacy.opts = net->opts; + netdev = &legacy; /* missing optional values have been initialized to "all bits zero" */ name = net->has_id ? net->id : net->name; @@ -1007,7 +1011,7 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp) } } - if (net_client_init_fun[opts->type](opts, name, peer, errp) < 0) { + if (net_client_init_fun[opts->type](netdev, name, peer, errp) < 0) { /* FIXME drop when all init functions store an Error */ if (errp && !*errp) { error_setg(errp, QERR_DEVICE_INIT_FAILED, diff --git a/net/netmap.c b/net/netmap.c index 64967b947e..beb8d2841c 100644 --- a/net/netmap.c +++ b/net/netmap.c @@ -418,10 +418,10 @@ static NetClientInfo net_netmap_info = { * * ... -net netmap,ifname="..." */ -int net_init_netmap(const NetClientOptions *opts, +int net_init_netmap(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { - const NetdevNetmapOptions *netmap_opts = opts->u.netmap.data; + const NetdevNetmapOptions *netmap_opts = netdev->opts->u.netmap.data; struct nm_desc *nmd; NetClientState *nc; Error *err = NULL; diff --git a/net/slirp.c b/net/slirp.c index 28207b6614..ca34badb76 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -828,7 +828,7 @@ static const char **slirp_dnssearch(const StringList *dnsname) return ret; } -int net_init_slirp(const NetClientOptions *opts, const char *name, +int net_init_slirp(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { /* FIXME error_setg(errp, ...) on failure */ @@ -839,8 +839,8 @@ int net_init_slirp(const NetClientOptions *opts, const char *name, const char **dnssearch; bool ipv4 = true, ipv6 = true; - assert(opts->type == NET_CLIENT_OPTIONS_KIND_USER); - user = opts->u.user.data; + assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_USER); + user = netdev->opts->u.user.data; if ((user->has_ipv6 && user->ipv6 && !user->has_ipv4) || (user->has_ipv4 && !user->ipv4)) { diff --git a/net/socket.c b/net/socket.c index ae6f92101d..6e5c902ea9 100644 --- a/net/socket.c +++ b/net/socket.c @@ -663,15 +663,15 @@ static int net_socket_udp_init(NetClientState *peer, return 0; } -int net_init_socket(const NetClientOptions *opts, const char *name, +int net_init_socket(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { /* FIXME error_setg(errp, ...) on failure */ Error *err = NULL; const NetdevSocketOptions *sock; - assert(opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET); - sock = opts->u.socket.data; + assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET); + sock = netdev->opts->u.socket.data; if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast + sock->has_udp != 1) { diff --git a/net/tap-win32.c b/net/tap-win32.c index f1e142ace6..0f23b19c96 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -788,14 +788,14 @@ static int tap_win32_init(NetClientState *peer, const char *model, return 0; } -int net_init_tap(const NetClientOptions *opts, const char *name, +int net_init_tap(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { /* FIXME error_setg(errp, ...) on failure */ const NetdevTapOptions *tap; - assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP); - tap = opts->u.tap.data; + assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_TAP); + tap = netdev->opts->u.tap.data; if (!tap->has_ifname) { error_report("tap: no interface name"); diff --git a/net/tap.c b/net/tap.c index e9c32f3a44..ceb8c43821 100644 --- a/net/tap.c +++ b/net/tap.c @@ -571,7 +571,7 @@ static int net_bridge_run_helper(const char *helper, const char *bridge, } } -int net_init_bridge(const NetClientOptions *opts, const char *name, +int net_init_bridge(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { const NetdevBridgeOptions *bridge; @@ -579,8 +579,8 @@ int net_init_bridge(const NetClientOptions *opts, const char *name, TAPState *s; int fd, vnet_hdr; - assert(opts->type == NET_CLIENT_OPTIONS_KIND_BRIDGE); - bridge = opts->u.bridge.data; + assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_BRIDGE); + bridge = netdev->opts->u.bridge.data; helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER; br = bridge->has_br ? bridge->br : DEFAULT_BRIDGE_INTERFACE; @@ -735,7 +735,7 @@ static int get_fds(char *str, char *fds[], int max) return i; } -int net_init_tap(const NetClientOptions *opts, const char *name, +int net_init_tap(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { const NetdevTapOptions *tap; @@ -747,8 +747,8 @@ int net_init_tap(const NetClientOptions *opts, const char *name, const char *vhostfdname; char ifname[128]; - assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP); - tap = opts->u.tap.data; + assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_TAP); + tap = netdev->opts->u.tap.data; queues = tap->has_queues ? tap->queues : 1; vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL; diff --git a/net/vde.c b/net/vde.c index 9427eaa16f..53cdbbf0ea 100644 --- a/net/vde.c +++ b/net/vde.c @@ -109,14 +109,14 @@ static int net_vde_init(NetClientState *peer, const char *model, return 0; } -int net_init_vde(const NetClientOptions *opts, const char *name, +int net_init_vde(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { /* FIXME error_setg(errp, ...) on failure */ const NetdevVdeOptions *vde; - assert(opts->type == NET_CLIENT_OPTIONS_KIND_VDE); - vde = opts->u.vde.data; + assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_VDE); + vde = netdev->opts->u.vde.data; /* missing optional values have been initialized to "all bits zero" */ if (net_vde_init(peer, "vde", name, vde->sock, vde->port, vde->group, diff --git a/net/vhost-user.c b/net/vhost-user.c index a88dfe0655..dfdcca221c 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -334,15 +334,15 @@ static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp) return 0; } -int net_init_vhost_user(const NetClientOptions *opts, const char *name, +int net_init_vhost_user(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { int queues; const NetdevVhostUserOptions *vhost_user_opts; CharDriverState *chr; - assert(opts->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); - vhost_user_opts = opts->u.vhost_user.data; + assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); + vhost_user_opts = netdev->opts->u.vhost_user.data; chr = net_vhost_parse_chardev(vhost_user_opts, errp); if (!chr) { -- cgit v1.2.3 From f394b2e20d9a666fb194fb692179a0eeaca5daea Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 13 Jul 2016 21:50:23 -0600 Subject: qapi: Change Netdev into a flat union MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a mostly-mechanical conversion that creates a new flat union 'Netdev' QAPI type that covers all the branches of the former 'NetClientOptions' simple union, where the branches are now listed in a new 'NetClientDriver' enum rather than generated from the simple union. The existence of a flat union has no change to the command line syntax accepted for new code, and will make it possible for a future patch to switch the QMP command to parse a boxed union for no change to valid QMP; but it does have some ripple effect on the C code when dealing with the new types. While making the conversion, note that the 'NetLegacy' type remains unchanged: it applies only to legacy command line options, and will not be ported to QMP, so it should remain a wrapper around a simple union; to avoid confusion, the type named 'NetClientOptions' is now gone, and we introduce 'NetLegacyOptions' in its place. Then, in the C code, we convert from NetLegacy to Netdev as soon as possible, so that the bulk of the net stack only has to deal with one QAPI type, not two. Note that since the old legacy code always rejected 'hubport', we can just omit that branch from the new 'NetLegacyOptions' simple union. Based on an idea originally by Zoltán Kővágó : Message-Id: <01a527fbf1a5de880091f98cf011616a78adeeee.1441627176.git.DirtY.iCE.hu@gmail.com> although the sed script in that patch no longer applies due to other changes in the tree since then, and I also did some manual cleanups (such as fixing whitespace to keep checkpatch happy). Signed-off-by: Eric Blake Message-Id: <1468468228-27827-13-git-send-email-eblake@redhat.com> Reviewed-by: Markus Armbruster [Fixup from Eric squashed in] Signed-off-by: Markus Armbruster --- net/dump.c | 6 +-- net/filter.c | 2 +- net/hub.c | 22 ++++----- net/l2tpv3.c | 6 +-- net/net.c | 133 +++++++++++++++++++++++++++++++++++-------------------- net/netmap.c | 4 +- net/slirp.c | 6 +-- net/socket.c | 8 ++-- net/tap-win32.c | 6 +-- net/tap.c | 24 +++++----- net/vde.c | 6 +-- net/vhost-user.c | 20 ++++----- 12 files changed, 140 insertions(+), 103 deletions(-) (limited to 'net') diff --git a/net/dump.c b/net/dump.c index f8a500f715..89a149b5dd 100644 --- a/net/dump.c +++ b/net/dump.c @@ -172,7 +172,7 @@ static void dumpclient_cleanup(NetClientState *nc) } static NetClientInfo net_dump_info = { - .type = NET_CLIENT_OPTIONS_KIND_DUMP, + .type = NET_CLIENT_DRIVER_DUMP, .size = sizeof(DumpNetClient), .receive = dumpclient_receive, .receive_iov = dumpclient_receive_iov, @@ -189,8 +189,8 @@ int net_init_dump(const Netdev *netdev, const char *name, NetClientState *nc; DumpNetClient *dnc; - assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_DUMP); - dump = netdev->opts->u.dump.data; + assert(netdev->type == NET_CLIENT_DRIVER_DUMP); + dump = &netdev->u.dump; assert(peer); diff --git a/net/filter.c b/net/filter.c index 8ac79f3b7b..888fe6dd93 100644 --- a/net/filter.c +++ b/net/filter.c @@ -201,7 +201,7 @@ static void netfilter_complete(UserCreatable *uc, Error **errp) } queues = qemu_find_net_clients_except(nf->netdev_id, ncs, - NET_CLIENT_OPTIONS_KIND_NIC, + NET_CLIENT_DRIVER_NIC, MAX_QUEUE_NUM); if (queues < 1) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "netdev", diff --git a/net/hub.c b/net/hub.c index ec4626f2c0..32d8cf5cd4 100644 --- a/net/hub.c +++ b/net/hub.c @@ -131,7 +131,7 @@ static void net_hub_port_cleanup(NetClientState *nc) } static NetClientInfo net_hub_port_info = { - .type = NET_CLIENT_OPTIONS_KIND_HUBPORT, + .type = NET_CLIENT_DRIVER_HUBPORT, .size = sizeof(NetHubPort), .can_receive = net_hub_port_can_receive, .receive = net_hub_port_receive, @@ -266,10 +266,10 @@ int net_hub_id_for_client(NetClientState *nc, int *id) { NetHubPort *port; - if (nc->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) { + if (nc->info->type == NET_CLIENT_DRIVER_HUBPORT) { port = DO_UPCAST(NetHubPort, nc, nc); } else if (nc->peer != NULL && nc->peer->info->type == - NET_CLIENT_OPTIONS_KIND_HUBPORT) { + NET_CLIENT_DRIVER_HUBPORT) { port = DO_UPCAST(NetHubPort, nc, nc->peer); } else { return -ENOENT; @@ -286,9 +286,9 @@ int net_init_hubport(const Netdev *netdev, const char *name, { const NetdevHubPortOptions *hubport; - assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT); + assert(netdev->type == NET_CLIENT_DRIVER_HUBPORT); assert(!peer); - hubport = netdev->opts->u.hubport.data; + hubport = &netdev->u.hubport; net_hub_add_port(hubport->hubid, name); return 0; @@ -315,14 +315,14 @@ void net_hub_check_clients(void) } switch (peer->info->type) { - case NET_CLIENT_OPTIONS_KIND_NIC: + case NET_CLIENT_DRIVER_NIC: has_nic = 1; break; - case NET_CLIENT_OPTIONS_KIND_USER: - case NET_CLIENT_OPTIONS_KIND_TAP: - case NET_CLIENT_OPTIONS_KIND_SOCKET: - case NET_CLIENT_OPTIONS_KIND_VDE: - case NET_CLIENT_OPTIONS_KIND_VHOST_USER: + case NET_CLIENT_DRIVER_USER: + case NET_CLIENT_DRIVER_TAP: + case NET_CLIENT_DRIVER_SOCKET: + case NET_CLIENT_DRIVER_VDE: + case NET_CLIENT_DRIVER_VHOST_USER: has_host_dev = 1; break; default: diff --git a/net/l2tpv3.c b/net/l2tpv3.c index df02f5bdcc..6745b78990 100644 --- a/net/l2tpv3.c +++ b/net/l2tpv3.c @@ -516,7 +516,7 @@ static void net_l2tpv3_cleanup(NetClientState *nc) } static NetClientInfo net_l2tpv3_info = { - .type = NET_CLIENT_OPTIONS_KIND_L2TPV3, + .type = NET_CLIENT_DRIVER_L2TPV3, .size = sizeof(NetL2TPV3State), .receive = net_l2tpv3_receive_dgram, .receive_iov = net_l2tpv3_receive_dgram_iov, @@ -545,8 +545,8 @@ int net_init_l2tpv3(const Netdev *netdev, s->queue_tail = 0; s->header_mismatch = false; - assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_L2TPV3); - l2tpv3 = netdev->opts->u.l2tpv3.data; + assert(netdev->type == NET_CLIENT_DRIVER_L2TPV3); + l2tpv3 = &netdev->u.l2tpv3; if (l2tpv3->has_ipv6 && l2tpv3->ipv6) { s->ipv6 = l2tpv3->ipv6; diff --git a/net/net.c b/net/net.c index d80fd82210..4a7f392baf 100644 --- a/net/net.c +++ b/net/net.c @@ -289,7 +289,7 @@ NICState *qemu_new_nic(NetClientInfo *info, NICState *nic; int i, queues = MAX(1, conf->peers.queues); - assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC); + assert(info->type == NET_CLIENT_DRIVER_NIC); assert(info->size >= sizeof(NICState)); nic = g_malloc0(info->size + sizeof(NetClientState) * queues); @@ -360,13 +360,13 @@ void qemu_del_net_client(NetClientState *nc) int queues, i; NetFilterState *nf, *next; - assert(nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC); + assert(nc->info->type != NET_CLIENT_DRIVER_NIC); /* If the NetClientState belongs to a multiqueue backend, we will change all * other NetClientStates also. */ queues = qemu_find_net_clients_except(nc->name, ncs, - NET_CLIENT_OPTIONS_KIND_NIC, + NET_CLIENT_DRIVER_NIC, MAX_QUEUE_NUM); assert(queues != 0); @@ -375,7 +375,7 @@ void qemu_del_net_client(NetClientState *nc) } /* If there is a peer NIC, delete and cleanup client, but do not free. */ - if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { NICState *nic = qemu_get_nic(nc->peer); if (nic->peer_deleted) { return; @@ -431,7 +431,7 @@ void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) NetClientState *nc; QTAILQ_FOREACH(nc, &net_clients, next) { - if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { + if (nc->info->type == NET_CLIENT_DRIVER_NIC) { if (nc->queue_index == 0) { func(qemu_get_nic(nc), opaque); } @@ -603,7 +603,7 @@ void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge) { nc->receive_disabled = 0; - if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) { + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_HUBPORT) { if (net_hub_flush(nc->peer)) { qemu_notify_event(); } @@ -777,7 +777,7 @@ NetClientState *qemu_find_netdev(const char *id) NetClientState *nc; QTAILQ_FOREACH(nc, &net_clients, next) { - if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) + if (nc->info->type == NET_CLIENT_DRIVER_NIC) continue; if (!strcmp(nc->name, id)) { return nc; @@ -788,7 +788,7 @@ NetClientState *qemu_find_netdev(const char *id) } int qemu_find_net_clients_except(const char *id, NetClientState **ncs, - NetClientOptionsKind type, int max) + NetClientDriver type, int max) { NetClientState *nc; int ret = 0; @@ -869,8 +869,8 @@ static int net_init_nic(const Netdev *netdev, const char *name, NICInfo *nd; const NetLegacyNicOptions *nic; - assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_NIC); - nic = netdev->opts->u.nic.data; + assert(netdev->type == NET_CLIENT_DRIVER_NIC); + nic = &netdev->u.nic; idx = nic_get_free_idx(); if (idx == -1 || nb_nics >= MAX_NICS) { @@ -930,39 +930,38 @@ static int net_init_nic(const Netdev *netdev, const char *name, } -static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND__MAX])( +static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) = { - [NET_CLIENT_OPTIONS_KIND_NIC] = net_init_nic, + [NET_CLIENT_DRIVER_NIC] = net_init_nic, #ifdef CONFIG_SLIRP - [NET_CLIENT_OPTIONS_KIND_USER] = net_init_slirp, + [NET_CLIENT_DRIVER_USER] = net_init_slirp, #endif - [NET_CLIENT_OPTIONS_KIND_TAP] = net_init_tap, - [NET_CLIENT_OPTIONS_KIND_SOCKET] = net_init_socket, + [NET_CLIENT_DRIVER_TAP] = net_init_tap, + [NET_CLIENT_DRIVER_SOCKET] = net_init_socket, #ifdef CONFIG_VDE - [NET_CLIENT_OPTIONS_KIND_VDE] = net_init_vde, + [NET_CLIENT_DRIVER_VDE] = net_init_vde, #endif #ifdef CONFIG_NETMAP - [NET_CLIENT_OPTIONS_KIND_NETMAP] = net_init_netmap, + [NET_CLIENT_DRIVER_NETMAP] = net_init_netmap, #endif - [NET_CLIENT_OPTIONS_KIND_DUMP] = net_init_dump, + [NET_CLIENT_DRIVER_DUMP] = net_init_dump, #ifdef CONFIG_NET_BRIDGE - [NET_CLIENT_OPTIONS_KIND_BRIDGE] = net_init_bridge, + [NET_CLIENT_DRIVER_BRIDGE] = net_init_bridge, #endif - [NET_CLIENT_OPTIONS_KIND_HUBPORT] = net_init_hubport, + [NET_CLIENT_DRIVER_HUBPORT] = net_init_hubport, #ifdef CONFIG_VHOST_NET_USED - [NET_CLIENT_OPTIONS_KIND_VHOST_USER] = net_init_vhost_user, + [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user, #endif #ifdef CONFIG_L2TPV3 - [NET_CLIENT_OPTIONS_KIND_L2TPV3] = net_init_l2tpv3, + [NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3, #endif }; static int net_client_init1(const void *object, int is_netdev, Error **errp) { - const NetClientOptions *opts; Netdev legacy = {0}; const Netdev *netdev; const char *name; @@ -970,34 +969,72 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp) if (is_netdev) { netdev = object; - opts = netdev->opts; name = netdev->id; - if (opts->type == NET_CLIENT_OPTIONS_KIND_DUMP || - opts->type == NET_CLIENT_OPTIONS_KIND_NIC || - !net_client_init_fun[opts->type]) { + if (netdev->type == NET_CLIENT_DRIVER_DUMP || + netdev->type == NET_CLIENT_DRIVER_NIC || + !net_client_init_fun[netdev->type]) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", "a netdev backend type"); return -1; } } else { const NetLegacy *net = object; + const NetLegacyOptions *opts = net->opts; legacy.id = net->id; - opts = legacy.opts = net->opts; netdev = &legacy; /* missing optional values have been initialized to "all bits zero" */ name = net->has_id ? net->id : net->name; - if (opts->type == NET_CLIENT_OPTIONS_KIND_NONE) { + /* Map the old options to the new flat type */ + switch (opts->type) { + case NET_LEGACY_OPTIONS_KIND_NONE: return 0; /* nothing to do */ - } - if (opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", - "a net type"); - return -1; + case NET_LEGACY_OPTIONS_KIND_NIC: + legacy.type = NET_CLIENT_DRIVER_NIC; + legacy.u.nic = *opts->u.nic.data; + break; + case NET_LEGACY_OPTIONS_KIND_USER: + legacy.type = NET_CLIENT_DRIVER_USER; + legacy.u.user = *opts->u.user.data; + break; + case NET_LEGACY_OPTIONS_KIND_TAP: + legacy.type = NET_CLIENT_DRIVER_TAP; + legacy.u.tap = *opts->u.tap.data; + break; + case NET_LEGACY_OPTIONS_KIND_L2TPV3: + legacy.type = NET_CLIENT_DRIVER_L2TPV3; + legacy.u.l2tpv3 = *opts->u.l2tpv3.data; + break; + case NET_LEGACY_OPTIONS_KIND_SOCKET: + legacy.type = NET_CLIENT_DRIVER_SOCKET; + legacy.u.socket = *opts->u.socket.data; + break; + case NET_LEGACY_OPTIONS_KIND_VDE: + legacy.type = NET_CLIENT_DRIVER_VDE; + legacy.u.vde = *opts->u.vde.data; + break; + case NET_LEGACY_OPTIONS_KIND_DUMP: + legacy.type = NET_CLIENT_DRIVER_DUMP; + legacy.u.dump = *opts->u.dump.data; + break; + case NET_LEGACY_OPTIONS_KIND_BRIDGE: + legacy.type = NET_CLIENT_DRIVER_BRIDGE; + legacy.u.bridge = *opts->u.bridge.data; + break; + case NET_LEGACY_OPTIONS_KIND_NETMAP: + legacy.type = NET_CLIENT_DRIVER_NETMAP; + legacy.u.netmap = *opts->u.netmap.data; + break; + case NET_LEGACY_OPTIONS_KIND_VHOST_USER: + legacy.type = NET_CLIENT_DRIVER_VHOST_USER; + legacy.u.vhost_user = *opts->u.vhost_user.data; + break; + default: + abort(); } - if (!net_client_init_fun[opts->type]) { + if (!net_client_init_fun[netdev->type]) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", "a net backend type (maybe it is not compiled " "into this binary)"); @@ -1005,17 +1042,17 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp) } /* Do not add to a vlan if it's a nic with a netdev= parameter. */ - if (opts->type != NET_CLIENT_OPTIONS_KIND_NIC || + if (netdev->type != NET_CLIENT_DRIVER_NIC || !opts->u.nic.data->has_netdev) { peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL); } } - if (net_client_init_fun[opts->type](netdev, name, peer, errp) < 0) { + if (net_client_init_fun[netdev->type](netdev, name, peer, errp) < 0) { /* FIXME drop when all init functions store an Error */ if (errp && !*errp) { error_setg(errp, QERR_DEVICE_INIT_FAILED, - NetClientOptionsKind_lookup[opts->type]); + NetClientDriver_lookup[netdev->type]); } return -1; } @@ -1135,7 +1172,7 @@ void hmp_host_net_remove(Monitor *mon, const QDict *qdict) device, vlan_id); return; } - if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { + if (nc->info->type == NET_CLIENT_DRIVER_NIC) { error_report("invalid host network device '%s'", device); return; } @@ -1226,7 +1263,7 @@ void print_net_client(Monitor *mon, NetClientState *nc) monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, nc->queue_index, - NetClientOptionsKind_lookup[nc->info->type], + NetClientDriver_lookup[nc->info->type], nc->info_str); if (!QTAILQ_EMPTY(&nc->filters)) { monitor_printf(mon, "filters:\n"); @@ -1256,7 +1293,7 @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, } /* only query rx-filter information of NIC */ - if (nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC) { + if (nc->info->type != NET_CLIENT_DRIVER_NIC) { if (has_name) { error_setg(errp, "net client(%s) isn't a NIC", name); return NULL; @@ -1302,7 +1339,7 @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, void hmp_info_network(Monitor *mon, const QDict *qdict) { NetClientState *nc, *peer; - NetClientOptionsKind type; + NetClientDriver type; net_hub_info(mon); @@ -1315,10 +1352,10 @@ void hmp_info_network(Monitor *mon, const QDict *qdict) continue; } - if (!peer || type == NET_CLIENT_OPTIONS_KIND_NIC) { + if (!peer || type == NET_CLIENT_DRIVER_NIC) { print_net_client(mon, nc); } /* else it's a netdev connected to a NIC, printed with the NIC */ - if (peer && type == NET_CLIENT_OPTIONS_KIND_NIC) { + if (peer && type == NET_CLIENT_DRIVER_NIC) { monitor_printf(mon, " \\ "); print_net_client(mon, peer); } @@ -1332,7 +1369,7 @@ void qmp_set_link(const char *name, bool up, Error **errp) int queues, i; queues = qemu_find_net_clients_except(name, ncs, - NET_CLIENT_OPTIONS_KIND__MAX, + NET_CLIENT_DRIVER__MAX, MAX_QUEUE_NUM); if (queues == 0) { @@ -1359,7 +1396,7 @@ void qmp_set_link(const char *name, bool up, Error **errp) * multiple clients that can still communicate with each other in * disconnected mode. For now maintain this compatibility. */ - if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { + if (nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { for (i = 0; i < queues; i++) { ncs[i]->peer->link_down = !up; } @@ -1400,7 +1437,7 @@ void net_cleanup(void) */ while (!QTAILQ_EMPTY(&net_clients)) { nc = QTAILQ_FIRST(&net_clients); - if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { + if (nc->info->type == NET_CLIENT_DRIVER_NIC) { qemu_del_nic(qemu_get_nic(nc)); } else { qemu_del_net_client(nc); @@ -1420,7 +1457,7 @@ void net_check_clients(void) QTAILQ_FOREACH(nc, &net_clients, next) { if (!nc->peer) { fprintf(stderr, "Warning: %s %s has no peer\n", - nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC ? + nc->info->type == NET_CLIENT_DRIVER_NIC ? "nic" : "netdev", nc->name); } } diff --git a/net/netmap.c b/net/netmap.c index beb8d2841c..2d11a8f4be 100644 --- a/net/netmap.c +++ b/net/netmap.c @@ -400,7 +400,7 @@ static void netmap_set_offload(NetClientState *nc, int csum, int tso4, int tso6, /* NetClientInfo methods */ static NetClientInfo net_netmap_info = { - .type = NET_CLIENT_OPTIONS_KIND_NETMAP, + .type = NET_CLIENT_DRIVER_NETMAP, .size = sizeof(NetmapState), .receive = netmap_receive, .receive_iov = netmap_receive_iov, @@ -421,7 +421,7 @@ static NetClientInfo net_netmap_info = { int net_init_netmap(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp) { - const NetdevNetmapOptions *netmap_opts = netdev->opts->u.netmap.data; + const NetdevNetmapOptions *netmap_opts = &netdev->u.netmap; struct nm_desc *nmd; NetClientState *nc; Error *err = NULL; diff --git a/net/slirp.c b/net/slirp.c index ca34badb76..facc30ed18 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -137,7 +137,7 @@ static void net_slirp_cleanup(NetClientState *nc) } static NetClientInfo net_slirp_info = { - .type = NET_CLIENT_OPTIONS_KIND_USER, + .type = NET_CLIENT_DRIVER_USER, .size = sizeof(SlirpState), .receive = net_slirp_receive, .cleanup = net_slirp_cleanup, @@ -839,8 +839,8 @@ int net_init_slirp(const Netdev *netdev, const char *name, const char **dnssearch; bool ipv4 = true, ipv6 = true; - assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_USER); - user = netdev->opts->u.user.data; + assert(netdev->type == NET_CLIENT_DRIVER_USER); + user = &netdev->u.user; if ((user->has_ipv6 && user->ipv6 && !user->has_ipv4) || (user->has_ipv4 && !user->ipv4)) { diff --git a/net/socket.c b/net/socket.c index 6e5c902ea9..17e635de20 100644 --- a/net/socket.c +++ b/net/socket.c @@ -311,7 +311,7 @@ static void net_socket_cleanup(NetClientState *nc) } static NetClientInfo net_dgram_socket_info = { - .type = NET_CLIENT_OPTIONS_KIND_SOCKET, + .type = NET_CLIENT_DRIVER_SOCKET, .size = sizeof(NetSocketState), .receive = net_socket_receive_dgram, .cleanup = net_socket_cleanup, @@ -395,7 +395,7 @@ static void net_socket_connect(void *opaque) } static NetClientInfo net_socket_info = { - .type = NET_CLIENT_OPTIONS_KIND_SOCKET, + .type = NET_CLIENT_DRIVER_SOCKET, .size = sizeof(NetSocketState), .receive = net_socket_receive, .cleanup = net_socket_cleanup, @@ -670,8 +670,8 @@ int net_init_socket(const Netdev *netdev, const char *name, Error *err = NULL; const NetdevSocketOptions *sock; - assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET); - sock = netdev->opts->u.socket.data; + assert(netdev->type == NET_CLIENT_DRIVER_SOCKET); + sock = &netdev->u.socket; if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast + sock->has_udp != 1) { diff --git a/net/tap-win32.c b/net/tap-win32.c index 0f23b19c96..662f9b63e1 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -750,7 +750,7 @@ static void tap_set_vnet_hdr_len(NetClientState *nc, int len) } static NetClientInfo net_tap_win32_info = { - .type = NET_CLIENT_OPTIONS_KIND_TAP, + .type = NET_CLIENT_DRIVER_TAP, .size = sizeof(TAPState), .receive = tap_receive, .cleanup = tap_cleanup, @@ -794,8 +794,8 @@ int net_init_tap(const Netdev *netdev, const char *name, /* FIXME error_setg(errp, ...) on failure */ const NetdevTapOptions *tap; - assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_TAP); - tap = netdev->opts->u.tap.data; + assert(netdev->type == NET_CLIENT_DRIVER_TAP); + tap = &netdev->u.tap; if (!tap->has_ifname) { error_report("tap: no interface name"); diff --git a/net/tap.c b/net/tap.c index ceb8c43821..7928a09daa 100644 --- a/net/tap.c +++ b/net/tap.c @@ -223,7 +223,7 @@ static bool tap_has_ufo(NetClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); + assert(nc->info->type == NET_CLIENT_DRIVER_TAP); return s->has_ufo; } @@ -232,7 +232,7 @@ static bool tap_has_vnet_hdr(NetClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); + assert(nc->info->type == NET_CLIENT_DRIVER_TAP); return !!s->host_vnet_hdr_len; } @@ -241,7 +241,7 @@ static bool tap_has_vnet_hdr_len(NetClientState *nc, int len) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); + assert(nc->info->type == NET_CLIENT_DRIVER_TAP); return !!tap_probe_vnet_hdr_len(s->fd, len); } @@ -250,7 +250,7 @@ static void tap_set_vnet_hdr_len(NetClientState *nc, int len) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); + assert(nc->info->type == NET_CLIENT_DRIVER_TAP); assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) || len == sizeof(struct virtio_net_hdr)); @@ -262,7 +262,7 @@ static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); + assert(nc->info->type == NET_CLIENT_DRIVER_TAP); assert(!!s->host_vnet_hdr_len == using_vnet_hdr); s->using_vnet_hdr = using_vnet_hdr; @@ -336,14 +336,14 @@ static void tap_poll(NetClientState *nc, bool enable) int tap_get_fd(NetClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); + assert(nc->info->type == NET_CLIENT_DRIVER_TAP); return s->fd; } /* fd support */ static NetClientInfo net_tap_info = { - .type = NET_CLIENT_OPTIONS_KIND_TAP, + .type = NET_CLIENT_DRIVER_TAP, .size = sizeof(TAPState), .receive = tap_receive, .receive_raw = tap_receive_raw, @@ -579,8 +579,8 @@ int net_init_bridge(const Netdev *netdev, const char *name, TAPState *s; int fd, vnet_hdr; - assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_BRIDGE); - bridge = netdev->opts->u.bridge.data; + assert(netdev->type == NET_CLIENT_DRIVER_BRIDGE); + bridge = &netdev->u.bridge; helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER; br = bridge->has_br ? bridge->br : DEFAULT_BRIDGE_INTERFACE; @@ -747,8 +747,8 @@ int net_init_tap(const Netdev *netdev, const char *name, const char *vhostfdname; char ifname[128]; - assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_TAP); - tap = netdev->opts->u.tap.data; + assert(netdev->type == NET_CLIENT_DRIVER_TAP); + tap = &netdev->u.tap; queues = tap->has_queues ? tap->queues : 1; vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL; @@ -911,7 +911,7 @@ int net_init_tap(const Netdev *netdev, const char *name, VHostNetState *tap_get_vhost_net(NetClientState *nc) { TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); + assert(nc->info->type == NET_CLIENT_DRIVER_TAP); return s->vhost_net; } diff --git a/net/vde.c b/net/vde.c index 53cdbbf0ea..e50e5d6394 100644 --- a/net/vde.c +++ b/net/vde.c @@ -68,7 +68,7 @@ static void vde_cleanup(NetClientState *nc) } static NetClientInfo net_vde_info = { - .type = NET_CLIENT_OPTIONS_KIND_VDE, + .type = NET_CLIENT_DRIVER_VDE, .size = sizeof(VDEState), .receive = vde_receive, .cleanup = vde_cleanup, @@ -115,8 +115,8 @@ int net_init_vde(const Netdev *netdev, const char *name, /* FIXME error_setg(errp, ...) on failure */ const NetdevVdeOptions *vde; - assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_VDE); - vde = netdev->opts->u.vde.data; + assert(netdev->type == NET_CLIENT_DRIVER_VDE); + vde = &netdev->u.vde; /* missing optional values have been initialized to "all bits zero" */ if (net_vde_init(peer, "vde", name, vde->sock, vde->port, vde->group, diff --git a/net/vhost-user.c b/net/vhost-user.c index dfdcca221c..c4d63e05eb 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -34,14 +34,14 @@ typedef struct VhostUserChardevProps { VHostNetState *vhost_user_get_vhost_net(NetClientState *nc) { VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); return s->vhost_net; } uint64_t vhost_user_get_acked_features(NetClientState *nc) { VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); return s->acked_features; } @@ -56,7 +56,7 @@ static void vhost_user_stop(int queues, NetClientState *ncs[]) int i; for (i = 0; i < queues; i++) { - assert (ncs[i]->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); + assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER); s = DO_UPCAST(VhostUserState, nc, ncs[i]); if (!vhost_user_running(s)) { @@ -82,7 +82,7 @@ static int vhost_user_start(int queues, NetClientState *ncs[]) options.backend_type = VHOST_BACKEND_TYPE_USER; for (i = 0; i < queues; i++) { - assert (ncs[i]->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); + assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER); s = DO_UPCAST(VhostUserState, nc, ncs[i]); if (vhost_user_running(s)) { @@ -163,20 +163,20 @@ static void vhost_user_cleanup(NetClientState *nc) static bool vhost_user_has_vnet_hdr(NetClientState *nc) { - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); return true; } static bool vhost_user_has_ufo(NetClientState *nc) { - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); + assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER); return true; } static NetClientInfo net_vhost_user_info = { - .type = NET_CLIENT_OPTIONS_KIND_VHOST_USER, + .type = NET_CLIENT_DRIVER_VHOST_USER, .size = sizeof(VhostUserState), .receive = vhost_user_receive, .cleanup = vhost_user_cleanup, @@ -207,7 +207,7 @@ static void net_vhost_user_event(void *opaque, int event) int queues; queues = qemu_find_net_clients_except(name, ncs, - NET_CLIENT_OPTIONS_KIND_NIC, + NET_CLIENT_DRIVER_NIC, MAX_QUEUE_NUM); assert(queues < MAX_QUEUE_NUM); @@ -341,8 +341,8 @@ int net_init_vhost_user(const Netdev *netdev, const char *name, const NetdevVhostUserOptions *vhost_user_opts; CharDriverState *chr; - assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); - vhost_user_opts = netdev->opts->u.vhost_user.data; + assert(netdev->type == NET_CLIENT_DRIVER_VHOST_USER); + vhost_user_opts = &netdev->u.vhost_user; chr = net_vhost_parse_chardev(vhost_user_opts, errp); if (!chr) { -- cgit v1.2.3 From 0e55c381f69f302d09ab1e18f3c1156cca56f4a6 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 13 Jul 2016 21:50:24 -0600 Subject: net: Use correct type for bool flag is_netdev is only used as a bool, so make it one. Signed-off-by: Eric Blake Message-Id: <1468468228-27827-14-git-send-email-eblake@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- net/net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/net.c b/net/net.c index 4a7f392baf..c124b11e4d 100644 --- a/net/net.c +++ b/net/net.c @@ -960,7 +960,7 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( }; -static int net_client_init1(const void *object, int is_netdev, Error **errp) +static int net_client_init1(const void *object, bool is_netdev, Error **errp) { Netdev legacy = {0}; const Netdev *netdev; @@ -1060,7 +1060,7 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp) } -int net_client_init(QemuOpts *opts, int is_netdev, Error **errp) +int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) { void *object = NULL; Error *err = NULL; @@ -1153,7 +1153,7 @@ void hmp_host_net_add(Monitor *mon, const QDict *qdict) qemu_opt_set(opts, "type", device, &error_abort); - net_client_init(opts, 0, &local_err); + net_client_init(opts, false, &local_err); if (local_err) { error_report_err(local_err); monitor_printf(mon, "adding host network device %s failed\n", device); @@ -1183,7 +1183,7 @@ void hmp_host_net_remove(Monitor *mon, const QDict *qdict) void netdev_add(QemuOpts *opts, Error **errp) { - net_client_init(opts, 1, errp); + net_client_init(opts, true, errp); } void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp) @@ -1481,7 +1481,7 @@ static int net_init_client(void *dummy, QemuOpts *opts, Error **errp) { Error *local_err = NULL; - net_client_init(opts, 0, &local_err); + net_client_init(opts, false, &local_err); if (local_err) { error_report_err(local_err); return -1; @@ -1495,7 +1495,7 @@ static int net_init_netdev(void *dummy, QemuOpts *opts, Error **errp) Error *local_err = NULL; int ret; - ret = net_client_init(opts, 1, &local_err); + ret = net_client_init(opts, true, &local_err); if (local_err) { error_report_err(local_err); return -1; -- cgit v1.2.3 From d9d261142d554504a32d95b771e9d8191631323f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 27 Jul 2016 01:14:56 +0400 Subject: vhost-user: minor simplification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shorten the code and make it more clear by using the specialized function g_str_has_prefix(). Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-user.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/vhost-user.c b/net/vhost-user.c index c4d63e05eb..2af212bddb 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -316,7 +316,6 @@ static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp) { const char *name = opaque; const char *driver, *netdev; - const char virtio_name[] = "virtio-net-"; driver = qemu_opt_get(opts, "driver"); netdev = qemu_opt_get(opts, "netdev"); @@ -326,7 +325,7 @@ static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp) } if (strcmp(netdev, name) == 0 && - strncmp(driver, virtio_name, strlen(virtio_name)) != 0) { + !g_str_has_prefix(driver, "virtio-net-")) { error_setg(errp, "vhost-user requires frontend driver virtio-net-*"); return -1; } -- cgit v1.2.3 From 9c7d18b3a59f6e4464543905dede90f1a65096cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 27 Jul 2016 01:14:57 +0400 Subject: vhost-user: disconnect on HUP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In some cases, qemu_chr_fe_read_all() on HUP event doesn't raise CHR_EVENT_CLOSED because the read/recv function returns -1 on disconnected peers (for example with tch_chr_recv, an ECONNRESET errno overwritten as EIO). It is simpler to explicitely disconnect on HUP, rising CHR_EVENT_CLOSED if it wasn't disconnected already. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-user.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'net') diff --git a/net/vhost-user.c b/net/vhost-user.c index 2af212bddb..2cac32e3b7 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -188,12 +188,8 @@ static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond, void *opaque) { VhostUserState *s = opaque; - uint8_t buf[1]; - /* We don't actually want to read anything, but CHR_EVENT_CLOSED will be - * raised as a side-effect of the read. - */ - qemu_chr_fe_read_all(s->chr, buf, sizeof(buf)); + qemu_chr_disconnect(s->chr); return FALSE; } -- cgit v1.2.3 From e6bcb1b61782cefacecc8b9ee7a5f782373dab2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 27 Jul 2016 01:15:12 +0400 Subject: vhost-user: keep vhost_net after a disconnection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many code paths assume get_vhost_net() returns non-null. Keep VhostUserState.vhost_net after a successful vhost_net_init(), instead of freeing it in vhost_net_cleanup(). VhostUserState.vhost_net is thus freed before after being recreated or on final vhost_user_cleanup() and there is no need to save the acked features. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/tap.c | 1 + net/vhost-user.c | 36 +++++++++++++++++++----------------- 2 files changed, 20 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/tap.c b/net/tap.c index 40a8c741fc..6abb962efd 100644 --- a/net/tap.c +++ b/net/tap.c @@ -312,6 +312,7 @@ static void tap_cleanup(NetClientState *nc) if (s->vhost_net) { vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); s->vhost_net = NULL; } diff --git a/net/vhost-user.c b/net/vhost-user.c index 2cac32e3b7..d2a984d767 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -45,11 +45,6 @@ uint64_t vhost_user_get_acked_features(NetClientState *nc) return s->acked_features; } -static int vhost_user_running(VhostUserState *s) -{ - return (s->vhost_net) ? 1 : 0; -} - static void vhost_user_stop(int queues, NetClientState *ncs[]) { VhostUserState *s; @@ -59,15 +54,14 @@ static void vhost_user_stop(int queues, NetClientState *ncs[]) assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER); s = DO_UPCAST(VhostUserState, nc, ncs[i]); - if (!vhost_user_running(s)) { - continue; - } if (s->vhost_net) { /* save acked features */ - s->acked_features = vhost_net_get_acked_features(s->vhost_net); + uint64_t features = vhost_net_get_acked_features(s->vhost_net); + if (features) { + s->acked_features = features; + } vhost_net_cleanup(s->vhost_net); - s->vhost_net = NULL; } } } @@ -75,6 +69,7 @@ static void vhost_user_stop(int queues, NetClientState *ncs[]) static int vhost_user_start(int queues, NetClientState *ncs[]) { VhostNetOptions options; + struct vhost_net *net = NULL; VhostUserState *s; int max_queues; int i; @@ -85,33 +80,39 @@ static int vhost_user_start(int queues, NetClientState *ncs[]) assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER); s = DO_UPCAST(VhostUserState, nc, ncs[i]); - if (vhost_user_running(s)) { - continue; - } options.net_backend = ncs[i]; options.opaque = s->chr; options.busyloop_timeout = 0; - s->vhost_net = vhost_net_init(&options); - if (!s->vhost_net) { + net = vhost_net_init(&options); + if (!net) { error_report("failed to init vhost_net for queue %d", i); goto err; } if (i == 0) { - max_queues = vhost_net_get_max_queues(s->vhost_net); + max_queues = vhost_net_get_max_queues(net); if (queues > max_queues) { error_report("you are asking more queues than supported: %d", max_queues); goto err; } } + + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); + } + s->vhost_net = net; } return 0; err: - vhost_user_stop(i + 1, ncs); + if (net) { + vhost_net_cleanup(net); + } + vhost_user_stop(i, ncs); return -1; } @@ -150,6 +151,7 @@ static void vhost_user_cleanup(NetClientState *nc) if (s->vhost_net) { vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); s->vhost_net = NULL; } if (s->chr) { -- cgit v1.2.3 From 1a5b68cee8a2b165ffd61b2e0641a4da3990f242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 27 Jul 2016 01:15:13 +0400 Subject: vhost-user: add get_vhost_net() assertions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a few assertions to be more explicit about the runtime behaviour after the previous patch: get_vhost_net() is non-null after net_vhost_user_init(). Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-user.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/vhost-user.c b/net/vhost-user.c index d2a984d767..39987a3c8a 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -259,6 +259,8 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, qemu_chr_add_handlers(chr, NULL, NULL, net_vhost_user_event, nc[0].name); + assert(s->vhost_net); + return 0; } -- cgit v1.2.3 From c89804d674e4e3804bd3ac1fe79650896044b4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Wed, 27 Jul 2016 01:15:19 +0400 Subject: vhost-user: wait until backend init is completed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The chardev waits for an initial connection before starting qemu, and vhost-user should wait for the backend negotiation to be completed before starting qemu too. vhost-user is started in the net_vhost_user_event callback, which is synchronously called after the socket is connected. Use a VhostUserState.started flag to indicate vhost-user init completed successfully and qemu can be started. Signed-off-by: Marc-André Lureau Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-user.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/vhost-user.c b/net/vhost-user.c index 39987a3c8a..b0595f8781 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -24,6 +24,7 @@ typedef struct VhostUserState { VHostNetState *vhost_net; guint watch; uint64_t acked_features; + bool started; } VhostUserState; typedef struct VhostUserChardevProps { @@ -220,6 +221,7 @@ static void net_vhost_user_event(void *opaque, int event) return; } qmp_set_link(name, true, &err); + s->started = true; break; case CHR_EVENT_CLOSED: qmp_set_link(name, false, &err); @@ -238,7 +240,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, const char *name, CharDriverState *chr, int queues) { - NetClientState *nc; + NetClientState *nc, *nc0 = NULL; VhostUserState *s; int i; @@ -247,6 +249,9 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, for (i = 0; i < queues; i++) { nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name); + if (!nc0) { + nc0 = nc; + } snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s", i, chr->label); @@ -257,7 +262,16 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, s->chr = chr; } - qemu_chr_add_handlers(chr, NULL, NULL, net_vhost_user_event, nc[0].name); + s = DO_UPCAST(VhostUserState, nc, nc0); + do { + Error *err = NULL; + if (qemu_chr_wait_connected(chr, &err) < 0) { + error_report_err(err); + return -1; + } + qemu_chr_add_handlers(chr, NULL, NULL, + net_vhost_user_event, nc0->name); + } while (!s->started); assert(s->vhost_net); -- cgit v1.2.3 From e723b8710356163e0f1722b94f988a8ddf83f17a Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 8 Aug 2016 17:11:21 +0200 Subject: trace-events: fix first line comment in trace-events Documentation is docs/tracing.txt instead of docs/trace-events.txt. find . -name trace-events -exec \ sed -i "s?See docs/trace-events.txt for syntax documentation.?See docs/tracing.txt for syntax documentation.?" \ {} \; Signed-off-by: Laurent Vivier Message-id: 1470669081-17860-1-git-send-email-lvivier@redhat.com Signed-off-by: Stefan Hajnoczi --- net/trace-events | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/trace-events b/net/trace-events index 32a0a8abb9..65c46a48fb 100644 --- a/net/trace-events +++ b/net/trace-events @@ -1,4 +1,4 @@ -# See docs/trace-events.txt for syntax documentation. +# See docs/tracing.txt for syntax documentation. # net/vhost-user.c vhost_user_event(const char *chr, int event) "chr: %s got event: %d" -- cgit v1.2.3 From e9e0a5854b6dc888f44e7e280a007326714199a6 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Thu, 18 Aug 2016 11:23:25 +0800 Subject: net/net: properly handle multiple packets in net_fill_rstate() When network is busy, we will receive multiple packets at one time. In that situation, we should keep trying to do the receiving instead of finalizing only the first packet. Signed-off-by: Zhang Chen Signed-off-by: Li Zhijian Signed-off-by: Jason Wang --- net/net.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/net.c b/net/net.c index c124b11e4d..d51cb29882 100644 --- a/net/net.c +++ b/net/net.c @@ -1602,9 +1602,8 @@ void net_socket_rs_init(SocketReadState *rs, /* * Returns - * 0: SocketReadState is not ready - * 1: SocketReadState is ready - * otherwise error occurs + * 0: success + * -1: error occurs */ int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size) { @@ -1652,10 +1651,11 @@ int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size) if (rs->finalize) { rs->finalize(rs); } - return 1; } break; } } + + assert(size == 0); return 0; } -- cgit v1.2.3 From 67f3280c062d622dc077246b483702096d11dcc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 18 Aug 2016 17:44:05 +0400 Subject: slirp: fix segv when init failed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit f6c2e66ae8c8a, slirp uses an exit notifier to call slirp_smb_cleanup. However, if init() failed, the notifier isn't added, and removing it will fail: ==18447== Invalid write of size 8 ==18447== at 0x7EF2B5: notifier_remove (notify.c:32) ==18447== by 0x48E80C: qemu_remove_exit_notifier (vl.c:2661) ==18447== by 0x6A2187: net_slirp_cleanup (slirp.c:134) ==18447== by 0x69419D: qemu_cleanup_net_client (net.c:338) ==18447== by 0x69445B: qemu_del_net_client (net.c:401) ==18447== by 0x6A2B81: net_slirp_init (slirp.c:366) ==18447== by 0x6A4241: net_init_slirp (slirp.c:865) ==18447== by 0x695C6D: net_client_init1 (net.c:1051) ==18447== by 0x695F6E: net_client_init (net.c:1108) ==18447== by 0x696DBA: net_init_netdev (net.c:1498) ==18447== by 0x7F1F99: qemu_opts_foreach (qemu-option.c:1116) ==18447== by 0x696E60: net_init_clients (net.c:1516) ==18447== Address 0x0 is not stack'd, malloc'd or (recently) free'd Signed-off-by: Marc-André Lureau Signed-off-by: Jason Wang --- net/slirp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/slirp.c b/net/slirp.c index facc30ed18..b60893f9c5 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -131,7 +131,9 @@ static void net_slirp_cleanup(NetClientState *nc) SlirpState *s = DO_UPCAST(SlirpState, nc, nc); slirp_cleanup(s->slirp); - qemu_remove_exit_notifier(&s->exit_notifier); + if (s->exit_notifier.notify) { + qemu_remove_exit_notifier(&s->exit_notifier); + } slirp_smb_cleanup(s); QTAILQ_REMOVE(&slirp_stacks, s, entry); } -- cgit v1.2.3 From 616018352c244d8b0ea4626407b0801844ae0748 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 30 Aug 2016 14:04:12 +0200 Subject: Revert "Change net/socket.c to use socket_*() functions" Since commit 7e8449594c929, the socket connect code is blocking, because calling socket_connect() without callback is blocking. This reverts the commit. Signed-off-by: Paolo Bonzini --- net/socket.c | 55 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index 17e635de20..3f98eefb34 100644 --- a/net/socket.c +++ b/net/socket.c @@ -489,30 +489,41 @@ static int net_socket_listen_init(NetClientState *peer, { NetClientState *nc; NetSocketState *s; - SocketAddress *saddr; - int ret; - Error *local_error = NULL; + struct sockaddr_in saddr; + int fd, ret; - saddr = socket_parse(host_str, &local_error); - if (saddr == NULL) { - error_report_err(local_error); + if (parse_host_port(&saddr, host_str) < 0) + return -1; + + fd = qemu_socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); return -1; } + qemu_set_nonblock(fd); - ret = socket_listen(saddr, &local_error); + socket_set_fast_reuse(fd); + + ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { - error_report_err(local_error); + perror("bind"); + closesocket(fd); + return -1; + } + ret = listen(fd, 0); + if (ret < 0) { + perror("listen"); + closesocket(fd); return -1; } nc = qemu_new_net_client(&net_socket_info, peer, model, name); s = DO_UPCAST(NetSocketState, nc, nc); s->fd = -1; - s->listen_fd = ret; + s->listen_fd = fd; s->nc.link_down = true; qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); - qapi_free_SocketAddress(saddr); return 0; } @@ -523,15 +534,10 @@ static int net_socket_connect_init(NetClientState *peer, { NetSocketState *s; int fd, connected, ret; - char *addr_str; - SocketAddress *saddr; - Error *local_error = NULL; + struct sockaddr_in saddr; - saddr = socket_parse(host_str, &local_error); - if (saddr == NULL) { - error_report_err(local_error); + if (parse_host_port(&saddr, host_str) < 0) return -1; - } fd = qemu_socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { @@ -539,9 +545,10 @@ static int net_socket_connect_init(NetClientState *peer, return -1; } qemu_set_nonblock(fd); + connected = 0; for(;;) { - ret = socket_connect(saddr, &local_error, NULL, NULL); + ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { if (errno == EINTR || errno == EWOULDBLOCK) { /* continue */ @@ -550,7 +557,7 @@ static int net_socket_connect_init(NetClientState *peer, errno == EINVAL) { break; } else { - error_report_err(local_error); + perror("connect"); closesocket(fd); return -1; } @@ -562,15 +569,9 @@ static int net_socket_connect_init(NetClientState *peer, s = net_socket_fd_init(peer, model, name, fd, connected); if (!s) return -1; - - addr_str = socket_address_to_string(saddr, &local_error); - if (addr_str == NULL) - return -1; - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: connect to %s", addr_str); - qapi_free_SocketAddress(saddr); - g_free(addr_str); + "socket: connect to %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; } -- cgit v1.2.3