vdpa/mlx5: support live migration

Add support for live migration feature by the HW:
	Create a single Mkey that maps the memory address space of the
		VHOST live migration log file.
	Modify VIRTIO_NET_Q object and provide vhost_log_page,
		dirty_bitmap_mkey, dirty_bitmap_size, dirty_bitmap_addr
		and dirty_bitmap_dump_enable.
	Modify VIRTIO_NET_Q object and move state to SUSPEND.
	Query VIRTIO_NET_Q and get hw_available_idx and hw_used_idx.

Signed-off-by: Matan Azrad <matan@mellanox.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>
Acked-by: Maxime Coquelin <maxime.coquelin@redhat.com>
This commit is contained in:
Matan Azrad 2020-02-02 16:03:51 +00:00 committed by Ferruh Yigit
parent 62c813706e
commit 9d39e57f21
7 changed files with 235 additions and 3 deletions

View File

@ -9,6 +9,7 @@ guest csum = Y
host tso4 = Y
host tso6 = Y
version 1 = Y
log all = Y
any layout = Y
guest announce = Y
mq = Y

View File

@ -12,6 +12,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_VDPA_PMD) += mlx5_vdpa_mem.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_VDPA_PMD) += mlx5_vdpa_event.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_VDPA_PMD) += mlx5_vdpa_virtq.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_VDPA_PMD) += mlx5_vdpa_steer.c
SRCS-$(CONFIG_RTE_LIBRTE_MLX5_VDPA_PMD) += mlx5_vdpa_lm.c
# Basic CFLAGS.

View File

