[v2,2/2] vhost: support requests only handled by external backend

Message ID 20190313155504.15087-3-maxime.coquelin@redhat.com
State New
Delegated to: Maxime Coquelin
Headers show
Series
  • vhost: Support external backend only vhost-user requests
Related show

Checks

Context Check Description
ci/Intel-compilation success Compilation OK
ci/checkpatch success coding style OK

Commit Message

Maxime Coquelin March 13, 2019, 3:55 p.m.
External backends may have specific requests to handle, and so
we don't want the vhost-user lib to handle these requests as
errors.

This patch also changes the experimental API by introducing
RTE_VHOST_MSG_RESULT_NOT_HANDLED so that vhost-user lib
can report an error if a message is handled neither by
the vhost-user library nor by the external backend.

The logic changes a bit so that if the callback returns
with ERR, OK or REPLY, it is considered the message
is handled by the external backend so it won't be
handled by the vhost-user library.
It is still possible for an external backend to listen
to requests that have to be handled by the vhost-user
library like SET_MEM_TABLE, but the callback have to
return NOT_HANDLED in that case.

Vhost-crypto backend is ialso adapted to this API change.

Suggested-by: Ilya Maximets <i.maximets@samsung.com>
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
Tested-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
---
 lib/librte_vhost/rte_vhost.h    | 33 ++++---------
 lib/librte_vhost/vhost_crypto.c | 10 +++-
 lib/librte_vhost/vhost_user.c   | 82 +++++++++++++++++++++------------
 3 files changed, 69 insertions(+), 56 deletions(-)

Comments

