On 01/09/2018 03:26 PM, Xiao Wang wrote:
When live migration is done, for the backup VM, either the virtio
frontend or the vhost backend needs to send out gratuitous RARP packet
to announce its new network location.

This patch enables VIRTIO_NET_F_GUEST_ANNOUNCE feature to support live
migration scenario where the vhost backend doesn't have the ability to
generate RARP packet.

Brief introduction of the work flow:
1. QEMU finishes live migration, pokes the backup VM with an interrupt.
2. Virtio interrupt handler reads out the interrupt status value, and
    realizes it needs to send out RARP packet to announce its location.
3. Pause device to stop worker thread touching the queues.
4. Inject a RARP packet into a Tx Queue.
5. Ack the interrupt via control queue.
6. Resume device to continue packet processing.

Signed-off-by: Xiao Wang <xiao.w.w...@intel.com>
---
  drivers/net/virtio/virtio_ethdev.c | 95 +++++++++++++++++++++++++++++++++++++-
  drivers/net/virtio/virtio_ethdev.h |  1 +
  drivers/net/virtio/virtqueue.h     | 11 +++++
  3 files changed, 105 insertions(+), 2 deletions(-)

diff --git a/drivers/net/virtio/virtio_ethdev.c 
b/drivers/net/virtio/virtio_ethdev.c
index e8ff1e449..9606df514 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -19,6 +19,8 @@
  #include <rte_pci.h>
  #include <rte_bus_pci.h>
  #include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_arp.h>
  #include <rte_common.h>
  #include <rte_errno.h>
  #include <rte_cpuflags.h>
@@ -78,6 +80,11 @@ static int virtio_dev_queue_stats_mapping_set(
        uint8_t stat_idx,
        uint8_t is_rx);
+static int make_rarp_packet(struct rte_mbuf *rarp_mbuf,
+               const struct ether_addr *mac);
+static void virtio_notify_peers(struct rte_eth_dev *dev);
+static void virtio_ack_link_announce(struct rte_eth_dev *dev);
+
  /*
   * The set of PCI devices this driver supports
   */
@@ -1272,9 +1279,89 @@ virtio_inject_pkts(struct rte_eth_dev *dev, struct 
rte_mbuf **tx_pkts,
        return ret;
  }
+#define RARP_PKT_SIZE 64
+static int
+make_rarp_packet(struct rte_mbuf *rarp_mbuf, const struct ether_addr *mac)
+{
+       struct ether_hdr *eth_hdr;
+       struct arp_hdr *rarp;
+
+       if (rarp_mbuf->buf_len < RARP_PKT_SIZE) {
+               PMD_DRV_LOG(ERR, "mbuf size too small %u (< %d)",
+                               rarp_mbuf->buf_len, RARP_PKT_SIZE);
+               return -1;
+       }
+
+       /* Ethernet header. */
+       eth_hdr = rte_pktmbuf_mtod(rarp_mbuf, struct ether_hdr *);
+       memset(eth_hdr->d_addr.addr_bytes, 0xff, ETHER_ADDR_LEN);
+       ether_addr_copy(mac, &eth_hdr->s_addr);
+       eth_hdr->ether_type = htons(ETHER_TYPE_RARP);
+
+       /* RARP header. */
+       rarp = (struct arp_hdr *)(eth_hdr + 1);
+       rarp->arp_hrd = htons(ARP_HRD_ETHER);
+       rarp->arp_pro = htons(ETHER_TYPE_IPv4);
+       rarp->arp_hln = ETHER_ADDR_LEN;
+       rarp->arp_pln = 4;
+       rarp->arp_op  = htons(ARP_OP_REVREQUEST);
+
+       ether_addr_copy(mac, &rarp->arp_data.arp_sha);
+       ether_addr_copy(mac, &rarp->arp_data.arp_tha);
+       memset(&rarp->arp_data.arp_sip, 0x00, 4);
+       memset(&rarp->arp_data.arp_tip, 0x00, 4);
+
+       rarp_mbuf->data_len = RARP_PKT_SIZE;
+       rarp_mbuf->pkt_len = RARP_PKT_SIZE;
+
+       return 0;
+}

Do you think it could make sense to have this function in a lib, as
vhost user lib does exactly the same?

I don't know if it could be useful to others than vhost/virtio though.

Thanks,
Maxime

Reply via email to