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

# By Jason Wang (2) and others
# Via Stefan Hajnoczi
* stefanha/net:
  qmp: netdev_add is like -netdev, not -net, fix documentation
  doc: document -netdev hubport
  net: reduce the unnecessary memory allocation of multiqueue
  tap: set IFF_ONE_QUEUE per default
  tap: forbid creating multiqueue tap when hub is used
  net: fix unbounded NetQueue
  net: fix qemu_flush_queued_packets() in presence of a hub
This commit is contained in:
Anthony Liguori 2013-03-04 08:20:06 -06:00
commit bf5363efcf
12 changed files with 80 additions and 24 deletions

View file

@ -1169,7 +1169,7 @@ ETEXI
{
.name = "netdev_add",
.args_type = "netdev:O",
.params = "[user|tap|socket],id=str[,prop=value][,...]",
.params = "[user|tap|socket|hubport],id=str[,prop=value][,...]",
.help = "add host network device",
.mhandler.cmd = hmp_netdev_add,
},

View file

@ -44,7 +44,7 @@ typedef struct VirtIONet
VirtIODevice vdev;
uint8_t mac[ETH_ALEN];
uint16_t status;
VirtIONetQueue vqs[MAX_QUEUE_NUM];
VirtIONetQueue *vqs;
VirtQueue *ctrl_vq;
NICState *nic;
uint32_t tx_timeout;
@ -1326,8 +1326,9 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
n->vdev.set_status = virtio_net_set_status;
n->vdev.guest_notifier_mask = virtio_net_guest_notifier_mask;
n->vdev.guest_notifier_pending = virtio_net_guest_notifier_pending;
n->max_queues = MAX(conf->queues, 1);
n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues);
n->vqs[0].rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
n->max_queues = conf->queues;
n->curr_queues = 1;
n->vqs[0].n = n;
n->tx_timeout = net->txtimer;
@ -1412,6 +1413,7 @@ void virtio_net_exit(VirtIODevice *vdev)
}
}
g_free(n->vqs);
qemu_del_nic(n->nic);
virtio_cleanup(&n->vdev);
}

View file

@ -72,7 +72,7 @@ struct NetClientState {
};
typedef struct NICState {
NetClientState ncs[MAX_QUEUE_NUM];
NetClientState *ncs;
NICConf *conf;
void *opaque;
bool peer_deleted;

View file

@ -338,3 +338,17 @@ void net_hub_check_clients(void)
}
}
}
bool net_hub_flush(NetClientState *nc)
{
NetHubPort *port;
NetHubPort *source_port = DO_UPCAST(NetHubPort, nc, nc);
int ret = 0;
QLIST_FOREACH(port, &source_port->hub->ports, next) {
if (port != source_port) {
ret += qemu_net_queue_flush(port->nc.send_queue);
}
}
return ret ? true : false;
}

View file

@ -21,5 +21,6 @@ NetClientState *net_hub_add_port(int hub_id, const char *name);
NetClientState *net_hub_find_client_by_name(int hub_id, const char *name);
void net_hub_info(Monitor *mon);
void net_hub_check_clients(void);
bool net_hub_flush(NetClientState *nc);
#endif /* NET_HUB_H */

View file

@ -235,23 +235,20 @@ NICState *qemu_new_nic(NetClientInfo *info,
const char *name,
void *opaque)
{
NetClientState *nc;
NetClientState **peers = conf->peers.ncs;
NICState *nic;
int i;
int i, queues = MAX(1, conf->queues);
assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC);
assert(info->size >= sizeof(NICState));
nc = qemu_new_net_client(info, peers[0], model, name);
nc->queue_index = 0;
nic = qemu_get_nic(nc);
nic = g_malloc0(info->size + sizeof(NetClientState) * queues);
nic->ncs = (void *)nic + info->size;
nic->conf = conf;
nic->opaque = opaque;
for (i = 1; i < conf->queues; i++) {
qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, nc->name,
for (i = 0; i < queues; i++) {
qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name,
NULL);
nic->ncs[i].queue_index = i;
}
@ -261,7 +258,7 @@ NICState *qemu_new_nic(NetClientInfo *info,
NetClientState *qemu_get_subqueue(NICState *nic, int queue_index)
{
return &nic->ncs[queue_index];
return nic->ncs + queue_index;
}
NetClientState *qemu_get_queue(NICState *nic)
@ -273,7 +270,7 @@ NICState *qemu_get_nic(NetClientState *nc)
{
NetClientState *nc0 = nc - nc->queue_index;
return DO_UPCAST(NICState, ncs[0], nc0);
return (NICState *)((void *)nc0 - nc->info->size);
}
void *qemu_get_nic_opaque(NetClientState *nc)
@ -368,6 +365,8 @@ void qemu_del_nic(NICState *nic)
qemu_cleanup_net_client(nc);
qemu_free_net_client(nc);
}
g_free(nic);
}
void qemu_foreach_nic(qemu_nic_foreach func, void *opaque)
@ -441,6 +440,12 @@ void qemu_flush_queued_packets(NetClientState *nc)
{
nc->receive_disabled = 0;
if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) {
if (net_hub_flush(nc->peer)) {
qemu_notify_event();
}
return;
}
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).

View file

