mirror of https://github.com/xemu-project/xemu.git
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:
commit
bf5363efcf
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ struct NetClientState {
|
|||
};
|
||||
|
||||
typedef struct NICState {
|
||||
NetClientState ncs[MAX_QUEUE_NUM];
|
||||
NetClientState *ncs;
|
||||
NICConf *conf;
|
||||
void *opaque;
|
||||
bool peer_deleted;
|
||||
|
|
14
net/hub.c
14
net/hub.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
25
net/net.c
25
net/net.c
|
@ -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).
|
||||
|
|
15
net/queue.c
15
net/queue.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 ||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue