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 <liuyon...@huawei.com> > > Cc: Amos Kong <ak...@redhat.com> > > Signed-off-by: Jason Wang <jasow...@redhat.com> > > --- > > 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 > > > > > >