@ -16,6 +16,7 @@ sources = files(
'mlx5_vdpa_event.c',
'mlx5_vdpa_virtq.c',
'mlx5_vdpa_steer.c',
'mlx5_vdpa_lm.c',
)
cflags_options = [
'-std=c11',

View File

@ -19,7 +19,8 @@
(1ULL << VIRTIO_F_ANY_LAYOUT) | \
(1ULL << VIRTIO_NET_F_MQ) | \
(1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE) | \
(1ULL << VIRTIO_F_ORDER_PLATFORM))
(1ULL << VIRTIO_F_ORDER_PLATFORM) | \
(1ULL << VHOST_F_LOG_ALL))
#define MLX5_VDPA_PROTOCOL_FEATURES \
((1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ) | \
@ -127,6 +128,45 @@ mlx5_vdpa_set_vring_state(int vid, int vring, int state)
return mlx5_vdpa_virtq_enable(virtq, state);
}
static int
mlx5_vdpa_features_set(int vid)
{
int did = rte_vhost_get_vdpa_device_id(vid);
struct mlx5_vdpa_priv *priv = mlx5_vdpa_find_priv_resource_by_did(did);
uint64_t log_base, log_size;
uint64_t features;
int ret;
if (priv == NULL) {
DRV_LOG(ERR, "Invalid device id: %d.", did);
return -EINVAL;
}
ret = rte_vhost_get_negotiated_features(vid, &features);
if (ret) {
DRV_LOG(ERR, "Failed to get negotiated features.");
return ret;
}
if (RTE_VHOST_NEED_LOG(features)) {
ret = rte_vhost_get_log_base(vid, &log_base, &log_size);
if (ret) {
DRV_LOG(ERR, "Failed to get log base.");
return ret;
}
ret = mlx5_vdpa_dirty_bitmap_set(priv, log_base, log_size);
if (ret) {
DRV_LOG(ERR, "Failed to set dirty bitmap.");
return ret;
}
DRV_LOG(INFO, "mlx5 vdpa: enabling dirty logging...");
ret = mlx5_vdpa_logging_enable(priv, 1);
if (ret) {
DRV_LOG(ERR, "Failed t enable dirty logging.");
return ret;
}
}
return 0;
}
static struct rte_vdpa_dev_ops mlx5_vdpa_ops = {
.get_queue_num = mlx5_vdpa_get_queue_num,
.get_features = mlx5_vdpa_get_vdpa_features,
@ -134,7 +174,7 @@ static struct rte_vdpa_dev_ops mlx5_vdpa_ops = {
.dev_conf = NULL,
.dev_close = NULL,
.set_vring_state = mlx5_vdpa_set_vring_state,
.set_features = NULL,
.set_features = mlx5_vdpa_features_set,
.migration_done = NULL,
.get_vfio_group_fd = NULL,
.get_vfio_device_fd = NULL,

View File

@ -250,4 +250,59 @@ int mlx5_vdpa_steer_unset(struct mlx5_vdpa_priv *priv);
*/
int mlx5_vdpa_steer_setup(struct mlx5_vdpa_priv *priv);
/**
* Enable\Disable live migration logging.
*
* @param[in] priv
* The vdpa driver private structure.
* @param[in] enable
* Set for enable, unset for disable.
*
* @return
* 0 on success, a negative value otherwise.
*/
int mlx5_vdpa_logging_enable(struct mlx5_vdpa_priv *priv, int enable);
/**
* Set dirty bitmap logging to allow live migration.
*
* @param[in] priv
* The vdpa driver private structure.
* @param[in] log_base
* Vhost log base.
* @param[in] log_size
* Vhost log size.
*
* @return
* 0 on success, a negative value otherwise.
*/
int mlx5_vdpa_dirty_bitmap_set(struct mlx5_vdpa_priv *priv, uint64_t log_base,
uint64_t log_size);
/**
* Log all virtqs information for live migration.
*
* @param[in] priv
* The vdpa driver private structure.
* @param[in] enable
* Set for enable, unset for disable.
*
* @return
* 0 on success, a negative value otherwise.
*/
int mlx5_vdpa_lm_log(struct mlx5_vdpa_priv *priv);
/**
* Modify virtq state to be ready or suspend.
*
* @param[in] virtq
* The vdpa driver private virtq structure.
* @param[in] state
* Set for ready, otherwise suspend.
*
* @return
* 0 on success, a negative value otherwise.
*/
int mlx5_vdpa_virtq_modify(struct mlx5_vdpa_virtq *virtq, int state);
#endif /* RTE_PMD_MLX5_VDPA_H_ */

View File

@ -0,0 +1,129 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2019 Mellanox Technologies, Ltd
*/
#include <rte_malloc.h>
#include <rte_errno.h>
#include "mlx5_vdpa_utils.h"
#include "mlx5_vdpa.h"
int
mlx5_vdpa_logging_enable(struct mlx5_vdpa_priv *priv, int enable)
{
struct mlx5_devx_virtq_attr attr = {
.type = MLX5_VIRTQ_MODIFY_TYPE_DIRTY_BITMAP_DUMP_ENABLE,
.dirty_bitmap_dump_enable = enable,
};
struct mlx5_vdpa_virtq *virtq;
SLIST_FOREACH(virtq, &priv->virtq_list, next) {
attr.queue_index = virtq->index;
if (mlx5_devx_cmd_modify_virtq(virtq->virtq, &attr)) {
DRV_LOG(ERR, "Failed to modify virtq %d logging.",
virtq->index);
return -1;
}
}
return 0;
}
int
mlx5_vdpa_dirty_bitmap_set(struct mlx5_vdpa_priv *priv, uint64_t log_base,
uint64_t log_size)
{
struct mlx5_devx_mkey_attr mkey_attr = {
.addr = (uintptr_t)log_base,
.size = log_size,
.pd = priv->pdn,
.pg_access = 1,
.klm_array = NULL,
.klm_num = 0,
};
struct mlx5_devx_virtq_attr attr = {
.type = MLX5_VIRTQ_MODIFY_TYPE_DIRTY_BITMAP_PARAMS,
.dirty_bitmap_addr = log_base,
.dirty_bitmap_size = log_size,
};
struct mlx5_vdpa_query_mr *mr = rte_malloc(__func__, sizeof(*mr), 0);
struct mlx5_vdpa_virtq *virtq;
if (!mr) {
DRV_LOG(ERR, "Failed to allocate mem for lm mr.");
return -1;
}
mr->umem = mlx5_glue->devx_umem_reg(priv->ctx,
(void *)(uintptr_t)log_base,
log_size, IBV_ACCESS_LOCAL_WRITE);
if (!mr->umem) {
DRV_LOG(ERR, "Failed to register umem for lm mr.");
goto err;
}
mkey_attr.umem_id = mr->umem->umem_id;
mr->mkey = mlx5_devx_cmd_mkey_create(priv->ctx, &mkey_attr);
if (!mr->mkey) {
DRV_LOG(ERR, "Failed to create Mkey for lm.");
goto err;
}
attr.dirty_bitmap_mkey = mr->mkey->id;
SLIST_FOREACH(virtq, &priv->virtq_list, next) {
attr.queue_index = virtq->index;
if (mlx5_devx_cmd_modify_virtq(virtq->virtq, &attr)) {
DRV_LOG(ERR, "Failed to modify virtq %d for lm.",
virtq->index);
goto err;
}
}
mr->is_indirect = 0;
SLIST_INSERT_HEAD(&priv->mr_list, mr, next);
return 0;
err:
if (mr->mkey)
mlx5_devx_cmd_destroy(mr->mkey);
if (mr->umem)
mlx5_glue->devx_umem_dereg(mr->umem);
rte_free(mr);
return -1;
}
#define MLX5_VDPA_USED_RING_LEN(size) \
((size) * sizeof(struct vring_used_elem) + sizeof(uint16_t) * 3)
int
mlx5_vdpa_lm_log(struct mlx5_vdpa_priv *priv)
{
struct mlx5_devx_virtq_attr attr = {0};
struct mlx5_vdpa_virtq *virtq;
uint64_t features;
int ret = rte_vhost_get_negotiated_features(priv->vid, &features);
if (ret) {
DRV_LOG(ERR, "Failed to get negotiated features.");
return -1;
}
if (!RTE_VHOST_NEED_LOG(features))
return 0;
SLIST_FOREACH(virtq, &priv->virtq_list, next) {
ret = mlx5_vdpa_virtq_modify(virtq, 0);
if (ret)
return -1;
if (mlx5_devx_cmd_query_virtq(virtq->virtq, &attr)) {
DRV_LOG(ERR, "Failed to query virtq %d.", virtq->index);
return -1;
}
DRV_LOG(INFO, "Query vid %d vring %d: hw_available_idx=%d, "
"hw_used_index=%d", priv->vid, virtq->index,
attr.hw_available_index, attr.hw_used_index);
ret = rte_vhost_set_vring_base(priv->vid, virtq->index,
attr.hw_available_index,
attr.hw_used_index);
if (ret) {
DRV_LOG(ERR, "Failed to set virtq %d base.",
virtq->index);
return -1;
}
rte_vhost_log_used_vring(priv->vid, virtq->index, 0,
MLX5_VDPA_USED_RING_LEN(virtq->vq_size));
}
return 0;
}

View File

@ -112,7 +112,7 @@ mlx5_vdpa_virtqs_release(struct mlx5_vdpa_priv *priv)
priv->features = 0;
}
static int
int
mlx5_vdpa_virtq_modify(struct mlx5_vdpa_virtq *virtq, int state)
{
struct mlx5_devx_virtq_attr attr = {
@ -253,6 +253,11 @@ mlx5_vdpa_virtq_setup(struct mlx5_vdpa_priv *priv,
if (mlx5_vdpa_virtq_modify(virtq, 1))
goto error;
virtq->enable = 1;
virtq->priv = priv;
/* Be sure notifications are not missed during configuration. */
claim_zero(rte_vhost_enable_guest_notification(priv->vid, index, 1));
rte_write32(virtq->index, priv->virtq_db_addr);
/* Setup doorbell mapping. */
virtq->intr_handle.fd = vq.kickfd;
virtq->intr_handle.type = RTE_INTR_HANDLE_EXT;
if (rte_intr_callback_register(&virtq->intr_handle,