Merge remote-tracking branch 'stefanha/net' into staging

* stefanha/net:
  net: EAGAIN handling for net/socket.c TCP
  net: EAGAIN handling for net/socket.c UDP
  net: asynchronous send/receive infrastructure for net/socket.c
  net: broadcast hub packets if at least one port can receive
  net: fix usbnet_receive() packet drops
  net: clean up usbnet_receive()
  net: add -netdev options to man page
  net: do not report queued packets as sent
  net: add receive_disabled logic to iov delivery path
  eepro100: Fix network hang when rx buffers run out
  xen: flush queue when getting an event
  e1000: flush queue whenever can_receive can go from false to true
  net: notify iothread after flushing queue
This commit is contained in:
Anthony Liguori 2012-09-17 10:20:48 -05:00
commit de71bd6f77
11 changed files with 187 additions and 64 deletions

View file

@ -295,6 +295,7 @@ set_rx_control(E1000State *s, int index, uint32_t val)
s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1; s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT], DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
s->mac_reg[RCTL]); s->mac_reg[RCTL]);
qemu_flush_queued_packets(&s->nic->nc);
} }
static void static void
@ -926,6 +927,9 @@ set_rdt(E1000State *s, int index, uint32_t val)
{ {
s->check_rxov = 0; s->check_rxov = 0;
s->mac_reg[index] = val & 0xffff; s->mac_reg[index] = val & 0xffff;
if (e1000_has_rxbufs(s, 1)) {
qemu_flush_queued_packets(&s->nic->nc);
}
} }
static void static void

View file

@ -1036,6 +1036,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
} }
set_ru_state(s, ru_ready); set_ru_state(s, ru_ready);
s->ru_offset = e100_read_reg4(s, SCBPointer); s->ru_offset = e100_read_reg4(s, SCBPointer);
qemu_flush_queued_packets(&s->nic->nc);
TRACE(OTHER, logout("val=0x%02x (rx start)\n", val)); TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
break; break;
case RX_RESUME: case RX_RESUME:
@ -1770,7 +1771,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
if (rfd_command & COMMAND_EL) { if (rfd_command & COMMAND_EL) {
/* EL bit is set, so this was the last frame. */ /* EL bit is set, so this was the last frame. */
logout("receive: Running out of frames\n"); logout("receive: Running out of frames\n");
set_ru_state(s, ru_suspended); set_ru_state(s, ru_no_resources);
eepro100_rnr_interrupt(s);
} }
if (rfd_command & COMMAND_S) { if (rfd_command & COMMAND_S) {
/* S bit is set. */ /* S bit is set. */

View file

@ -1001,6 +1001,13 @@ static int rndis_keepalive_response(USBNetState *s,
return 0; return 0;
} }
/* Prepare to receive the next packet */
static void usb_net_reset_in_buf(USBNetState *s)
{
s->in_ptr = s->in_len = 0;
qemu_flush_queued_packets(&s->nic->nc);
}
static int rndis_parse(USBNetState *s, uint8_t *data, int length) static int rndis_parse(USBNetState *s, uint8_t *data, int length)
{ {
uint32_t msg_type; uint32_t msg_type;
@ -1025,7 +1032,8 @@ static int rndis_parse(USBNetState *s, uint8_t *data, int length)
case RNDIS_RESET_MSG: case RNDIS_RESET_MSG:
rndis_clear_responsequeue(s); rndis_clear_responsequeue(s);
s->out_ptr = s->in_ptr = s->in_len = 0; s->out_ptr = 0;
usb_net_reset_in_buf(s);
return rndis_reset_response(s, (rndis_reset_msg_type *) data); return rndis_reset_response(s, (rndis_reset_msg_type *) data);
case RNDIS_KEEPALIVE_MSG: case RNDIS_KEEPALIVE_MSG:
@ -1135,7 +1143,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
int ret = USB_RET_NAK; int ret = USB_RET_NAK;
if (s->in_ptr > s->in_len) { if (s->in_ptr > s->in_len) {
s->in_ptr = s->in_len = 0; usb_net_reset_in_buf(s);
ret = USB_RET_NAK; ret = USB_RET_NAK;
return ret; return ret;
} }
@ -1152,7 +1160,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
if (s->in_ptr >= s->in_len && if (s->in_ptr >= s->in_len &&
(is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) { (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
/* no short packet necessary */ /* no short packet necessary */
s->in_ptr = s->in_len = 0; usb_net_reset_in_buf(s);
} }
#ifdef TRAFFIC_DEBUG #ifdef TRAFFIC_DEBUG
@ -1250,20 +1258,32 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size) static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
{ {
USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
struct rndis_packet_msg_type *msg; uint8_t *in_buf = s->in_buf;
size_t total_size = size;
if (is_rndis(s)) { if (is_rndis(s)) {
msg = (struct rndis_packet_msg_type *) s->in_buf;
if (s->rndis_state != RNDIS_DATA_INITIALIZED) { if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
return -1; return -1;
} }
if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf)) total_size += sizeof(struct rndis_packet_msg_type);
}
if (total_size > sizeof(s->in_buf)) {
return -1; return -1;
}
/* Only accept packet if input buffer is empty */
if (s->in_len > 0) {
return 0;
}
if (is_rndis(s)) {
struct rndis_packet_msg_type *msg;
msg = (struct rndis_packet_msg_type *)in_buf;
memset(msg, 0, sizeof(struct rndis_packet_msg_type)); memset(msg, 0, sizeof(struct rndis_packet_msg_type));
msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG); msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG);
msg->MessageLength = cpu_to_le32(size + sizeof(struct rndis_packet_msg_type)); msg->MessageLength = cpu_to_le32(size + sizeof(*msg));
msg->DataOffset = cpu_to_le32(sizeof(struct rndis_packet_msg_type) - 8); msg->DataOffset = cpu_to_le32(sizeof(*msg) - 8);
msg->DataLength = cpu_to_le32(size); msg->DataLength = cpu_to_le32(size);
/* msg->OOBDataOffset; /* msg->OOBDataOffset;
* msg->OOBDataLength; * msg->OOBDataLength;
@ -1273,14 +1293,11 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz
* msg->VcHandle; * msg->VcHandle;
* msg->Reserved; * msg->Reserved;
*/ */
memcpy(msg + 1, buf, size); in_buf += sizeof(*msg);
s->in_len = size + sizeof(struct rndis_packet_msg_type);
} else {
if (size > sizeof(s->in_buf))
return -1;
memcpy(s->in_buf, buf, size);
s->in_len = size;
} }
memcpy(in_buf, buf, size);
s->in_len = total_size;
s->in_ptr = 0; s->in_ptr = 0;
return size; return size;
} }

