diff --git a/lib/librte_vhost/Makefile b/lib/librte_vhost/Makefile
index 5d6c6abaed51..07439a186d91 100644
--- a/lib/librte_vhost/Makefile
+++ b/lib/librte_vhost/Makefile
@@ -25,6 +25,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_VHOST) := fd_man.c iotlb.c socket.c vhost.c \
 					vhost_user.c virtio_net.c
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_VHOST)-include += rte_vhost.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_VHOST)-include += rte_vhost.h rte_vhost_user.h
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_vhost/rte_vhost.h b/lib/librte_vhost/rte_vhost.h
index d33206997453..7b76952638dc 100644
--- a/lib/librte_vhost/rte_vhost.h
+++ b/lib/librte_vhost/rte_vhost.h
@@ -16,12 +16,13 @@
 #include <rte_memory.h>
 #include <rte_mempool.h>
 
+#include <rte_vhost_user.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /* These are not C++-aware. */
-#include <linux/vhost.h>
 #include <linux/virtio_ring.h>
 
 #define RTE_VHOST_USER_CLIENT		(1ULL << 0)
@@ -65,6 +66,51 @@ struct rte_vhost_vring {
 };
 
 /**
+ * Vhost library started processing given vhost user message.
+ *
+ * This state should be used eg. to stop rings processing in case of
+ * SET_MEM_TABLE message.
+ *
+ * Backend is allowed to return any result of RTE_VHOST_USER_MESSAGE_RESULT_*.
+ */
+#define RTE_VHOST_USER_MSG_START 0
+
+/**
+ * Vhost library is finishing processing given vhost user message.
+ * If backend have handled the message produced response is passed as message
+ * parameter. If response is needed it will be send after returning.
+ *
+ * This state might be used to resume ring processing in case of SET_MEM_TABLE
+ * message.
+ *
+ * Returning RTE_VHOST_USER_MSG_RESULT_FAILED will trigger failure action in
+ * vhost library.
+ */
+#define RTE_VHOST_USER_MSG_END 1
+
+/**
+ * Backend understood the message but processing it failed for some reason.
+ * vhost library will take the failure action - chance closing existing
+ * connection.
+ */
+#define RTE_VHOST_USER_MSG_RESULT_FAILED -1
+
+/**
+ * Backend understood the message and handled it entirly. Backend is responsible
+ * for filling message object with right response data.
+ */
+#define RTE_VHOST_USER_MSG_RESULT_HANDLED 0
+
+/**
+ * Backend ignored the message or understood and took some action. In either
+ * case the message need to be further processed by vhost library.
+ *
+ * Backend is not allowed to change passed message.
+ */
+#define RTE_VHOST_USER_MSG_RESULT_OK 1
+
+
+/**
  * Device and vring operations.
  */
 struct vhost_device_ops {
@@ -84,7 +130,17 @@ struct vhost_device_ops {
 	int (*new_connection)(int vid);
 	void (*destroy_connection)(int vid);
 
-	void *reserved[2]; /**< Reserved for future extension */
+	/**
+	 * Backend callback for user message.
+	 *
+	 * @param vid id of vhost device
+	 * @param msg message object.
+	 * @param phase RTE_VHOST_USER_MSG_START or RTE_VHOST_USER_MSG_END
+	 * @return one of RTE_VHOST_USER_MESSAGE_RESULT_*
+	 */
+	int (*user_message_handler)(int vid, struct VhostUserMsg *msg, int phase);
+
+	void *reserved[1]; /**< Reserved for future extension */
 };
 
 /**
diff --git a/lib/librte_vhost/rte_vhost_user.h b/lib/librte_vhost/rte_vhost_user.h
new file mode 100644
index 000000000000..f7678d33acc3
--- /dev/null
+++ b/lib/librte_vhost/rte_vhost_user.h
@@ -0,0 +1,120 @@
+#ifndef _VHOST_RTE_VHOST_USER_H_
+#define _VHOST_RTE_VHOST_USER_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* These are not C++-aware. */
+#include <linux/vhost.h>
+
+/* refer to hw/virtio/vhost-user.c */
+
+struct vhost_iotlb_msg {
+	__u64 iova;
+	__u64 size;
+	__u64 uaddr;
+#define VHOST_ACCESS_RO      0x1
+#define VHOST_ACCESS_WO      0x2
+#define VHOST_ACCESS_RW      0x3
+	__u8 perm;
+#define VHOST_IOTLB_MISS           1
+#define VHOST_IOTLB_UPDATE         2
+#define VHOST_IOTLB_INVALIDATE     3
+#define VHOST_IOTLB_ACCESS_FAIL    4
+	__u8 type;
+};
+
+#define VHOST_MEMORY_MAX_NREGIONS 8
+
+#define VHOST_USER_PROTOCOL_F_MQ	0
+#define VHOST_USER_PROTOCOL_F_LOG_SHMFD	1
+#define VHOST_USER_PROTOCOL_F_RARP	2
+#define VHOST_USER_PROTOCOL_F_REPLY_ACK	3
+#define VHOST_USER_PROTOCOL_F_NET_MTU 4
+#define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5
+
+typedef enum VhostUserRequest {
+	VHOST_USER_NONE = 0,
+	VHOST_USER_GET_FEATURES = 1,
+	VHOST_USER_SET_FEATURES = 2,
+	VHOST_USER_SET_OWNER = 3,
+	VHOST_USER_RESET_OWNER = 4,
+	VHOST_USER_SET_MEM_TABLE = 5,
+	VHOST_USER_SET_LOG_BASE = 6,
+	VHOST_USER_SET_LOG_FD = 7,
+	VHOST_USER_SET_VRING_NUM = 8,
+	VHOST_USER_SET_VRING_ADDR = 9,
+	VHOST_USER_SET_VRING_BASE = 10,
+	VHOST_USER_GET_VRING_BASE = 11,
+	VHOST_USER_SET_VRING_KICK = 12,
+	VHOST_USER_SET_VRING_CALL = 13,
+	VHOST_USER_SET_VRING_ERR = 14,
+	VHOST_USER_GET_PROTOCOL_FEATURES = 15,
+	VHOST_USER_SET_PROTOCOL_FEATURES = 16,
+	VHOST_USER_GET_QUEUE_NUM = 17,
+	VHOST_USER_SET_VRING_ENABLE = 18,
+	VHOST_USER_SEND_RARP = 19,
+	VHOST_USER_NET_SET_MTU = 20,
+	VHOST_USER_SET_SLAVE_REQ_FD = 21,
+	VHOST_USER_IOTLB_MSG = 22,
+	VHOST_USER_MAX
+} VhostUserRequest;
+
+typedef enum VhostUserSlaveRequest {
+	VHOST_USER_SLAVE_NONE = 0,
+	VHOST_USER_SLAVE_IOTLB_MSG = 1,
+	VHOST_USER_SLAVE_MAX
+} VhostUserSlaveRequest;
+
+typedef struct VhostUserMemoryRegion {
+	uint64_t guest_phys_addr;
+	uint64_t memory_size;
+	uint64_t userspace_addr;
+	uint64_t mmap_offset;
+} VhostUserMemoryRegion;
+
+typedef struct VhostUserMemory {
+	uint32_t nregions;
+	uint32_t padding;
+	VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
+} VhostUserMemory;
+
+typedef struct VhostUserLog {
+	uint64_t mmap_size;
+	uint64_t mmap_offset;
+} VhostUserLog;
+
+typedef struct VhostUserMsg {
+	union {
+		VhostUserRequest master;
+		VhostUserSlaveRequest slave;
+	} request;
+
+#define VHOST_USER_VERSION_MASK     0x3
+#define VHOST_USER_REPLY_MASK       (0x1 << 2)
+#define VHOST_USER_NEED_REPLY		(0x1 << 3)
+	uint32_t flags;
+	uint32_t size; /* the following payload size */
+	union {
+#define VHOST_USER_VRING_IDX_MASK   0xff
+#define VHOST_USER_VRING_NOFD_MASK  (0x1<<8)
+		uint64_t u64;
+		struct vhost_vring_state state;
+		struct vhost_vring_addr addr;
+		VhostUserMemory memory;
+		VhostUserLog    log;
+		struct vhost_iotlb_msg iotlb;
+	} payload;
+	int fds[VHOST_MEMORY_MAX_NREGIONS];
+} __attribute((packed)) VhostUserMsg;
+
+#define VHOST_USER_HDR_SIZE offsetof(VhostUserMsg, payload.u64)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VHOST_RTE_VHOST_USER_H_ */
diff --git a/lib/librte_vhost/vhost.h b/lib/librte_vhost/vhost.h
index d947bc9e3b3f..42a1474095a3 100644
--- a/lib/librte_vhost/vhost.h
+++ b/lib/librte_vhost/vhost.h
@@ -141,20 +141,6 @@ struct vhost_virtqueue {
 
 #define VIRTIO_F_IOMMU_PLATFORM 33
 
-struct vhost_iotlb_msg {
-	__u64 iova;
-	__u64 size;
-	__u64 uaddr;
-#define VHOST_ACCESS_RO      0x1
-#define VHOST_ACCESS_WO      0x2
-#define VHOST_ACCESS_RW      0x3
-	__u8 perm;
-#define VHOST_IOTLB_MISS           1
-#define VHOST_IOTLB_UPDATE         2
-#define VHOST_IOTLB_INVALIDATE     3
-#define VHOST_IOTLB_ACCESS_FAIL    4
-	__u8 type;
-};
 
 #define VHOST_IOTLB_MSG 0x1
 
diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c
index 90ed2112e0af..15532e182b58 100644
--- a/lib/librte_vhost/vhost_user.c
+++ b/lib/librte_vhost/vhost_user.c
@@ -1301,6 +1301,7 @@ vhost_user_msg_handler(int vid, int fd)
 	struct virtio_net *dev;
 	struct VhostUserMsg msg;
 	int ret;
+	int user_handler_result;
 	int unlock_required = 0;
 
 	dev = get_device(vid);
@@ -1347,6 +1348,26 @@ vhost_user_msg_handler(int vid, int fd)
 		return -1;
 	}
 
+
+	if (dev->notify_ops->user_message_handler) {
+		user_handler_result = dev->notify_ops->user_message_handler(
+				dev->vid, &msg, RTE_VHOST_USER_MSG_START);
+
+		switch (user_handler_result) {
+		case RTE_VHOST_USER_MSG_RESULT_FAILED:
+			RTE_LOG(ERR, VHOST_CONFIG,
+				"User message handler failed\n");
+			return -1;
+		case RTE_VHOST_USER_MSG_RESULT_HANDLED:
+			RTE_LOG(DEBUG, VHOST_CONFIG,
+				"User message handled by backend\n");
+			goto msg_handled;
+		case RTE_VHOST_USER_MSG_RESULT_OK:
+			break;
+		}
+	}
+
+
 	/*
 	 * Note: we don't lock all queues on VHOST_USER_GET_VRING_BASE
 	 * and VHOST_USER_RESET_OWNER, since it is sent when virtio stops
@@ -1485,6 +1506,15 @@ vhost_user_msg_handler(int vid, int fd)
 	if (unlock_required)
 		vhost_user_unlock_all_queue_pairs(dev);
 
+msg_handled:
+	if (dev->notify_ops->user_message_handler) {
+		user_handler_result = dev->notify_ops->user_message_handler(
+				dev->vid, &msg, RTE_VHOST_USER_MSG_END);
+
+		if (user_handler_result == RTE_VHOST_USER_MSG_RESULT_FAILED)
+			return -1;
+	}
+
 	if (msg.flags & VHOST_USER_NEED_REPLY) {
 		msg.payload.u64 = !!ret;
 		msg.size = sizeof(msg.payload.u64);
diff --git a/lib/librte_vhost/vhost_user.h b/lib/librte_vhost/vhost_user.h
index d4bd604b9d6b..cf3f0da0ec41 100644
--- a/lib/librte_vhost/vhost_user.h
+++ b/lib/librte_vhost/vhost_user.h
@@ -10,17 +10,6 @@
 
 #include "rte_vhost.h"
 
-/* refer to hw/virtio/vhost-user.c */
-
-#define VHOST_MEMORY_MAX_NREGIONS 8
-
-#define VHOST_USER_PROTOCOL_F_MQ	0
-#define VHOST_USER_PROTOCOL_F_LOG_SHMFD	1
-#define VHOST_USER_PROTOCOL_F_RARP	2
-#define VHOST_USER_PROTOCOL_F_REPLY_ACK	3
-#define VHOST_USER_PROTOCOL_F_NET_MTU 4
-#define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5
-
 #define VHOST_USER_PROTOCOL_FEATURES	((1ULL << VHOST_USER_PROTOCOL_F_MQ) | \
 					 (1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD) |\
 					 (1ULL << VHOST_USER_PROTOCOL_F_RARP) | \
@@ -28,83 +17,6 @@
 					 (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU) | \
 					 (1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ))
 
