vhost: export APIs for live migration support
Export few APIs for the vhost-user driver to log the guest memory writes, which is a must for live migration support. This patch basically moves vhost_log_write() and vhost_log_used_vring() into vhost.h and then add an wrapper (the public API) to them. Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com> Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com>
This commit is contained in:
parent
abd53c16b6
commit
52f8091f05
lib/librte_vhost
@ -41,5 +41,7 @@ DPDK_17.05 {
|
|||||||
rte_vhost_get_vhost_vring;
|
rte_vhost_get_vhost_vring;
|
||||||
rte_vhost_get_vring_num;
|
rte_vhost_get_vring_num;
|
||||||
rte_vhost_gpa_to_vva;
|
rte_vhost_gpa_to_vva;
|
||||||
|
rte_vhost_log_used_vring;
|
||||||
|
rte_vhost_log_write;
|
||||||
|
|
||||||
} DPDK_16.07;
|
} DPDK_16.07;
|
||||||
|
@ -132,6 +132,49 @@ rte_vhost_gpa_to_vva(struct rte_vhost_memory *mem, uint64_t gpa)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define RTE_VHOST_NEED_LOG(features) ((features) & (1ULL << VHOST_F_LOG_ALL))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the memory write start with given address.
|
||||||
|
*
|
||||||
|
* This function only need be invoked when the live migration starts.
|
||||||
|
* Therefore, we won't need call it at all in the most of time. For
|
||||||
|
* making the performance impact be minimum, it's suggested to do a
|
||||||
|
* check before calling it:
|
||||||
|
*
|
||||||
|
* if (unlikely(RTE_VHOST_NEED_LOG(features)))
|
||||||
|
* rte_vhost_log_write(vid, addr, len);
|
||||||
|
*
|
||||||
|
* @param vid
|
||||||
|
* vhost device ID
|
||||||
|
* @param addr
|
||||||
|
* the starting address for write
|
||||||
|
* @param len
|
||||||
|
* the length to write
|
||||||
|
*/
|
||||||
|
void rte_vhost_log_write(int vid, uint64_t addr, uint64_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the used ring update start at given offset.
|
||||||
|
*
|
||||||
|
* Same as rte_vhost_log_write, it's suggested to do a check before
|
||||||
|
* calling it:
|
||||||
|
*
|
||||||
|
* if (unlikely(RTE_VHOST_NEED_LOG(features)))
|
||||||
|
* rte_vhost_log_used_vring(vid, vring_idx, offset, len);
|
||||||
|
*
|
||||||
|
* @param vid
|
||||||
|
* vhost device ID
|
||||||
|
* @param vring_idx
|
||||||
|
* the vring index
|
||||||
|
* @param offset
|
||||||
|
* the offset inside the used ring
|
||||||
|
* @param len
|
||||||
|
* the length to write
|
||||||
|
*/
|
||||||
|
void rte_vhost_log_used_vring(int vid, uint16_t vring_idx,
|
||||||
|
uint64_t offset, uint64_t len);
|
||||||
|
|
||||||
int rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable);
|
int rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -444,3 +444,34 @@ rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable)
|
|||||||
dev->virtqueue[queue_id]->used->flags = VRING_USED_F_NO_NOTIFY;
|
dev->virtqueue[queue_id]->used->flags = VRING_USED_F_NO_NOTIFY;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rte_vhost_log_write(int vid, uint64_t addr, uint64_t len)
|
||||||
|
{
|
||||||
|
struct virtio_net *dev = get_device(vid);
|
||||||
|
|
||||||
|
if (dev == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vhost_log_write(dev, addr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rte_vhost_log_used_vring(int vid, uint16_t vring_idx,
|
||||||
|
uint64_t offset, uint64_t len)
|
||||||
|
{
|
||||||
|
struct virtio_net *dev;
|
||||||
|
struct vhost_virtqueue *vq;
|
||||||
|
|
||||||
|
dev = get_device(vid);
|
||||||
|
if (dev == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (vring_idx >= VHOST_MAX_VRING)
|
||||||
|
return;
|
||||||
|
vq = dev->virtqueue[vring_idx];
|
||||||
|
if (!vq)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vhost_log_used_vring(dev, vq, offset, len);
|
||||||
|
}
|
||||||
|
@ -198,6 +198,44 @@ struct virtio_net {
|
|||||||
struct guest_page *guest_pages;
|
struct guest_page *guest_pages;
|
||||||
} __rte_cache_aligned;
|
} __rte_cache_aligned;
|
||||||
|
|
||||||
|
|
||||||
|
#define VHOST_LOG_PAGE 4096
|
||||||
|
|
||||||
|
static inline void __attribute__((always_inline))
|
||||||
|
vhost_log_page(uint8_t *log_base, uint64_t page)
|
||||||
|
{
|
||||||
|
log_base[page / 8] |= 1 << (page % 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __attribute__((always_inline))
|
||||||
|
vhost_log_write(struct virtio_net *dev, uint64_t addr, uint64_t len)
|
||||||
|
{
|
||||||
|
uint64_t page;
|
||||||
|
|
||||||
|
if (likely(((dev->features & (1ULL << VHOST_F_LOG_ALL)) == 0) ||
|
||||||
|
!dev->log_base || !len))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (unlikely(dev->log_size <= ((addr + len - 1) / VHOST_LOG_PAGE / 8)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* To make sure guest memory updates are committed before logging */
|
||||||
|
rte_smp_wmb();
|
||||||
|
|
||||||
|
page = addr / VHOST_LOG_PAGE;
|
||||||
|
while (page * VHOST_LOG_PAGE < addr + len) {
|
||||||
|
vhost_log_page((uint8_t *)(uintptr_t)dev->log_base, page);
|
||||||
|
page += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __attribute__((always_inline))
|
||||||
|
vhost_log_used_vring(struct virtio_net *dev, struct vhost_virtqueue *vq,
|
||||||
|
uint64_t offset, uint64_t len)
|
||||||
|
{
|
||||||
|
vhost_log_write(dev, vq->log_guest_addr + offset, len);
|
||||||
|
}
|
||||||
|
|
||||||
/* Macros for printing using RTE_LOG */
|
/* Macros for printing using RTE_LOG */
|
||||||
#define RTE_LOGTYPE_VHOST_CONFIG RTE_LOGTYPE_USER1
|
#define RTE_LOGTYPE_VHOST_CONFIG RTE_LOGTYPE_USER1
|
||||||
#define RTE_LOGTYPE_VHOST_DATA RTE_LOGTYPE_USER1
|
#define RTE_LOGTYPE_VHOST_DATA RTE_LOGTYPE_USER1
|
||||||
|
@ -48,42 +48,6 @@
|
|||||||
#include "vhost.h"
|
#include "vhost.h"
|
||||||
|
|
||||||
#define MAX_PKT_BURST 32
|
#define MAX_PKT_BURST 32
|
||||||
#define VHOST_LOG_PAGE 4096
|
|
||||||
|
|
||||||
static inline void __attribute__((always_inline))
|
|
||||||
vhost_log_page(uint8_t *log_base, uint64_t page)
|
|
||||||
{
|
|
||||||
log_base[page / 8] |= 1 << (page % 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __attribute__((always_inline))
|
|
||||||
vhost_log_write(struct virtio_net *dev, uint64_t addr, uint64_t len)
|
|
||||||
{
|
|
||||||
uint64_t page;
|
|
||||||
|
|
||||||
if (likely(((dev->features & (1ULL << VHOST_F_LOG_ALL)) == 0) ||
|
|
||||||
!dev->log_base || !len))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (unlikely(dev->log_size <= ((addr + len - 1) / VHOST_LOG_PAGE / 8)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* To make sure guest memory updates are committed before logging */
|
|
||||||
rte_smp_wmb();
|
|
||||||
|
|
||||||
page = addr / VHOST_LOG_PAGE;
|
|
||||||
while (page * VHOST_LOG_PAGE < addr + len) {
|
|
||||||
vhost_log_page((uint8_t *)(uintptr_t)dev->log_base, page);
|
|
||||||
page += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __attribute__((always_inline))
|
|
||||||
vhost_log_used_vring(struct virtio_net *dev, struct vhost_virtqueue *vq,
|
|
||||||
uint64_t offset, uint64_t len)
|
|
||||||
{
|
|
||||||
vhost_log_write(dev, vq->log_guest_addr + offset, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
is_valid_virt_queue_idx(uint32_t idx, int is_tx, uint32_t nr_vring)
|
is_valid_virt_queue_idx(uint32_t idx, int is_tx, uint32_t nr_vring)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user