@ -50,6 +50,8 @@ struct NetPacket {
struct NetQueue {
void *opaque;
uint32_t nq_maxlen;
uint32_t nq_count;
QTAILQ_HEAD(packets, NetPacket) packets;
@ -63,6 +65,8 @@ NetQueue *qemu_new_net_queue(void *opaque)
queue = g_malloc0(sizeof(NetQueue));
queue->opaque = opaque;
queue->nq_maxlen = 10000;
queue->nq_count = 0;
QTAILQ_INIT(&queue->packets);
@ -92,6 +96,9 @@ static void qemu_net_queue_append(NetQueue *queue,
{
NetPacket *packet;
if (queue->nq_count >= queue->nq_maxlen && !sent_cb) {
return; /* drop if queue full and no callback */
}
packet = g_malloc(sizeof(NetPacket) + size);
packet->sender = sender;
packet->flags = flags;
@ -99,6 +106,7 @@ static void qemu_net_queue_append(NetQueue *queue,
packet->sent_cb = sent_cb;
memcpy(packet->data, buf, size);
queue->nq_count++;
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
}
@ -113,6 +121,9 @@ static void qemu_net_queue_append_iov(NetQueue *queue,
size_t max_len = 0;
int i;
if (queue->nq_count >= queue->nq_maxlen && !sent_cb) {
return; /* drop if queue full and no callback */
}
for (i = 0; i < iovcnt; i++) {
max_len += iov[i].iov_len;
}
@ -130,6 +141,7 @@ static void qemu_net_queue_append_iov(NetQueue *queue,
packet->size += len;
}
queue->nq_count++;
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
}
@ -220,6 +232,7 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from)
QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
if (packet->sender == from) {
QTAILQ_REMOVE(&queue->packets, packet, entry);
queue->nq_count--;
g_free(packet);
}
}
@ -233,6 +246,7 @@ bool qemu_net_queue_flush(NetQueue *queue)
packet = QTAILQ_FIRST(&queue->packets);
QTAILQ_REMOVE(&queue->packets, packet, entry);
queue->nq_count--;
ret = qemu_net_queue_deliver(queue,
packet->sender,
@ -240,6 +254,7 @@ bool qemu_net_queue_flush(NetQueue *queue)
packet->data,
packet->size);
if (ret == 0) {
queue->nq_count++;
QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
return false;
}

View file

@ -42,6 +42,7 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
struct ifreq ifr;
int fd, ret;
int len = sizeof(struct virtio_net_hdr);
unsigned int features;
TFR(fd = open(PATH_NET_TUN, O_RDWR));
if (fd < 0) {
@ -51,9 +52,12 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if (*vnet_hdr) {
unsigned int features;
if (ioctl(fd, TUNGETFEATURES, &features) == 0 &&
features & IFF_ONE_QUEUE) {
ifr.ifr_flags |= IFF_ONE_QUEUE;
}
if (*vnet_hdr) {
if (ioctl(fd, TUNGETFEATURES, &features) == 0 &&
features & IFF_VNET_HDR) {
*vnet_hdr = 1;
@ -78,8 +82,6 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
}
if (mq_required) {
unsigned int features;
if ((ioctl(fd, TUNGETFEATURES, &features) != 0) ||
!(features & IFF_MULTI_QUEUE)) {
error_report("multiqueue required, but no kernel "

View file

@ -34,10 +34,11 @@
#endif
/* TUNSETIFF ifr flags */
#define IFF_TAP 0x0002
#define IFF_NO_PI 0x1000
#define IFF_VNET_HDR 0x4000
#define IFF_MULTI_QUEUE 0x0100
#define IFF_TAP 0x0002
#define IFF_NO_PI 0x1000
#define IFF_ONE_QUEUE 0x2000
#define IFF_VNET_HDR 0x4000
#define IFF_MULTI_QUEUE 0x0100
#define IFF_ATTACH_QUEUE 0x0200
#define IFF_DETACH_QUEUE 0x0400

View file

@ -693,6 +693,13 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
queues = tap->has_queues ? tap->queues : 1;
vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;
/* QEMU vlans does not support multiqueue tap, in this case peer is set.
* For -netdev, peer is always NULL. */
if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) {
error_report("Multiqueue tap cannnot be used with QEMU vlans");
return -1;
}
if (tap->has_fd) {
if (tap->has_ifname || tap->has_script || tap->has_downscript ||
tap->has_vnet_hdr || tap->has_helper || tap->has_queues ||

View file

@ -1408,7 +1408,8 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
#ifdef CONFIG_VDE
"vde|"
#endif
"socket],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
"socket|"
"hubport],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
STEXI
@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}]
@findex -net
@ -1730,6 +1731,14 @@ vde_switch -F -sock /tmp/myswitch
qemu-system-i386 linux.img -net nic -net vde,sock=/tmp/myswitch
@end example
@item -netdev hubport,id=@var{id},hubid=@var{hubid}
Create a hub port on QEMU "vlan" @var{hubid}.
The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single
netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the
required hub automatically.
@item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}]
Dump network traffic on VLAN @var{n} to file @var{file} (@file{qemu-vlan0.pcap} by default).
At most @var{len} bytes (64k by default) per packet are stored. The file format is

View file

@ -822,7 +822,7 @@ Example:
-> { "execute": "netdev_add", "arguments": { "type": "user", "id": "netdev1" } }
<- { "return": {} }
Note: The supported device options are the same ones supported by the '-net'
Note: The supported device options are the same ones supported by the '-netdev'
command-line argument, which are listed in the '-help' output or QEMU's
manual