@@ -21,6 +21,8 @@
#define TAP_VNET_HDR
+#define VIRTIO_VM_VERSION 3
+
typedef struct VirtIONet
{
VirtIODevice vdev;
@@ -32,6 +34,8 @@ typedef struct VirtIONet
QEMUTimer *tx_timer;
int tx_timer_active;
int mergeable_rx_bufs;
+ int promisc;
+ int allmulti;
} VirtIONet;
/* TODO
@@ -113,6 +117,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
{
+ VirtIONet *n = to_virtio_net(vdev);
struct {
uint8_t class;
uint8_t cmd;
@@ -134,7 +139,27 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
ctrl = (void *)elem.out_sg[0].iov_base;
status = (void *)elem.in_sg[elem.in_num - 1].iov_base;
- *status = VIRTIO_NET_ERR;
+ *status = VIRTIO_NET_OK;
+
+ if (ctrl->class == VIRTIO_NET_CTRL_RX_MODE) {
+ uint8_t *on;
+
+ if (elem.out_num != 2 || elem.out_sg[1].iov_len != sizeof(*on)) {
+ fprintf(stderr, "virtio-net ctrl invalid rx mode command\n");
+ exit(1);
+ }
+
+ on = (void *)elem.out_sg[1].iov_base;
+
+ if (ctrl->cmd == VIRTIO_NET_CTRL_RX_MODE_PROMISC)
+ n->promisc = *on;
+ else if (ctrl->cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI)
+ n->allmulti = *on;
+ else
+ *status = VIRTIO_NET_ERR;
+ } else {
+ *status = VIRTIO_NET_ERR;
+ }
virtqueue_push(vq, &elem, sizeof(*status));
virtio_notify(vdev, vq);
@@ -409,13 +434,15 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
#ifdef TAP_VNET_HDR
qemu_put_be32(f, tap_has_vnet_hdr(n->vc->vlan->first_client));
#endif
+ qemu_put_be32(f, n->promisc);
+ qemu_put_be32(f, n->allmulti);
}
static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
{
VirtIONet *n = opaque;
- if (version_id != 2)
+ if (version_id < 2 || version_id > VIRTIO_VM_VERSION)
return -EINVAL;
virtio_load(&n->vdev, f);
@@ -429,6 +456,13 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
tap_using_vnet_hdr(n->vc->vlan->first_client, 1);
#endif
+ if (version_id >= 3) {
+ n->promisc = qemu_get_be32(f);
+ n->allmulti = qemu_get_be32(f);
+ } else {
+ n->promisc = 1;
+ }
+
if (n->tx_timer_active) {
qemu_mod_timer(n->tx_timer,
qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
@@ -465,8 +499,9 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
n->tx_timer = qemu_new_timer(vm_clock, virtio_net_tx_timer, n);
n->tx_timer_active = 0;
n->mergeable_rx_bufs = 0;
+ n->promisc = 1; /* for compatibility */
- register_savevm("virtio-net", virtio_net_id++, 2,
+ register_savevm("virtio-net", virtio_net_id++, VIRTIO_VM_VERSION,
virtio_net_save, virtio_net_load, n);
return (PCIDevice *)n;
@@ -80,4 +80,8 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn);
#define VIRTIO_NET_OK 0
#define VIRTIO_NET_ERR 1
+#define VIRTIO_NET_CTRL_RX_MODE 0
+ #define VIRTIO_NET_CTRL_RX_MODE_PROMISC 0
+ #define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI 1
+
#endif
Set via control virtqueue. For compatibility with older guest drivers we need to default to promiscuous. Signed-off-by: Alex Williamson <alex.williamson@hp.com> --- qemu/hw/virtio-net.c | 41 ++++++++++++++++++++++++++++++++++++++--- qemu/hw/virtio-net.h | 4 ++++ 2 files changed, 42 insertions(+), 3 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html