Ilya Maximets March 13, 2019, 4:09 p.m. | #1
On 13.03.2019 18:55, Maxime Coquelin wrote:
> External backends may have specific requests to handle, and so
> we don't want the vhost-user lib to handle these requests as
> errors.
> 
> This patch also changes the experimental API by introducing
> RTE_VHOST_MSG_RESULT_NOT_HANDLED so that vhost-user lib
> can report an error if a message is handled neither by
> the vhost-user library nor by the external backend.
> 
> The logic changes a bit so that if the callback returns
> with ERR, OK or REPLY, it is considered the message
> is handled by the external backend so it won't be
> handled by the vhost-user library.
> It is still possible for an external backend to listen
> to requests that have to be handled by the vhost-user
> library like SET_MEM_TABLE, but the callback have to
> return NOT_HANDLED in that case.
> 
> Vhost-crypto backend is ialso adapted to this API change.
> 
> Suggested-by: Ilya Maximets <i.maximets@samsung.com>
> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
> Tested-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
> ---
>  lib/librte_vhost/rte_vhost.h    | 33 ++++---------
>  lib/librte_vhost/vhost_crypto.c | 10 +++-
>  lib/librte_vhost/vhost_user.c   | 82 +++++++++++++++++++++------------
>  3 files changed, 69 insertions(+), 56 deletions(-)
> 
> diff --git a/lib/librte_vhost/rte_vhost.h b/lib/librte_vhost/rte_vhost.h
> index c9c392975..8ab4ff299 100644
> --- a/lib/librte_vhost/rte_vhost.h
> +++ b/lib/librte_vhost/rte_vhost.h
> @@ -121,6 +121,8 @@ enum rte_vhost_msg_result {
>  	RTE_VHOST_MSG_RESULT_OK =  0,
>  	/* Message handling successful and reply prepared */
>  	RTE_VHOST_MSG_RESULT_REPLY =  1,
> +	/* Message not handled */
> +	RTE_VHOST_MSG_RESULT_NOT_HANDLED,
>  };
>  
>  /**
> @@ -131,37 +133,20 @@ enum rte_vhost_msg_result {

/**
 * Function prototype for the vhost backend to handler specific vhost user
 * messages prior to the master message handling

Now you have definition of pre handler for a common handler type.

It should be updated. Probably just cropped a bit (and s/handler/handle/):

/**
 * Function prototype for the vhost backend to handle specific vhost user
 * messages.

>   *  vhost device id
>   * @param msg
>   *  Message pointer.
> - * @param skip_master
> - *  If the handler requires skipping the master message handling, this variable
> - *  shall be written 1, otherwise 0.
>   * @return
> - *  VH_RESULT_OK on success, VH_RESULT_REPLY on success with reply,
> - *  VH_RESULT_ERR on failure
> + *  RTE_VHOST_MSG_RESULT_OK on success,
> + *  RTE_VHOST_MSG_RESULT_REPLY on success with reply,
> + *  RTE_VHOST_MSG_RESULT_ERR on failure,
> + *  RTE_VHOST_MSG_RESULT_NOT_HANDLED if message was not handled.
>   */
> -typedef enum rte_vhost_msg_result (*rte_vhost_msg_pre_handle)(int vid,
> -		void *msg, uint32_t *skip_master);
> -
> -/**
> - * Function prototype for the vhost backend to handler specific vhost user
> - * messages after the master message handling is done
> - *
> - * @param vid
> - *  vhost device id
> - * @param msg
> - *  Message pointer.
> - * @return
> - *  VH_RESULT_OK on success, VH_RESULT_REPLY on success with reply,
> - *  VH_RESULT_ERR on failure
> - */
> -typedef enum rte_vhost_msg_result (*rte_vhost_msg_post_handle)(int vid,
> -		void *msg);
> +typedef enum rte_vhost_msg_result (*rte_vhost_msg_handle)(int vid, void *msg);
>  
>  /**
>   * Optional vhost user message handlers.
>   */
>  struct rte_vhost_user_extern_ops {
> -	rte_vhost_msg_pre_handle pre_msg_handle;
> -	rte_vhost_msg_post_handle post_msg_handle;

What about some comments here?

        /* Called prior to the master message handling. */
> +	rte_vhost_msg_handle pre_msg_handle;

        /* Called after the master message handling. */
> +	rte_vhost_msg_handle post_msg_handle;
>  };
>  
>  /**
> diff --git a/lib/librte_vhost/vhost_crypto.c b/lib/librte_vhost/vhost_crypto.c
> index 0f437c4a1..9b4b850e8 100644
> --- a/lib/librte_vhost/vhost_crypto.c
> +++ b/lib/librte_vhost/vhost_crypto.c
> @@ -453,14 +453,20 @@ vhost_crypto_msg_post_handler(int vid, void *msg)
>  		return RTE_VHOST_MSG_RESULT_ERR;
>  	}
>  
> -	if (vmsg->request.master == VHOST_USER_CRYPTO_CREATE_SESS) {
> +	switch (vmsg->request.master) {
> +	case VHOST_USER_CRYPTO_CREATE_SESS:
>  		vhost_crypto_create_sess(vcrypto,
>  				&vmsg->payload.crypto_session);
>  		vmsg->fd_num = 0;
>  		ret = RTE_VHOST_MSG_RESULT_REPLY;
> -	} else if (vmsg->request.master == VHOST_USER_CRYPTO_CLOSE_SESS) {
> +		break;
> +	case VHOST_USER_CRYPTO_CLOSE_SESS:
>  		if (vhost_crypto_close_sess(vcrypto, vmsg->payload.u64))
>  			ret = RTE_VHOST_MSG_RESULT_ERR;
> +		break;
> +	default:
> +		ret = RTE_VHOST_MSG_RESULT_NOT_HANDLED;
> +		break;
>  	}
>  
>  	return ret;
> diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c
> index 555d09ad9..39756fce7 100644
> --- a/lib/librte_vhost/vhost_user.c
> +++ b/lib/librte_vhost/vhost_user.c
> @@ -1910,7 +1910,7 @@ vhost_user_msg_handler(int vid, int fd)
>  	int did = -1;
>  	int ret;
>  	int unlock_required = 0;
> -	uint32_t skip_master = 0;
> +	bool handled;
>  	int request;
>  
>  	dev = get_device(vid);
> @@ -1928,27 +1928,30 @@ vhost_user_msg_handler(int vid, int fd)
>  	}
>  
>  	ret = read_vhost_message(fd, &msg);
> -	if (ret <= 0 || msg.request.master >= VHOST_USER_MAX) {
> +	if (ret <= 0) {
>  		if (ret < 0)
>  			RTE_LOG(ERR, VHOST_CONFIG,
>  				"vhost read message failed\n");
> -		else if (ret == 0)
> +		else
>  			RTE_LOG(INFO, VHOST_CONFIG,
>  				"vhost peer closed\n");
> -		else
> -			RTE_LOG(ERR, VHOST_CONFIG,
> -				"vhost read incorrect message\n");
>  
>  		return -1;
>  	}
>  
>  	ret = 0;
> -	if (msg.request.master != VHOST_USER_IOTLB_MSG)
> -		RTE_LOG(INFO, VHOST_CONFIG, "read message %s\n",
> -			vhost_message_str[msg.request.master]);
> -	else
> -		RTE_LOG(DEBUG, VHOST_CONFIG, "read message %s\n",
> -			vhost_message_str[msg.request.master]);
> +	request = msg.request.master;
> +	if (request > VHOST_USER_NONE && request < VHOST_USER_MAX &&
> +			vhost_message_str[request]) {
> +		if (request != VHOST_USER_IOTLB_MSG)
> +			RTE_LOG(INFO, VHOST_CONFIG, "read message %s\n",
> +				vhost_message_str[request]);
> +		else
> +			RTE_LOG(DEBUG, VHOST_CONFIG, "read message %s\n",
> +				vhost_message_str[request]);
> +	} else {
> +		RTE_LOG(DEBUG, VHOST_CONFIG, "External request %d\n", request);
> +	}
>  
>  	ret = vhost_user_check_and_alloc_queue_pair(dev, &msg);
>  	if (ret < 0) {
> @@ -1964,7 +1967,7 @@ vhost_user_msg_handler(int vid, int fd)
>  	 * inactive, so it is safe. Otherwise taking the access_lock
>  	 * would cause a dead lock.
>  	 */
> -	switch (msg.request.master) {
> +	switch (request) {
>  	case VHOST_USER_SET_FEATURES:
>  	case VHOST_USER_SET_PROTOCOL_FEATURES:
>  	case VHOST_USER_SET_OWNER:
> @@ -1989,19 +1992,24 @@ vhost_user_msg_handler(int vid, int fd)
>  
>  	}
>  
> +	handled = false;
>  	if (dev->extern_ops.pre_msg_handle) {
>  		ret = (*dev->extern_ops.pre_msg_handle)(dev->vid,
> -				(void *)&msg, &skip_master);
> -		if (ret == RTE_VHOST_MSG_RESULT_ERR)
> -			goto skip_to_reply;
> -		else if (ret == RTE_VHOST_MSG_RESULT_REPLY)
> +				(void *)&msg);
> +		switch (ret) {
> +		case RTE_VHOST_MSG_RESULT_REPLY:
>  			send_vhost_reply(fd, &msg);
> -
> -		if (skip_master)
> +			/* Fall-through */
> +		case RTE_VHOST_MSG_RESULT_ERR:
> +		case RTE_VHOST_MSG_RESULT_OK:
> +			handled = true;
>  			goto skip_to_post_handle;
> +		case RTE_VHOST_MSG_RESULT_NOT_HANDLED:
> +		default:
> +			break;
> +		}
>  	}
>  
> -	request = msg.request.master;
>  	if (request > VHOST_USER_NONE && request < VHOST_USER_MAX) {
>  		if (!vhost_message_handlers[request])
>  			goto skip_to_post_handle;
> @@ -2012,40 +2020,54 @@ vhost_user_msg_handler(int vid, int fd)
>  			RTE_LOG(ERR, VHOST_CONFIG,
>  				"Processing %s failed.\n",
>  				vhost_message_str[request]);
> +			handled = true;
>  			break;
>  		case RTE_VHOST_MSG_RESULT_OK:
>  			RTE_LOG(DEBUG, VHOST_CONFIG,
>  				"Processing %s succeeded.\n",
>  				vhost_message_str[request]);
> +			handled = true;
>  			break;
>  		case RTE_VHOST_MSG_RESULT_REPLY:
>  			RTE_LOG(DEBUG, VHOST_CONFIG,
>  				"Processing %s succeeded and needs reply.\n",
>  				vhost_message_str[request]);
>  			send_vhost_reply(fd, &msg);
> +			handled = true;
> +			break;
> +		default:
>  			break;
>  		}
> -	} else {
> -		RTE_LOG(ERR, VHOST_CONFIG,
> -			"Requested invalid message type %d.\n", request);
> -		ret = RTE_VHOST_MSG_RESULT_ERR;
>  	}
>  
>  skip_to_post_handle:
>  	if (ret != RTE_VHOST_MSG_RESULT_ERR &&
>  			dev->extern_ops.post_msg_handle) {
> -		ret = (*dev->extern_ops.post_msg_handle)(
> -				dev->vid, (void *)&msg);
> -		if (ret == RTE_VHOST_MSG_RESULT_ERR)
> -			goto skip_to_reply;
> -		else if (ret == RTE_VHOST_MSG_RESULT_REPLY)
> +		ret = (*dev->extern_ops.post_msg_handle)(dev->vid,
> +				(void *)&msg);
> +		switch (ret) {
> +		case RTE_VHOST_MSG_RESULT_REPLY:
>  			send_vhost_reply(fd, &msg);
> +			/* Fall-through */
> +		case RTE_VHOST_MSG_RESULT_ERR:
> +		case RTE_VHOST_MSG_RESULT_OK:
> +			handled = true;
> +		case RTE_VHOST_MSG_RESULT_NOT_HANDLED:
> +		default:
> +			break;
> +		}
>  	}
>  
> -skip_to_reply:
>  	if (unlock_required)
>  		vhost_user_unlock_all_queue_pairs(dev);
>  
> +	/* If message was not handled at this stage, treat it as an error */
> +	if (!handled) {
> +		RTE_LOG(ERR, VHOST_CONFIG,
> +			"vhost message (req: %d) was not handled.\n", request);
> +		ret = RTE_VHOST_MSG_RESULT_ERR;
> +	}
> +
>  	/*
>  	 * If the request required a reply that was already sent,
>  	 * this optional reply-ack won't be sent as the
>

Patch

diff --git a/lib/librte_vhost/rte_vhost.h b/lib/librte_vhost/rte_vhost.h
index c9c392975..8ab4ff299 100644
--- a/lib/librte_vhost/rte_vhost.h
+++ b/lib/librte_vhost/rte_vhost.h
@@ -121,6 +121,8 @@  enum rte_vhost_msg_result {
 	RTE_VHOST_MSG_RESULT_OK =  0,
 	/* Message handling successful and reply prepared */
 	RTE_VHOST_MSG_RESULT_REPLY =  1,
+	/* Message not handled */
+	RTE_VHOST_MSG_RESULT_NOT_HANDLED,
 };
 
 /**
@@ -131,37 +133,20 @@  enum rte_vhost_msg_result {
  *  vhost device id
  * @param msg
  *  Message pointer.
- * @param skip_master
- *  If the handler requires skipping the master message handling, this variable
- *  shall be written 1, otherwise 0.
  * @return
- *  VH_RESULT_OK on success, VH_RESULT_REPLY on success with reply,
- *  VH_RESULT_ERR on failure
+ *  RTE_VHOST_MSG_RESULT_OK on success,
+ *  RTE_VHOST_MSG_RESULT_REPLY on success with reply,
+ *  RTE_VHOST_MSG_RESULT_ERR on failure,
+ *  RTE_VHOST_MSG_RESULT_NOT_HANDLED if message was not handled.
  */
-typedef enum rte_vhost_msg_result (*rte_vhost_msg_pre_handle)(int vid,
-		void *msg, uint32_t *skip_master);
-
-/**
- * Function prototype for the vhost backend to handler specific vhost user
- * messages after the master message handling is done
- *
- * @param vid
- *  vhost device id
- * @param msg
- *  Message pointer.
- * @return
- *  VH_RESULT_OK on success, VH_RESULT_REPLY on success with reply,
- *  VH_RESULT_ERR on failure
- */
-typedef enum rte_vhost_msg_result (*rte_vhost_msg_post_handle)(int vid,
-		void *msg);
+typedef enum rte_vhost_msg_result (*rte_vhost_msg_handle)(int vid, void *msg);
 
 /**
  * Optional vhost user message handlers.
  */
 struct rte_vhost_user_extern_ops {
-	rte_vhost_msg_pre_handle pre_msg_handle;
-	rte_vhost_msg_post_handle post_msg_handle;
+	rte_vhost_msg_handle pre_msg_handle;
+	rte_vhost_msg_handle post_msg_handle;
 };
 
 /**
diff --git a/lib/librte_vhost/vhost_crypto.c b/lib/librte_vhost/vhost_crypto.c
index 0f437c4a1..9b4b850e8 100644
--- a/lib/librte_vhost/vhost_crypto.c
+++ b/lib/librte_vhost/vhost_crypto.c
@@ -453,14 +453,20 @@  vhost_crypto_msg_post_handler(int vid, void *msg)
 		return RTE_VHOST_MSG_RESULT_ERR;
 	}
 
-	if (vmsg->request.master == VHOST_USER_CRYPTO_CREATE_SESS) {
+	switch (vmsg->request.master) {
+	case VHOST_USER_CRYPTO_CREATE_SESS:
 		vhost_crypto_create_sess(vcrypto,
 				&vmsg->payload.crypto_session);
 		vmsg->fd_num = 0;
 		ret = RTE_VHOST_MSG_RESULT_REPLY;
-	} else if (vmsg->request.master == VHOST_USER_CRYPTO_CLOSE_SESS) {
+		break;
+	case VHOST_USER_CRYPTO_CLOSE_SESS:
 		if (vhost_crypto_close_sess(vcrypto, vmsg->payload.u64))
 			ret = RTE_VHOST_MSG_RESULT_ERR;
+		break;
+	default:
+		ret = RTE_VHOST_MSG_RESULT_NOT_HANDLED;
+		break;
 	}
 
 	return ret;
diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c
index 555d09ad9..39756fce7 100644
--- a/lib/librte_vhost/vhost_user.c
+++ b/lib/librte_vhost/vhost_user.c
@@ -1910,7 +1910,7 @@  vhost_user_msg_handler(int vid, int fd)
 	int did = -1;
 	int ret;
 	int unlock_required = 0;
-	uint32_t skip_master = 0;
+	bool handled;
 	int request;
 
 	dev = get_device(vid);
@@ -1928,27 +1928,30 @@  vhost_user_msg_handler(int vid, int fd)
 	}
 
 	ret = read_vhost_message(fd, &msg);
-	if (ret <= 0 || msg.request.master >= VHOST_USER_MAX) {
+	if (ret <= 0) {
 		if (ret < 0)
 			RTE_LOG(ERR, VHOST_CONFIG,
 				"vhost read message failed\n");
-		else if (ret == 0)
+		else
 			RTE_LOG(INFO, VHOST_CONFIG,
 				"vhost peer closed\n");
-		else
-			RTE_LOG(ERR, VHOST_CONFIG,
-				"vhost read incorrect message\n");
 
 		return -1;
 	}
 
 	ret = 0;
-	if (msg.request.master != VHOST_USER_IOTLB_MSG)
-		RTE_LOG(INFO, VHOST_CONFIG, "read message %s\n",
-			vhost_message_str[msg.request.master]);
-	else
-		RTE_LOG(DEBUG, VHOST_CONFIG, "read message %s\n",
-			vhost_message_str[msg.request.master]);
+	request = msg.request.master;
+	if (request > VHOST_USER_NONE && request < VHOST_USER_MAX &&
+			vhost_message_str[request]) {
+		if (request != VHOST_USER_IOTLB_MSG)
+			RTE_LOG(INFO, VHOST_CONFIG, "read message %s\n",
+				vhost_message_str[request]);
+		else
+			RTE_LOG(DEBUG, VHOST_CONFIG, "read message %s\n",
+				vhost_message_str[request]);
+	} else {
+		RTE_LOG(DEBUG, VHOST_CONFIG, "External request %d\n", request);
+	}
 
 	ret = vhost_user_check_and_alloc_queue_pair(dev, &msg);
 	if (ret < 0) {
@@ -1964,7 +1967,7 @@  vhost_user_msg_handler(int vid, int fd)
 	 * inactive, so it is safe. Otherwise taking the access_lock
 	 * would cause a dead lock.
 	 */
-	switch (msg.request.master) {
+	switch (request) {
 	case VHOST_USER_SET_FEATURES:
 	case VHOST_USER_SET_PROTOCOL_FEATURES:
 	case VHOST_USER_SET_OWNER:
@@ -1989,19 +1992,24 @@  vhost_user_msg_handler(int vid, int fd)
 
 	}
 
+	handled = false;
 	if (dev->extern_ops.pre_msg_handle) {
 		ret = (*dev->extern_ops.pre_msg_handle)(dev->vid,
-				(void *)&msg, &skip_master);
-		if (ret == RTE_VHOST_MSG_RESULT_ERR)
-			goto skip_to_reply;
-		else if (ret == RTE_VHOST_MSG_RESULT_REPLY)
+				(void *)&msg);
+		switch (ret) {
+		case RTE_VHOST_MSG_RESULT_REPLY:
 			send_vhost_reply(fd, &msg);
-
-		if (skip_master)
+			/* Fall-through */
+		case RTE_VHOST_MSG_RESULT_ERR:
+		case RTE_VHOST_MSG_RESULT_OK:
+			handled = true;
 			goto skip_to_post_handle;
+		case RTE_VHOST_MSG_RESULT_NOT_HANDLED:
+		default:
+			break;
+		}
 	}
 