-typedef enum VhostUserRequest {
-	VHOST_USER_NONE = 0,
-	VHOST_USER_GET_FEATURES = 1,
-	VHOST_USER_SET_FEATURES = 2,
-	VHOST_USER_SET_OWNER = 3,
-	VHOST_USER_RESET_OWNER = 4,
-	VHOST_USER_SET_MEM_TABLE = 5,
-	VHOST_USER_SET_LOG_BASE = 6,
-	VHOST_USER_SET_LOG_FD = 7,
-	VHOST_USER_SET_VRING_NUM = 8,
-	VHOST_USER_SET_VRING_ADDR = 9,
-	VHOST_USER_SET_VRING_BASE = 10,
-	VHOST_USER_GET_VRING_BASE = 11,
-	VHOST_USER_SET_VRING_KICK = 12,
-	VHOST_USER_SET_VRING_CALL = 13,
-	VHOST_USER_SET_VRING_ERR = 14,
-	VHOST_USER_GET_PROTOCOL_FEATURES = 15,
-	VHOST_USER_SET_PROTOCOL_FEATURES = 16,
-	VHOST_USER_GET_QUEUE_NUM = 17,
-	VHOST_USER_SET_VRING_ENABLE = 18,
-	VHOST_USER_SEND_RARP = 19,
-	VHOST_USER_NET_SET_MTU = 20,
-	VHOST_USER_SET_SLAVE_REQ_FD = 21,
-	VHOST_USER_IOTLB_MSG = 22,
-	VHOST_USER_MAX
-} VhostUserRequest;
-
-typedef enum VhostUserSlaveRequest {
-	VHOST_USER_SLAVE_NONE = 0,
-	VHOST_USER_SLAVE_IOTLB_MSG = 1,
-	VHOST_USER_SLAVE_MAX
-} VhostUserSlaveRequest;
-
-typedef struct VhostUserMemoryRegion {
-	uint64_t guest_phys_addr;
-	uint64_t memory_size;
-	uint64_t userspace_addr;
-	uint64_t mmap_offset;
-} VhostUserMemoryRegion;
-
-typedef struct VhostUserMemory {
-	uint32_t nregions;
-	uint32_t padding;
-	VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
-} VhostUserMemory;
-
-typedef struct VhostUserLog {
-	uint64_t mmap_size;
-	uint64_t mmap_offset;
-} VhostUserLog;
-
-typedef struct VhostUserMsg {
-	union {
-		VhostUserRequest master;
-		VhostUserSlaveRequest slave;
-	} request;
-
-#define VHOST_USER_VERSION_MASK     0x3
-#define VHOST_USER_REPLY_MASK       (0x1 << 2)
-#define VHOST_USER_NEED_REPLY		(0x1 << 3)
-	uint32_t flags;
-	uint32_t size; /* the following payload size */
-	union {
-#define VHOST_USER_VRING_IDX_MASK   0xff
-#define VHOST_USER_VRING_NOFD_MASK  (0x1<<8)
-		uint64_t u64;
-		struct vhost_vring_state state;
-		struct vhost_vring_addr addr;
-		VhostUserMemory memory;
-		VhostUserLog    log;
-		struct vhost_iotlb_msg iotlb;
-	} payload;
-	int fds[VHOST_MEMORY_MAX_NREGIONS];
-} __attribute((packed)) VhostUserMsg;
-
-#define VHOST_USER_HDR_SIZE offsetof(VhostUserMsg, payload.u64)
-
 /* The version of the protocol we support */
 #define VHOST_USER_VERSION    0x1
 
