There are a lot of cases where vhost-user massage handling
could fail and end up in a fully not recoverable state. For
example, allocation failures of shadow used ring and batched
copy array are not recoverable and leads to the segmentation
faults like this on the receiving/transmission path:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7f913fecf0 (LWP 43625)]
in copy_desc_to_mbuf () at /lib/librte_vhost/virtio_net.c:760
760 batch_copy[vq->batch_copy_nb_elems].dst =
This could be easily reproduced in case of low memory or big
number of vhost-user ports.
Fix that by propagating error to the upper layer which will
end up with disconnection in case we can not report to
the message sender when the error happens.
Fixes:
f689586bc060 ("vhost: shadow used ring update")
Cc: stable@dpdk.org
Signed-off-by: Ilya Maximets <i.maximets@samsung.com>
Reviewed-by: Maxime Coquelin <maxime.coquelin@redhat.com>
vhost_user_set_vring_kick(struct virtio_net **pdev, struct VhostUserMsg *pmsg)
{
struct vhost_vring_file file;
vhost_user_set_vring_kick(struct virtio_net **pdev, struct VhostUserMsg *pmsg)
{
struct vhost_vring_file file;
/* Interpret ring addresses only when ring is started. */
dev = translate_ring_addresses(dev, file.index);
if (!dev)
/* Interpret ring addresses only when ring is started. */
dev = translate_ring_addresses(dev, file.index);
if (!dev)
if (vq->kickfd >= 0)
close(vq->kickfd);
vq->kickfd = file.fd;
if (vq->kickfd >= 0)
close(vq->kickfd);
vq->kickfd = file.fd;
msg->size = sizeof(msg->payload.u64);
}
msg->size = sizeof(msg->payload.u64);
}
vhost_user_set_protocol_features(struct virtio_net *dev,
uint64_t protocol_features)
{
vhost_user_set_protocol_features(struct virtio_net *dev,
uint64_t protocol_features)
{
- if (protocol_features & ~VHOST_USER_PROTOCOL_FEATURES)
- return;
+ if (protocol_features & ~VHOST_USER_PROTOCOL_FEATURES) {
+ RTE_LOG(ERR, VHOST_CONFIG,
+ "(%d) received invalid protocol features.\n",
+ dev->vid);
+ return -1;
+ }
dev->protocol_features = protocol_features;
dev->protocol_features = protocol_features;
break;
case VHOST_USER_SET_FEATURES:
ret = vhost_user_set_features(dev, msg.payload.u64);
break;
case VHOST_USER_SET_FEATURES:
ret = vhost_user_set_features(dev, msg.payload.u64);
break;
case VHOST_USER_GET_PROTOCOL_FEATURES:
break;
case VHOST_USER_GET_PROTOCOL_FEATURES:
send_vhost_reply(fd, &msg);
break;
case VHOST_USER_SET_PROTOCOL_FEATURES:
send_vhost_reply(fd, &msg);
break;
case VHOST_USER_SET_PROTOCOL_FEATURES:
- vhost_user_set_protocol_features(dev, msg.payload.u64);
+ ret = vhost_user_set_protocol_features(dev, msg.payload.u64);
break;
case VHOST_USER_SET_OWNER:
break;
case VHOST_USER_SET_OWNER:
- vhost_user_set_owner();
+ ret = vhost_user_set_owner();
break;
case VHOST_USER_RESET_OWNER:
break;
case VHOST_USER_RESET_OWNER:
- vhost_user_reset_owner(dev);
+ ret = vhost_user_reset_owner(dev);
break;
case VHOST_USER_SET_MEM_TABLE:
break;
case VHOST_USER_SET_MEM_TABLE:
break;
case VHOST_USER_SET_LOG_BASE:
break;
case VHOST_USER_SET_LOG_BASE:
- vhost_user_set_log_base(dev, &msg);
-
+ ret = vhost_user_set_log_base(dev, &msg);
+ if (ret)
+ goto skip_to_reply;
/* it needs a reply */
msg.size = sizeof(msg.payload.u64);
send_vhost_reply(fd, &msg);
/* it needs a reply */
msg.size = sizeof(msg.payload.u64);
send_vhost_reply(fd, &msg);
break;
case VHOST_USER_SET_VRING_NUM:
break;
case VHOST_USER_SET_VRING_NUM:
- vhost_user_set_vring_num(dev, &msg);
+ ret = vhost_user_set_vring_num(dev, &msg);
break;
case VHOST_USER_SET_VRING_ADDR:
break;
case VHOST_USER_SET_VRING_ADDR:
- vhost_user_set_vring_addr(&dev, &msg);
+ ret = vhost_user_set_vring_addr(&dev, &msg);
break;
case VHOST_USER_SET_VRING_BASE:
break;
case VHOST_USER_SET_VRING_BASE:
- vhost_user_set_vring_base(dev, &msg);
+ ret = vhost_user_set_vring_base(dev, &msg);
break;
case VHOST_USER_GET_VRING_BASE:
break;
case VHOST_USER_GET_VRING_BASE:
- vhost_user_get_vring_base(dev, &msg);
+ ret = vhost_user_get_vring_base(dev, &msg);
+ if (ret)
+ goto skip_to_reply;
msg.size = sizeof(msg.payload.state);
send_vhost_reply(fd, &msg);
break;
case VHOST_USER_SET_VRING_KICK:
msg.size = sizeof(msg.payload.state);
send_vhost_reply(fd, &msg);
break;
case VHOST_USER_SET_VRING_KICK:
- vhost_user_set_vring_kick(&dev, &msg);
+ ret = vhost_user_set_vring_kick(&dev, &msg);
break;
case VHOST_USER_SET_VRING_CALL:
vhost_user_set_vring_call(dev, &msg);
break;
case VHOST_USER_SET_VRING_CALL:
vhost_user_set_vring_call(dev, &msg);
break;
case VHOST_USER_SET_VRING_ENABLE:
break;
case VHOST_USER_SET_VRING_ENABLE:
- vhost_user_set_vring_enable(dev, &msg);
+ ret = vhost_user_set_vring_enable(dev, &msg);
break;
case VHOST_USER_SEND_RARP:
break;
case VHOST_USER_SEND_RARP:
- vhost_user_send_rarp(dev, &msg);
+ ret = vhost_user_send_rarp(dev, &msg);
break;
case VHOST_USER_NET_SET_MTU:
break;
case VHOST_USER_NET_SET_MTU:
- if (dev->extern_ops.post_msg_handle) {
+ if (!ret && dev->extern_ops.post_msg_handle) {
uint32_t need_reply;
ret = (*dev->extern_ops.post_msg_handle)(
uint32_t need_reply;
ret = (*dev->extern_ops.post_msg_handle)(
msg.payload.u64 = !!ret;
msg.size = sizeof(msg.payload.u64);
send_vhost_reply(fd, &msg);
msg.payload.u64 = !!ret;
msg.size = sizeof(msg.payload.u64);
send_vhost_reply(fd, &msg);
+ } else if (ret) {
+ RTE_LOG(ERR, VHOST_CONFIG,
+ "vhost message handling failed.\n");
+ return -1;
}
if (!(dev->flags & VIRTIO_DEV_RUNNING) && virtio_is_ready(dev)) {
}
if (!(dev->flags & VIRTIO_DEV_RUNNING) && virtio_is_ready(dev)) {