-	request = msg.request.master;
 	if (request > VHOST_USER_NONE && request < VHOST_USER_MAX) {
 		if (!vhost_message_handlers[request])
 			goto skip_to_post_handle;
@@ -2012,40 +2020,54 @@  vhost_user_msg_handler(int vid, int fd)
 			RTE_LOG(ERR, VHOST_CONFIG,
 				"Processing %s failed.\n",
 				vhost_message_str[request]);
+			handled = true;
 			break;
 		case RTE_VHOST_MSG_RESULT_OK:
 			RTE_LOG(DEBUG, VHOST_CONFIG,
 				"Processing %s succeeded.\n",
 				vhost_message_str[request]);
+			handled = true;
 			break;
 		case RTE_VHOST_MSG_RESULT_REPLY:
 			RTE_LOG(DEBUG, VHOST_CONFIG,
 				"Processing %s succeeded and needs reply.\n",
 				vhost_message_str[request]);
 			send_vhost_reply(fd, &msg);
+			handled = true;
+			break;
+		default:
 			break;
 		}
-	} else {
-		RTE_LOG(ERR, VHOST_CONFIG,
-			"Requested invalid message type %d.\n", request);
-		ret = RTE_VHOST_MSG_RESULT_ERR;
 	}
 
 skip_to_post_handle:
 	if (ret != RTE_VHOST_MSG_RESULT_ERR &&
 			dev->extern_ops.post_msg_handle) {
-		ret = (*dev->extern_ops.post_msg_handle)(
-				dev->vid, (void *)&msg);
-		if (ret == RTE_VHOST_MSG_RESULT_ERR)
-			goto skip_to_reply;
-		else if (ret == RTE_VHOST_MSG_RESULT_REPLY)
+		ret = (*dev->extern_ops.post_msg_handle)(dev->vid,
+				(void *)&msg);
+		switch (ret) {
+		case RTE_VHOST_MSG_RESULT_REPLY:
 			send_vhost_reply(fd, &msg);
+			/* Fall-through */
+		case RTE_VHOST_MSG_RESULT_ERR:
+		case RTE_VHOST_MSG_RESULT_OK:
+			handled = true;
+		case RTE_VHOST_MSG_RESULT_NOT_HANDLED:
+		default:
+			break;
+		}
 	}
 
-skip_to_reply:
 	if (unlock_required)
 		vhost_user_unlock_all_queue_pairs(dev);
 
+	/* If message was not handled at this stage, treat it as an error */
+	if (!handled) {
+		RTE_LOG(ERR, VHOST_CONFIG,
+			"vhost message (req: %d) was not handled.\n", request);
+		ret = RTE_VHOST_MSG_RESULT_ERR;
+	}
+
 	/*
 	 * If the request required a reply that was already sent,
 	 * this optional reply-ack won't be sent as the