@@ -900,7 +900,7 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
s->conf.macaddr = nd->macaddr;
s->conf.vlan = nd->vlan;
- s->conf.peer = nd->netdev;
+ s->conf.peers[0] = nd->netdev;
s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s);
@@ -473,7 +473,7 @@ void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd,
s->conf.macaddr = nd->macaddr;
s->conf.vlan = nd->vlan;
- s->conf.peer = nd->netdev;
+ s->conf.peers[0] = nd->netdev;
s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s);
@@ -554,16 +554,37 @@ PropertyInfo qdev_prop_chr = {
static int parse_netdev(DeviceState *dev, const char *str, void **ptr)
{
- VLANClientState *netdev = qemu_find_netdev(str);
+ VLANClientState ***nc = (VLANClientState ***)ptr;
+ VLANClientState *vcs[MAX_QUEUE_NUM];
+ int queues, i = 0;
+ int ret;
- if (netdev == NULL) {
- return -ENOENT;
+ *nc = g_malloc(MAX_QUEUE_NUM * sizeof(VLANClientState *));
+ queues = qemu_find_netdev_all(str, vcs, MAX_QUEUE_NUM);
+ if (queues == 0) {
+ ret = -ENOENT;
+ goto err;
}
- if (netdev->peer) {
- return -EEXIST;
+
+ for (i = 0; i < queues; i++) {
+ if (vcs[i] == NULL) {
+ ret = -ENOENT;
+ goto err;
+ }
+
+ if (vcs[i]->peer) {
+ ret = -EEXIST;
+ goto err;
+ }
+
+ (*nc)[i] = vcs[i];
}
- *ptr = netdev;
+
return 0;
+
+err:
+ g_free(*nc);
+ return ret;
}
static const char *print_netdev(void *ptr)
@@ -248,6 +248,7 @@ extern PropertyInfo qdev_prop_blocksize;
.defval = (bool)_defval, \
}
+
#define DEFINE_PROP_UINT8(_n, _s, _f, _d) \
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
#define DEFINE_PROP_UINT16(_n, _s, _f, _d) \
@@ -274,7 +275,7 @@ extern PropertyInfo qdev_prop_blocksize;
#define DEFINE_PROP_STRING(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
#define DEFINE_PROP_NETDEV(_n, _s, _f) \
- DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, VLANClientState*)
+ DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, VLANClientState**)
#define DEFINE_PROP_VLAN(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, VLANState*)
#define DEFINE_PROP_DRIVE(_n, _s, _f) \
@@ -238,16 +238,40 @@ NICState *qemu_new_nic(NetClientInfo *info,
{
VLANClientState *nc;
NICState *nic;
+ int i;
assert(info->type == NET_CLIENT_TYPE_NIC);
assert(info->size >= sizeof(NICState));
- nc = qemu_new_net_client(info, conf->vlan, conf->peer, model, name);
+ if (conf->peers) {
+ nc = qemu_new_net_client(info, NULL, conf->peers[0], model, name);
+ } else {
+ nc = qemu_new_net_client(info, conf->vlan, NULL, model, name);
+ }
nic = DO_UPCAST(NICState, nc, nc);
nic->conf = conf;
nic->opaque = opaque;
+ /* For compatiablity with single queue nic */
+ nic->ncs[0] = nc;
+ nc->opaque = nic;
+
+ for (i = 1 ; i < conf->queues; i++) {
+ VLANClientState *vc = g_malloc0(sizeof(*vc));
+ vc->opaque = nic;
+ nic->ncs[i] = vc;
+ vc->peer = conf->peers[i];
+ vc->info = info;
+ vc->queue_index = i;
+ vc->peer->peer = vc;
+ QTAILQ_INSERT_TAIL(&non_vlan_clients, vc, next);
+
+ vc->send_queue = qemu_new_net_queue(qemu_deliver_packet,
+ qemu_deliver_packet_iov,
+ vc);
+ }
+
return nic;
}
@@ -283,11 +307,10 @@ void qemu_del_vlan_client(VLANClientState *vc)
{
/* If there is a peer NIC, delete and cleanup client, but do not free. */
if (!vc->vlan && vc->peer && vc->peer->info->type == NET_CLIENT_TYPE_NIC) {
- NICState *nic = DO_UPCAST(NICState, nc, vc->peer);
- if (nic->peer_deleted) {
+ if (vc->peer_deleted) {
return;
}
- nic->peer_deleted = true;
+ vc->peer_deleted = true;
/* Let NIC know peer is gone. */
vc->peer->link_down = true;
if (vc->peer->info->link_status_changed) {
@@ -299,8 +322,7 @@ void qemu_del_vlan_client(VLANClientState *vc)
/* If this is a peer NIC and peer has already been deleted, free it now. */
if (!vc->vlan && vc->peer && vc->info->type == NET_CLIENT_TYPE_NIC) {
- NICState *nic = DO_UPCAST(NICState, nc, vc);
- if (nic->peer_deleted) {
+ if (vc->peer_deleted) {
qemu_free_vlan_client(vc->peer);
}
}
@@ -342,14 +364,14 @@ void qemu_foreach_nic(qemu_nic_foreach func, void *opaque)
QTAILQ_FOREACH(nc, &non_vlan_clients, next) {
if (nc->info->type == NET_CLIENT_TYPE_NIC) {
- func(DO_UPCAST(NICState, nc, nc), opaque);
+ func((NICState *)nc->opaque, opaque);
}
}
QTAILQ_FOREACH(vlan, &vlans, next) {
QTAILQ_FOREACH(nc, &vlan->clients, next) {
if (nc->info->type == NET_CLIENT_TYPE_NIC) {
- func(DO_UPCAST(NICState, nc, nc), opaque);
+ func((NICState *)nc->opaque, opaque);
}
}
}
@@ -674,6 +696,26 @@ VLANClientState *qemu_find_netdev(const char *id)
return NULL;
}
+int qemu_find_netdev_all(const char *id, VLANClientState **vcs, int max)
+{
+ VLANClientState *vc;
+ int ret = 0;
+
+ QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+ if (vc->info->type == NET_CLIENT_TYPE_NIC) {
+ continue;
+ }
+ if (!strcmp(vc->name, id) && ret < max) {
+ vcs[ret++] = vc;
+ }
+ if (ret >= max) {
+ break;
+ }
+ }
+
+ return ret;
+}
+
static int nic_get_free_idx(void)
{
int index;
@@ -12,20 +12,24 @@ struct MACAddr {
uint8_t a[6];
};
+#define MAX_QUEUE_NUM 32
+
/* qdev nic properties */
typedef struct NICConf {
MACAddr macaddr;
VLANState *vlan;
- VLANClientState *peer;
+ VLANClientState **peers;
int32_t bootindex;
+ int32_t queues;
} NICConf;
#define DEFINE_NIC_PROPERTIES(_state, _conf) \
DEFINE_PROP_MACADDR("mac", _state, _conf.macaddr), \
DEFINE_PROP_VLAN("vlan", _state, _conf.vlan), \
- DEFINE_PROP_NETDEV("netdev", _state, _conf.peer), \
- DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1)
+ DEFINE_PROP_NETDEV("netdev", _state, _conf.peers), \
+ DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1), \
+ DEFINE_PROP_INT32("queues", _state, _conf.queues, 1)
/* VLANs support */
@@ -72,13 +76,16 @@ struct VLANClientState {
char *name;
char info_str[256];
unsigned receive_disabled : 1;
+ unsigned int queue_index;
+ bool peer_deleted;
+ void *opaque;
};
typedef struct NICState {
VLANClientState nc;
+ VLANClientState *ncs[MAX_QUEUE_NUM];
NICConf *conf;
void *opaque;
- bool peer_deleted;
} NICState;
struct VLANState {
@@ -90,6 +97,7 @@ struct VLANState {
VLANState *qemu_find_vlan(int id, int allocate);
VLANClientState *qemu_find_netdev(const char *id);
+int qemu_find_netdev_all(const char *id, VLANClientState **vcs, int max);
VLANClientState *qemu_new_net_client(NetClientInfo *info,
VLANState *vlan,
VLANClientState *peer,
This patch adds the multiqueues support for emulated nics. Each VLANClientState pairs are now abstract as a queue instead of a nic, and multiple VLANClientState pointers were stored in the NICState. A queue_index were also introduced to let the emulated nics know which queue the packet were came from or sent out. Virtio-net would be the first user. Signed-off-by: Jason Wang <jasowang@redhat.com> --- hw/dp8393x.c | 2 +- hw/mcf_fec.c | 2 +- hw/qdev-properties.c | 33 +++++++++++++++++++++++----- hw/qdev.h | 3 ++- net.c | 58 +++++++++++++++++++++++++++++++++++++++++++------- net.h | 16 ++++++++++---- 6 files changed, 93 insertions(+), 21 deletions(-)