View file

@ -447,10 +447,6 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
VirtIONet *n = to_virtio_net(vdev); VirtIONet *n = to_virtio_net(vdev);
qemu_flush_queued_packets(&n->nic->nc); qemu_flush_queued_packets(&n->nic->nc);
/* We now have RX buffers, signal to the IO thread to break out of the
* select to re-poll the tap file descriptor */
qemu_notify_event();
} }
static int virtio_net_can_receive(NetClientState *nc) static int virtio_net_can_receive(NetClientState *nc)

View file

@ -415,6 +415,7 @@ static void net_event(struct XenDevice *xendev)
{ {
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
net_tx_packets(netdev); net_tx_packets(netdev);
qemu_flush_queued_packets(&netdev->nic->nc);
} }
static int net_free(struct XenDevice *xendev) static int net_free(struct XenDevice *xendev)

26
net.c
View file

@ -357,7 +357,12 @@ void qemu_flush_queued_packets(NetClientState *nc)
{ {
nc->receive_disabled = 0; nc->receive_disabled = 0;
qemu_net_queue_flush(nc->send_queue); if (qemu_net_queue_flush(nc->send_queue)) {
/* We emptied the queue successfully, signal to the IO thread to repoll
* the file descriptor (for tap, for example).
*/
qemu_notify_event();
}
} }
static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender,
@ -418,16 +423,27 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender,
void *opaque) void *opaque)
{ {
NetClientState *nc = opaque; NetClientState *nc = opaque;
int ret;
if (nc->link_down) { if (nc->link_down) {
return iov_size(iov, iovcnt); return iov_size(iov, iovcnt);
} }
if (nc->info->receive_iov) { if (nc->receive_disabled) {
return nc->info->receive_iov(nc, iov, iovcnt); return 0;
} else {
return nc_sendv_compat(nc, iov, iovcnt);
} }
if (nc->info->receive_iov) {
ret = nc->info->receive_iov(nc, iov, iovcnt);
} else {
ret = nc_sendv_compat(nc, iov, iovcnt);
}
if (ret == 0) {
nc->receive_disabled = 1;
}
return ret;
} }
ssize_t qemu_sendv_packet_async(NetClientState *sender, ssize_t qemu_sendv_packet_async(NetClientState *sender,

View file

@ -97,12 +97,12 @@ static int net_hub_port_can_receive(NetClientState *nc)
continue; continue;
} }
if (!qemu_can_send_packet(&port->nc)) { if (qemu_can_send_packet(&port->nc)) {
return 0; return 1;
} }
} }
return 1; return 0;
} }
static ssize_t net_hub_port_receive(NetClientState *nc, static ssize_t net_hub_port_receive(NetClientState *nc,

View file

@ -83,7 +83,7 @@ void qemu_del_net_queue(NetQueue *queue)
g_free(queue); g_free(queue);
} }
static ssize_t qemu_net_queue_append(NetQueue *queue, static void qemu_net_queue_append(NetQueue *queue,
NetClientState *sender, NetClientState *sender,
unsigned flags, unsigned flags,
const uint8_t *buf, const uint8_t *buf,
@ -100,11 +100,9 @@ static ssize_t qemu_net_queue_append(NetQueue *queue,
memcpy(packet->data, buf, size); memcpy(packet->data, buf, size);
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
return size;
} }
static ssize_t qemu_net_queue_append_iov(NetQueue *queue, static void qemu_net_queue_append_iov(NetQueue *queue,
NetClientState *sender, NetClientState *sender,
unsigned flags, unsigned flags,
const struct iovec *iov, const struct iovec *iov,
@ -133,8 +131,6 @@ static ssize_t qemu_net_queue_append_iov(NetQueue *queue,
} }
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
return packet->size;
} }
static ssize_t qemu_net_queue_deliver(NetQueue *queue, static ssize_t qemu_net_queue_deliver(NetQueue *queue,
@ -177,7 +173,8 @@ ssize_t qemu_net_queue_send(NetQueue *queue,
ssize_t ret; ssize_t ret;
if (queue->delivering || !qemu_can_send_packet(sender)) { if (queue->delivering || !qemu_can_send_packet(sender)) {
return qemu_net_queue_append(queue, sender, flags, data, size, sent_cb); qemu_net_queue_append(queue, sender, flags, data, size, sent_cb);
return 0;
} }
ret = qemu_net_queue_deliver(queue, sender, flags, data, size); ret = qemu_net_queue_deliver(queue, sender, flags, data, size);
@ -201,8 +198,8 @@ ssize_t qemu_net_queue_send_iov(NetQueue *queue,
ssize_t ret; ssize_t ret;
if (queue->delivering || !qemu_can_send_packet(sender)) { if (queue->delivering || !qemu_can_send_packet(sender)) {
return qemu_net_queue_append_iov(queue, sender, flags, qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
iov, iovcnt, sent_cb); return 0;
} }
ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt); ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt);
@ -228,7 +225,7 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from)
} }
} }
void qemu_net_queue_flush(NetQueue *queue) bool qemu_net_queue_flush(NetQueue *queue)
{ {
while (!QTAILQ_EMPTY(&queue->packets)) { while (!QTAILQ_EMPTY(&queue->packets)) {
NetPacket *packet; NetPacket *packet;
@ -244,7 +241,7 @@ void qemu_net_queue_flush(NetQueue *queue)
packet->size); packet->size);
if (ret == 0) { if (ret == 0) {
QTAILQ_INSERT_HEAD(&queue->packets, packet, entry); QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
break; return false;
} }
if (packet->sent_cb) { if (packet->sent_cb) {
@ -253,4 +250,5 @@ void qemu_net_queue_flush(NetQueue *queue)
g_free(packet); g_free(packet);
} }
return true;
} }

View file

@ -53,6 +53,6 @@ ssize_t qemu_net_queue_send_iov(NetQueue *queue,
NetPacketSent *sent_cb); NetPacketSent *sent_cb);
void qemu_net_queue_purge(NetQueue *queue, NetClientState *from); void qemu_net_queue_purge(NetQueue *queue, NetClientState *from);
void qemu_net_queue_flush(NetQueue *queue); bool qemu_net_queue_flush(NetQueue *queue);
#endif /* QEMU_NET_QUEUE_H */ #endif /* QEMU_NET_QUEUE_H */

View file

@ -32,6 +32,7 @@
#include "qemu-error.h" #include "qemu-error.h"
#include "qemu-option.h" #include "qemu-option.h"
#include "qemu_socket.h" #include "qemu_socket.h"
#include "iov.h"
typedef struct NetSocketState { typedef struct NetSocketState {
NetClientState nc; NetClientState nc;
@ -40,29 +41,106 @@ typedef struct NetSocketState {
int state; /* 0 = getting length, 1 = getting data */ int state; /* 0 = getting length, 1 = getting data */
unsigned int index; unsigned int index;
unsigned int packet_len; unsigned int packet_len;
unsigned int send_index; /* number of bytes sent (only SOCK_STREAM) */
uint8_t buf[4096]; uint8_t buf[4096];
struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ 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? */
bool write_poll; /* waiting to transmit data? */
} NetSocketState; } NetSocketState;
static void net_socket_accept(void *opaque); static void net_socket_accept(void *opaque);
static void net_socket_writable(void *opaque);
/* Only read packets from socket when peer can receive them */
static int net_socket_can_send(void *opaque)
{
NetSocketState *s = opaque;
return qemu_can_send_packet(&s->nc);
}
static void net_socket_update_fd_handler(NetSocketState *s)
{
qemu_set_fd_handler2(s->fd,
s->read_poll ? net_socket_can_send : NULL,
s->read_poll ? s->send_fn : NULL,
s->write_poll ? net_socket_writable : NULL,
s);
}
static void net_socket_read_poll(NetSocketState *s, bool enable)
{
s->read_poll = enable;
net_socket_update_fd_handler(s);
}
static void net_socket_write_poll(NetSocketState *s, bool enable)
{
s->write_poll = enable;
net_socket_update_fd_handler(s);
}
static void net_socket_writable(void *opaque)
{
NetSocketState *s = opaque;
net_socket_write_poll(s, false);
qemu_flush_queued_packets(&s->nc);
}
/* XXX: we consider we can send the whole packet without blocking */
static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size) static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size)
{ {
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
uint32_t len; uint32_t len = htonl(size);
len = htonl(size); struct iovec iov[] = {
{
.iov_base = &len,
.iov_len = sizeof(len),
}, {
.iov_base = (void *)buf,
.iov_len = size,
},
};
size_t remaining;
ssize_t ret;
send_all(s->fd, (const uint8_t *)&len, sizeof(len)); remaining = iov_size(iov, 2) - s->send_index;
return send_all(s->fd, buf, size); ret = iov_send(s->fd, iov, 2, s->send_index, remaining);
if (ret == -1 && errno == EAGAIN) {
ret = 0; /* handled further down */
}
if (ret == -1) {
s->send_index = 0;
return -errno;
}
if (ret < (ssize_t)remaining) {
s->send_index += ret;
net_socket_write_poll(s, true);
return 0;
}
s->send_index = 0;
return size;
} }
static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size) static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size)
{ {
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
ssize_t ret;
return sendto(s->fd, (const void *)buf, size, 0, do {
(struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); ret = sendto(s->fd, buf, size, 0,
(struct sockaddr *)&s->dgram_dst,
sizeof(s->dgram_dst));
} while (ret == -1 && errno == EINTR);
if (ret == -1 && errno == EAGAIN) {
net_socket_write_poll(s, true);
return 0;
}
return ret;
} }
static void net_socket_send(void *opaque) static void net_socket_send(void *opaque)
@ -81,7 +159,8 @@ static void net_socket_send(void *opaque)
} else if (size == 0) { } else if (size == 0) {
/* end of connection */ /* end of connection */
eoc: eoc:
qemu_set_fd_handler(s->fd, NULL, NULL, NULL); net_socket_read_poll(s, false);
net_socket_write_poll(s, false);
if (s->listen_fd != -1) { if (s->listen_fd != -1) {
qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
} }
@ -152,7 +231,8 @@ static void net_socket_send_dgram(void *opaque)
return; return;
if (size == 0) { if (size == 0) {
/* end of connection */ /* end of connection */
qemu_set_fd_handler(s->fd, NULL, NULL, NULL); net_socket_read_poll(s, false);
net_socket_write_poll(s, false);
return; return;
} }
qemu_send_packet(&s->nc, s->buf, size); qemu_send_packet(&s->nc, s->buf, size);
@ -243,7 +323,8 @@ static void net_socket_cleanup(NetClientState *nc)
{ {
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
if (s->fd != -1) { if (s->fd != -1) {
qemu_set_fd_handler(s->fd, NULL, NULL, NULL); net_socket_read_poll(s, false);
net_socket_write_poll(s, false);
close(s->fd); close(s->fd);
s->fd = -1; s->fd = -1;
} }
@ -314,8 +395,8 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
s->fd = fd; s->fd = fd;
s->listen_fd = -1; s->listen_fd = -1;
s->send_fn = net_socket_send_dgram;
qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); net_socket_read_poll(s, true);
/* mcast: save bound address as dst */ /* mcast: save bound address as dst */
if (is_connected) { if (is_connected) {
@ -332,7 +413,8 @@ err:
static void net_socket_connect(void *opaque) static void net_socket_connect(void *opaque)
{ {
NetSocketState *s = opaque; NetSocketState *s = opaque;
qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); s->send_fn = net_socket_send;
net_socket_read_poll(s, true);
} }
static NetClientInfo net_socket_info = { static NetClientInfo net_socket_info = {

View file

@ -1362,6 +1362,7 @@ Valid values for @var{type} are
Not all devices are supported on all targets. Use -net nic,model=? Not all devices are supported on all targets. Use -net nic,model=?
for a list of available devices for your target. for a list of available devices for your target.
@item -netdev user,id=@var{id}[,@var{option}][,@var{option}][,...]
@item -net user[,@var{option}][,@var{option}][,...] @item -net user[,@var{option}][,@var{option}][,...]
Use the user mode network stack which requires no administrator Use the user mode network stack which requires no administrator
privilege to run. Valid options are: privilege to run. Valid options are:
@ -1370,6 +1371,7 @@ privilege to run. Valid options are:
@item vlan=@var{n} @item vlan=@var{n}
Connect user mode stack to VLAN @var{n} (@var{n} = 0 is the default). Connect user mode stack to VLAN @var{n} (@var{n} = 0 is the default).
@item id=@var{id}
@item name=@var{name} @item name=@var{name}
Assign symbolic name for use in monitor commands. Assign symbolic name for use in monitor commands.
@ -1495,6 +1497,7 @@ processed and applied to -net user. Mixing them with the new configuration
syntax gives undefined results. Their use for new applications is discouraged syntax gives undefined results. Their use for new applications is discouraged
as they will be removed from future versions. as they will be removed from future versions.
@item -netdev tap,id=@var{id}[,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}]
@item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}] @item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}]
Connect the host TAP network interface @var{name} to VLAN @var{n}. Connect the host TAP network interface @var{name} to VLAN @var{n}.
@ -1534,6 +1537,7 @@ qemu-system-i386 linux.img \
-net nic -net tap,"helper=/usr/local/libexec/qemu-bridge-helper" -net nic -net tap,"helper=/usr/local/libexec/qemu-bridge-helper"
@end example @end example
@item -netdev bridge,id=@var{id}[,br=@var{bridge}][,helper=@var{helper}]
@item -net bridge[,vlan=@var{n}][,name=@var{name}][,br=@var{bridge}][,helper=@var{helper}] @item -net bridge[,vlan=@var{n}][,name=@var{name}][,br=@var{bridge}][,helper=@var{helper}]
Connect a host TAP network interface to a host bridge device. Connect a host TAP network interface to a host bridge device.
@ -1556,6 +1560,7 @@ qemu-system-i386 linux.img -net bridge -net nic,model=virtio
qemu-system-i386 linux.img -net bridge,br=qemubr0 -net nic,model=virtio qemu-system-i386 linux.img -net bridge,br=qemubr0 -net nic,model=virtio
@end example @end example
@item -netdev socket,id=@var{id}[,fd=@var{h}][,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}]
@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}] @item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}]
Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual
@ -1578,6 +1583,7 @@ qemu-system-i386 linux.img \
-net socket,connect=127.0.0.1:1234 -net socket,connect=127.0.0.1:1234
@end example @end example
@item -netdev socket,id=@var{id}[,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]]
@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]] @item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]]
Create a VLAN @var{n} shared with another QEMU virtual Create a VLAN @var{n} shared with another QEMU virtual
@ -1629,6 +1635,7 @@ qemu-system-i386 linux.img \
-net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4 -net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4
@end example @end example
@item -netdev vde,id=@var{id}[,sock=@var{socketpath}][,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}]
@item -net vde[,vlan=@var{n}][,name=@var{name}][,sock=@var{socketpath}] [,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}] @item -net vde[,vlan=@var{n}][,name=@var{name}][,sock=@var{socketpath}] [,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}]
Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and
listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname} listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname}