[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH RFC V2] virtio-net: announce self by guest
From: |
Jason Wang |
Subject: |
Re: [Qemu-devel] [PATCH RFC V2] virtio-net: announce self by guest |
Date: |
Mon, 14 Apr 2014 11:09:04 +0800 |
On Fri, 2014-04-11 at 22:10 +0800, 陈梁 wrote:
> Hi Jason,
> Have you ever test that adds a bridge on the virtio-net in vm and migrate the
> vm?
I tested both ipv4 and ipv6, all work well.
> The bridge may don't send garp packet(in my testing).
Several questions:
- The garp should be sent by guest or qemu not bridge. After bridge
receives the garp, it should update the fdb.
- Did you manage to capture the garp sent by qemu? If no, you should
check your configuration since this patch keep this behavior.
- Which version of guest did you use? Only recent linux driver support
this.
> BTW, how about the other
> net devices like e1000 and rtl8139? Is it better that qemu notifys qemu guest
> agent
> to force the net devices in the vm to send the garp packet?
>
Yes. But for kvm, virtio-net is preferable, it can give better
performance and is virt friendly (e.g in this case).
> Best regards
> ChenLiang
> > It's hard to track all mac addresses and their configurations (e.g
> > vlan or ipv6) in qemu. Without those informations, it's impossible to
> > build proper garp packet after migration. The only possible solution
> > to this is let guest (who knew all configurations) to do this.
> >
> > So, this patch introduces a new readonly config status bit of virtio-net,
> > VIRTIO_NET_S_ANNOUNCE which is used to notify guest to announce
> > presence of its link through config update interrupt.When guest has
> > done the announcement, it should ack the notification through
> > VIRTIO_NET_CTRL_ANNOUNCE_ACK cmd. This feature is negotiated by a new
> > feature bit VIRTIO_NET_F_ANNOUNCE (which has already been supported by
> > Linux guest).
> >
> > During load, a counter of announcing rounds were set so that the after
> > the vm is running it can trigger rounds of config interrupts to notify
> > the guest to build and send the correct garps.
> >
> > Reference:
> > RFC v1: https://lists.gnu.org/archive/html/qemu-devel/2014-03/msg02648.html
> > V7: https://lists.gnu.org/archive/html/qemu-devel/2013-03/msg01127.html
> >
> > Changes from RFC v1:
> > - clean VIRTIO_NET_S_ANNOUNCE bit during reset
> > - free announce timer during clean
> > - make announce work for non-vhost case
> >
> > Changes from V7:
> > - Instead of introducing a global method for each kind of nic, this
> > version limits the changes to virtio-net itself.
> >
> > Cc: Liuyongan <address@hidden>
> > Cc: Amos Kong <address@hidden>
> > Signed-off-by: Jason Wang <address@hidden>
> > ---
> > hw/net/virtio-net.c | 48
> > ++++++++++++++++++++++++++++++++++++++++
> > include/hw/virtio/virtio-net.h | 16 +++++++++++++
> > 2 files changed, 64 insertions(+), 0 deletions(-)
> >
> > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> > index 3626608..e2f0519 100644
> > --- a/hw/net/virtio-net.c
> > +++ b/hw/net/virtio-net.c
> > @@ -25,6 +25,7 @@
> > #include "monitor/monitor.h"
> >
> > #define VIRTIO_NET_VM_VERSION 11
> > +#define VIRTIO_NET_ANNOUNCE_ROUNDS 3
> >
> > #define MAC_TABLE_ENTRIES 64
> > #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */
> > @@ -99,6 +100,25 @@ static bool virtio_net_started(VirtIONet *n, uint8_t
> > status)
> > (n->status & VIRTIO_NET_S_LINK_UP) && vdev->vm_running;
> > }
> >
> > +static void virtio_net_announce_timer(void *opaque)
> > +{
> > + VirtIONet *n = opaque;
> > + VirtIODevice *vdev = VIRTIO_DEVICE(n);
> > +
> > + if (n->announce &&
> > + virtio_net_started(n, vdev->status) &&
> > + vdev->guest_features & (0x1 << VIRTIO_NET_F_GUEST_ANNOUNCE) &&
> > + vdev->guest_features & (0x1 << VIRTIO_NET_F_CTRL_VQ)) {
> > +
> > + n->announce--;
> > + n->status |= VIRTIO_NET_S_ANNOUNCE;
> > + virtio_notify_config(vdev);
> > + } else {
> > + timer_del(n->announce_timer);
> > + n->announce = 0;
> > + }
> > +}
> > +
> > static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
> > {
> > VirtIODevice *vdev = VIRTIO_DEVICE(n);
> > @@ -147,6 +167,8 @@ static void virtio_net_set_status(struct VirtIODevice
> > *vdev, uint8_t status)
> >
> > virtio_net_vhost_status(n, status);
> >
> > + virtio_net_announce_timer(n);
> > +
> > for (i = 0; i < n->max_queues; i++) {
> > q = &n->vqs[i];
> >
> > @@ -306,6 +328,9 @@ static void virtio_net_reset(VirtIODevice *vdev)
> > n->nobcast = 0;
> > /* multiqueue is disabled by default */
> > n->curr_queues = 1;
> > + timer_del(n->announce_timer);
> > + n->announce = 0;
> > + n->status &= ~VIRTIO_NET_S_ANNOUNCE;
> >
> > /* Flush any MAC and VLAN filter table state */
> > n->mac_table.in_use = 0;
> > @@ -710,6 +735,22 @@ static int virtio_net_handle_vlan_table(VirtIONet *n,
> > uint8_t cmd,
> > return VIRTIO_NET_OK;
> > }
> >
> > +static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd,
> > + struct iovec *iov, unsigned int
> > iov_cnt)
> > +{
> > + if (cmd == VIRTIO_NET_CTRL_ANNOUNCE_ACK) {
> > + n->status &= ~VIRTIO_NET_S_ANNOUNCE;
> > + if (n->announce) {
> > + timer_mod(n->announce_timer,
> > + qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 50 +
> > + (VIRTIO_NET_ANNOUNCE_ROUNDS - n->announce - 1) *
> > 100);
> > + }
> > + return VIRTIO_NET_OK;
> > + } else {
> > + return VIRTIO_NET_ERR;
> > + }
> > +}
> > +
> > static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
> > struct iovec *iov, unsigned int iov_cnt)
> > {
> > @@ -773,6 +814,8 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev,
> > VirtQueue *vq)
> > status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt);
> > } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) {
> > status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov,
> > iov_cnt);
> > + } else if (ctrl.class == VIRTIO_NET_CTRL_ANNOUNCE) {
> > + status = virtio_net_handle_announce(n, ctrl.cmd, iov, iov_cnt);
> > } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) {
> > status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt);
> > } else if (ctrl.class == VIRTIO_NET_CTRL_GUEST_OFFLOADS) {
> > @@ -1418,6 +1461,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque,
> > int version_id)
> > qemu_get_subqueue(n->nic, i)->link_down = link_down;
> > }
> >
> > + n->announce = VIRTIO_NET_ANNOUNCE_ROUNDS;
> > return 0;
> > }
> >
> > @@ -1529,6 +1573,8 @@ static void virtio_net_device_realize(DeviceState
> > *dev, Error **errp)
> > qemu_macaddr_default_if_unset(&n->nic_conf.macaddr);
> > memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac));
> > n->status = VIRTIO_NET_S_LINK_UP;
> > + n->announce_timer = timer_new_ns(QEMU_CLOCK_REALTIME,
> > + virtio_net_announce_timer, n);
> >
> > if (n->netclient_type) {
> > /*
> > @@ -1609,6 +1655,8 @@ static void virtio_net_device_unrealize(DeviceState
> > *dev, Error **errp)
> > }
> > }
> >
> > + timer_del(n->announce_timer);
> > + timer_free(n->announce_timer);
> > g_free(n->vqs);
> > qemu_del_nic(n->nic);
> > virtio_cleanup(vdev);
> > diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
> > index df60f16..e53b2c4 100644
> > --- a/include/hw/virtio/virtio-net.h
> > +++ b/include/hw/virtio/virtio-net.h
> > @@ -49,12 +49,14 @@
> > #define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support
> > */
> > #define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */
> > #define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */
> > +#define VIRTIO_NET_F_GUEST_ANNOUNCE 21 /* Guest can announce itself */
> > #define VIRTIO_NET_F_MQ 22 /* Device supports Receive Flow
> > * Steering */
> >
> > #define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */
> >
> > #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */
> > +#define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */
> >
> > #define TX_TIMER_INTERVAL 150000 /* 150 us */
> >
> > @@ -193,6 +195,8 @@ typedef struct VirtIONet {
> > char *netclient_name;
> > char *netclient_type;
> > uint64_t curr_guest_offloads;
> > + QEMUTimer *announce_timer;
> > + int announce;
> > } VirtIONet;
> >
> > #define VIRTIO_NET_CTRL_MAC 1
> > @@ -213,6 +217,17 @@ typedef struct VirtIONet {
> > #define VIRTIO_NET_CTRL_VLAN_DEL 1
> >
> > /*
> > + * Control link announce acknowledgement
> > + *
> > + * The command VIRTIO_NET_CTRL_ANNOUNCE_ACK is used to indicate that
> > + * driver has recevied the notification and device would clear the
> > + * VIRTIO_NET_S_ANNOUNCE bit in the status filed after it received
> > + * this command.
> > + */
> > +#define VIRTIO_NET_CTRL_ANNOUNCE 3
> > + #define VIRTIO_NET_CTRL_ANNOUNCE_ACK 0
> > +
> > +/*
> > * Control Multiqueue
> > *
> > * The command VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET
> > @@ -251,6 +266,7 @@ struct virtio_net_ctrl_mq {
> > DEFINE_PROP_BIT("guest_tso6", _state, _field,
> > VIRTIO_NET_F_GUEST_TSO6, true), \
> > DEFINE_PROP_BIT("guest_ecn", _state, _field,
> > VIRTIO_NET_F_GUEST_ECN, true), \
> > DEFINE_PROP_BIT("guest_ufo", _state, _field,
> > VIRTIO_NET_F_GUEST_UFO, true), \
> > + DEFINE_PROP_BIT("guest_announce", _state, _field,
> > VIRTIO_NET_F_GUEST_ANNOUNCE, true), \
> > DEFINE_PROP_BIT("host_tso4", _state, _field,
> > VIRTIO_NET_F_HOST_TSO4, true), \
> > DEFINE_PROP_BIT("host_tso6", _state, _field,
> > VIRTIO_NET_F_HOST_TSO6, true), \
> > DEFINE_PROP_BIT("host_ecn", _state, _field, VIRTIO_NET_F_HOST_ECN,
> > true), \
> > --
> > 1.7.1
> >
> >
>
>