diff --git a/drivers/net/sssnic/base/meson.build b/drivers/net/sssnic/base/meson.build
index 7758faa482..dd4dd08fc1 100644
--- a/drivers/net/sssnic/base/meson.build
+++ b/drivers/net/sssnic/base/meson.build
@@ -3,7 +3,8 @@
 
 sources = [
         'sssnic_hw.c',
-        'sssnic_eventq.c'
+        'sssnic_eventq.c',
+        'sssnic_msg.c',
 ]
 
 c_args = cflags
diff --git a/drivers/net/sssnic/base/sssnic_eventq.c b/drivers/net/sssnic/base/sssnic_eventq.c
index a74b74f756..e90d24bb6b 100644
--- a/drivers/net/sssnic/base/sssnic_eventq.c
+++ b/drivers/net/sssnic/base/sssnic_eventq.c
@@ -14,6 +14,7 @@
 #include "../sssnic_log.h"
 #include "sssnic_hw.h"
 #include "sssnic_reg.h"
+#include "sssnic_msg.h"
 #include "sssnic_eventq.h"
 
 #define SSSNIC_EVENTQ_DEF_DEPTH 64
@@ -184,6 +185,32 @@ sssnic_eventq_ci_update(struct sssnic_eventq *eq, int informed)
 	sssnic_eventq_reg_write(eq, SSSNIC_EVENTQ_CI_CTRL_REG, reg.u32);
 }
 
+static int
+sssnic_event_default_handler_func(struct sssnic_eventq *eq,
+	struct sssnic_event *ev, __rte_unused void *data)
+{
+	struct sssnic_hw *hw;
+	int ret;
+
+	hw = eq->hw;
+	ret = sssnic_msg_rx_handle(hw, (struct sssnic_msg_hdr *)(ev->data));
+	if (ret != SSSNIC_MSG_DONE)
+		return -1;
+
+	return SSSNIC_EVENT_DONE;
+}
+
+static void
+sssnic_eventq_handlers_init(struct sssnic_eventq *eq)
+{
+	int i;
+
+	for (i = SSSNIC_EVENT_CODE_MIN; i <= SSSNIC_EVENT_CODE_MAX; i++) {
+		eq->handlers[i].func = sssnic_event_default_handler_func;
+		eq->handlers[i].data = NULL;
+	}
+}
+
 static int
 sssnic_eventq_init(struct sssnic_hw *hw, struct sssnic_eventq *eq, uint16_t qid)
 {
@@ -230,6 +257,8 @@ sssnic_eventq_init(struct sssnic_hw *hw, struct sssnic_eventq *eq, uint16_t qid)
 		PMD_DRV_LOG(ERR, "Failed to setup eventq pages!");
 		return ret;
 	}
+
+	sssnic_eventq_handlers_init(eq);
 	sssnic_eventq_ctrl_setup(eq);
 	sssnic_eventq_ci_update(eq, 1);
 	if (qid == 0)
diff --git a/drivers/net/sssnic/base/sssnic_hw.c b/drivers/net/sssnic/base/sssnic_hw.c
index 44e04486a5..387c823c7e 100644
--- a/drivers/net/sssnic/base/sssnic_hw.c
+++ b/drivers/net/sssnic/base/sssnic_hw.c
@@ -10,6 +10,7 @@
 #include "sssnic_hw.h"
 #include "sssnic_reg.h"
 #include "sssnic_eventq.h"
+#include "sssnic_msg.h"
 
 static int
 wait_for_sssnic_hw_ready(struct sssnic_hw *hw)
@@ -197,18 +198,30 @@ sssnic_hw_init(struct sssnic_hw *hw)
 		return ret;
 	}
 
+	ret = sssnic_msg_inbox_init(hw);
+	if (ret) {
+		PMD_DRV_LOG(ERR, "Failed to initialize message inbox.");
+		return ret;
+	}
+
 	ret = sssnic_eventq_all_init(hw);
 	if (ret != 0) {
 		PMD_DRV_LOG(ERR, "Failed to initialize event queues");
-		return ret;
+		goto eventq_init_fail;
 	}
 
 	return -EINVAL;
+
+eventq_init_fail:
+	sssnic_msg_inbox_shutdown(hw);
+	return ret;
 }
 
 void
 sssnic_hw_shutdown(struct sssnic_hw *hw)
 {
 	PMD_INIT_FUNC_TRACE();
+
 	sssnic_eventq_all_shutdown(hw);
+	sssnic_msg_inbox_shutdown(hw);
 }
diff --git a/drivers/net/sssnic/base/sssnic_hw.h b/drivers/net/sssnic/base/sssnic_hw.h
index 6caf3a6d66..38fb9ac1ac 100644
--- a/drivers/net/sssnic/base/sssnic_hw.h
+++ b/drivers/net/sssnic/base/sssnic_hw.h
@@ -52,11 +52,13 @@ struct sssnic_hw {
 	uint8_t *db_mem_len;
 	struct sssnic_hw_attr attr;
 	struct sssnic_eventq *eventqs;
+	struct sssnic_msg_inbox *msg_inbox;
 	uint8_t num_eventqs;
 	uint16_t eth_port_id;
 };
 
 #define SSSNIC_ETH_PORT_ID(hw) ((hw)->eth_port_id)
+#define SSSNIC_MPU_FUNC_IDX 0x1fff
 
 int sssnic_hw_init(struct sssnic_hw *hw);
 void sssnic_hw_shutdown(struct sssnic_hw *hw);
diff --git a/drivers/net/sssnic/base/sssnic_msg.c b/drivers/net/sssnic/base/sssnic_msg.c
new file mode 100644
index 0000000000..4b98fee75b
--- /dev/null
+++ b/drivers/net/sssnic/base/sssnic_msg.c
@@ -0,0 +1,254 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2022 Shenzhen 3SNIC Information Technology Co., Ltd.
+ */
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_mempool.h>
+#include <rte_memcpy.h>
+
+#include "../sssnic_log.h"
+#include "sssnic_hw.h"
+#include "sssnic_msg.h"
+
+/* Receive message segment based on message header
+ * @param msghdr
+ *	message header
+ * @param msg
+ *	message where segment store
+ * @return
+ *	SSSNIC_MSG_REJECT - Message segment was not received because of bad
+ *                          parameter of message header.
+ *	SSSNIC_MSG_ACCEPT - Message segment was received.
+ *	SSSNIC_MSG_DONE   - The last message segment was received.
+ */
+static int
+sssnic_msg_rx_seg(struct sssnic_msg_hdr *msghdr, struct sssnic_msg *msg)
+{
+	if (msghdr->seg_id > SSSNIC_MSG_MAX_SEG_ID ||
+		msghdr->seg_len > SSSNIC_MSG_MAX_SEG_SIZE) {
+		PMD_DRV_LOG(ERR,
+			"Bad segment id or segment size of message header");
+		return SSSNIC_MSG_REJECT;
+	}
+
+	if (msghdr->seg_id == 0) {
+		msg->command = msghdr->command;
+		msg->type = msghdr->type;
+		msg->module = msghdr->module;
+		msg->id = msghdr->id;
+	} else {
+		if (msghdr->seg_id != (msg->seg + 1) || msghdr->id != msg->id ||
+			msghdr->module != msg->module ||
+			msghdr->command != msg->command) {
+			PMD_DRV_LOG(ERR, "Bad parameters of message header");
+			return SSSNIC_MSG_REJECT;
+		}
+	}
+	rte_memcpy(msg->data_buf + (SSSNIC_MSG_MAX_SEG_SIZE * msghdr->seg_id),
+		SSSNIC_MSG_DATA(msghdr), msghdr->seg_len);
+
+	if (!msghdr->last_seg) {
+		msg->seg = msghdr->seg_id;
+		return SSSNIC_MSG_ACCEPT;
+	}
+
+	msg->ack = !msghdr->no_response;
+	msg->status = msghdr->status;
+	msg->data_len = msghdr->length;
+	msg->func = msghdr->function;
+	msg->seg = SSSNIC_MSG_MAX_SEG_ID;
+
+	return SSSNIC_MSG_DONE;
+}
+
+static int
+sssnic_msg_buf_alloc(struct sssnic_msg *msg, size_t size)
+{
+	msg->data_buf = rte_zmalloc("sssnic_msg_data", size, 1);
+	if (msg->data_buf == NULL) {
+		PMD_DRV_LOG(ERR, "Could not all message data buffer!");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void
+sssnic_msg_buf_free(struct sssnic_msg *msg)
+{
+	rte_free(msg->data_buf);
+}
+
+int
+sssnic_msg_rx_handle(struct sssnic_hw *hw, struct sssnic_msg_hdr *msghdr)
+{
+	struct sssnic_msg *msg;
+	struct sssnic_msg_handler *msg_handler;
+	int msg_src;
+	int msg_chan;
+	int msg_type;
+	int ret;
+
+	msg_src = SSSNIC_MSG_SRC(msghdr->function);
+	msg_chan = msghdr->channel;
+	msg_type = msghdr->type;
+	msg = SSSNIC_MSG_LOCATE(hw, msg_chan, msg_type, msg_src);
+
+	ret = sssnic_msg_rx_seg(msghdr, msg);
+	if (ret != SSSNIC_MSG_DONE)
+		return ret;
+
+	msg_handler = SSSNIC_MSG_HANDLER(hw, msg_chan, msg_type);
+	if (msg_handler->func == NULL) {
+		PMD_DRV_LOG(NOTICE,
+			"No message handler, message channel:%d, type:%d.",
+			msg_chan, msg_type);
+		return SSSNIC_MSG_REJECT;
+	}
+	ret = msg_handler->func(msg, msg_chan, msg_handler->priv);
+
+	return ret;
+}
+
+int
+sssnic_msg_rx_handler_register(struct sssnic_hw *hw,
+	enum sssnic_msg_chann_id chann_id, enum sssnic_msg_type msg_type,
+	sssnic_msg_handler_func_t *func, void *priv)
+{
+	struct sssnic_msg_handler *msg_handler;
+
+	if (chann_id >= SSSNIC_MSG_CHAN_COUNT ||
+		msg_type >= SSSNIC_MSG_TYPE_CONUT || func == NULL) {
+		PMD_DRV_LOG(ERR,
+			"Bad parameters for register rx message handler.");
+		return -EINVAL;
+	}
+
+	msg_handler = SSSNIC_MSG_HANDLER(hw, chann_id, msg_type);
+	if (msg_handler->func != NULL)
+		PMD_DRV_LOG(WARNING,
+			"RX message handler has existed, chann_id:%u, msg_type:%u",
+			chann_id, msg_type);
+
+	msg_handler->func = func;
+	msg_handler->priv = priv;
+
+	return 0;
+}
+
+static int
+sssnic_msg_channel_init(struct sssnic_hw *hw, struct sssnic_msg_channel *chan)
+{
+	struct sssnic_msg *msg;
+	int i;
+	int ret;
+
+	PMD_INIT_FUNC_TRACE();
+
+	for (i = 0; i < SSSNIC_MSG_TYPE_CONUT; i++) {
+		msg = &chan->msg[i][SSSNIC_MSG_SRC_MPU];
+		ret = sssnic_msg_buf_alloc(msg, SSSNIC_MSG_BUF_SIZE);
+		if (ret) {
+			PMD_DRV_LOG(ERR,
+				"Could not alloc MPU message buf for message inbox channel %d of sssnic%u.",
+				SSSNIC_ETH_PORT_ID(hw), chan->id);
+			goto msg_buf_alloc_fail;
+		}
+		msg = &chan->msg[i][SSSNIC_MSG_SRC_PF];
+		ret = sssnic_msg_buf_alloc(msg, SSSNIC_MSG_BUF_SIZE);
+		if (ret) {
+			PMD_DRV_LOG(ERR,
+				"Could not alloc PF message buf for message inbox channel %d of sssnic%u.",
+				SSSNIC_ETH_PORT_ID(hw), chan->id);
+			msg = &chan->msg[i][SSSNIC_MSG_SRC_MPU];
+			sssnic_msg_buf_free(msg);
+			goto msg_buf_alloc_fail;
+		}
+	}
+
+	return 0;
+
+msg_buf_alloc_fail:
+	while (i--) {
+		msg = &chan->msg[i][SSSNIC_MSG_SRC_MPU];
+		sssnic_msg_buf_free(msg);
+		msg = &chan->msg[i][SSSNIC_MSG_SRC_PF];
+		sssnic_msg_buf_free(msg);
+	}
+	return ret;
+}
+
+static void
+sssnic_msg_channel_shutdown(__rte_unused struct sssnic_hw *hw,
+	struct sssnic_msg_channel *chan)
+{
+	struct sssnic_msg *msg;
+	int i;
+
+	PMD_INIT_FUNC_TRACE();
+
+	for (i = 0; i < SSSNIC_MSG_TYPE_CONUT; i++) {
+		msg = &chan->msg[i][SSSNIC_MSG_SRC_MPU];
+		sssnic_msg_buf_free(msg);
+		msg = &chan->msg[i][SSSNIC_MSG_SRC_PF];
+		sssnic_msg_buf_free(msg);
+	}
+}
+
+int
+sssnic_msg_inbox_init(struct sssnic_hw *hw)
+{
+	struct sssnic_msg_inbox *inbox;
+	struct sssnic_msg_channel *chan;
+	int i;
+	int ret;
+
+	PMD_INIT_FUNC_TRACE();
+
+	inbox = rte_zmalloc(NULL, sizeof(struct sssnic_msg_inbox), 1);
+	if (inbox == NULL) {
+		PMD_DRV_LOG(ERR, "Could not alloc memory for message inbox");
+		return -ENOMEM;
+	}
+
+	inbox->hw = hw;
+	hw->msg_inbox = inbox;
+
+	for (i = 0; i < SSSNIC_MSG_CHAN_COUNT; i++) {
+		chan = &inbox->channel[i];
+		ret = sssnic_msg_channel_init(hw, chan);
+		if (ret) {
+			PMD_DRV_LOG(ERR,
+				"Failed to initialize channel%u of message inbox",
+				i);
+			goto init_msg_channel_fail;
+		}
+		chan->id = i;
+	}
+
+	return 0;
+
+init_msg_channel_fail:
+	while (i--) {
+		chan = &inbox->channel[i];
+		sssnic_msg_channel_shutdown(hw, chan);
+	}
+	rte_free(inbox);
+	return ret;
+}
+
+void
+sssnic_msg_inbox_shutdown(struct sssnic_hw *hw)
+{
+	struct sssnic_msg_channel *chan;
+	int i;
+
+	PMD_INIT_FUNC_TRACE();
+
+	for (i = 0; i < SSSNIC_MSG_CHAN_COUNT; i++) {
+		chan = &hw->msg_inbox->channel[i];
+		sssnic_msg_channel_shutdown(hw, chan);
+	}
+	rte_free(hw->msg_inbox);
+}
diff --git a/drivers/net/sssnic/base/sssnic_msg.h b/drivers/net/sssnic/base/sssnic_msg.h
new file mode 100644
index 0000000000..6580f4bb37
--- /dev/null
+++ b/drivers/net/sssnic/base/sssnic_msg.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2022 Shenzhen 3SNIC Information Technology Co., Ltd.
+ */
+
+#ifndef _SSSNIC_MSG_H_
+#define _SSSNIC_MSG_H_
+
+#include <string.h>
+
+enum sssnic_msg_chann_id {
+	SSSNIC_MSG_CHAN_MPU = 0, /* Message comes from MPU directly */
+	SSSNIC_MSG_CHAN_MBOX = 1, /* Message comes from MBOX */
+	SSSNIC_MSG_CHAN_COUNT = 2,
+};
+
+enum sssnic_msg_src {
+	SSSNIC_MSG_SRC_MPU, /* mbox message from MPU */
+	SSSNIC_MSG_SRC_PF, /* mbox message from PF */
+	SSSNIC_MSG_SRC_COUNT,
+};
+
+#define SSSNIC_MSG_SRC(func_id)                                                \
+	(((func_id) == SSSNIC_MPU_FUNC_IDX) ? SSSNIC_MSG_SRC_MPU :             \
+						    SSSNIC_MSG_SRC_PF)
+
+enum sssnic_msg_type {
+	SSSNIC_MSG_TYPE_REQ, /* Request message*/
+	SSSNIC_MSG_TYPE_RESP, /* Response message */
+	SSSNIC_MSG_TYPE_CONUT,
+};
+
+#define SSSNIC_MSG_TRANS_MODE_DMA 1
+#define SSSNIC_MSG_TRANS_MODE_INLINE 0
+
+/* hardware format of sssnic message header */
+struct sssnic_msg_hdr {
+	union {
+		uint64_t u64;
+		struct {
+			uint32_t dw0;
+			uint32_t dw1;
+		};
+		struct {
+			/* Id of the function the message comes from or send to */
+			uint64_t function : 13;
+			/* indicate the result of command */
+			uint64_t status : 2;
+			/* Mbox channel that message receive from or send to */
+			uint64_t channel : 1;
+			/* ID of the EventQ that response message is informed by */
+			uint64_t eventq : 2;
+			/* Message ID */
+			uint64_t id : 4;
+			/* Command ID of the message */
+			uint64_t command : 10;
+			/* total length of message data */
+			uint64_t length : 11;
+			/* Module of message comes from or send to */
+			uint64_t module : 5;
+			/* Length of this data segment */
+			uint64_t seg_len : 6;
+			/* needless response indication */
+			uint64_t no_response : 1;
+			/* Message data transmission mode, 0: inline 1:dma */
+			uint64_t trans_mode : 1;
+			/* Segment sequence of message data */
+			uint64_t seg_id : 6;
+			/* Last data segment indication, 1: Last segment */
+			uint64_t last_seg : 1;
+			/* Message type, see sssnic_mbox_msg_type */
+			uint64_t type : 1;
+		};
+	};
+};
+#define SSSNIC_MSG_HDR_SIZE sizeof(struct sssnic_msg_hdr)
+#define SSSNIC_MSG_DATA(hdr) (((uint8_t *)hdr) + SSSNIC_MSG_HDR_SIZE)
+
+#define SSSNIC_MSG_BUF_SIZE 2048UL
+#define SSSNIC_MSG_MAX_SEG_SIZE 48
+#define SSSNIC_MSG_MIN_SGE_ID 0
+#define SSSNIC_MSG_MAX_SEG_ID 42
+#define SSSNIC_MSG_MAX_DATA_SIZE (SSSNIC_MSG_BUF_SIZE - SSSNIC_MSG_HDR_SIZE)
+
+struct sssnic_msg {
+	/* message command ID */
+	uint16_t command;
+	/* function id of that message send to or receive from */
+	uint16_t func;
+	/* module id of that message send to or receive from */
+	uint32_t module;
+	/* message is request or response*/
+	enum sssnic_msg_type type;
+	/* message data */
+	uint8_t *data_buf;
+	/* data length */
+	uint32_t data_len;
+	/* need response indication */
+	uint8_t ack;
+	/* the id of last received segment*/
+	uint8_t seg;
+	/* indicate the result of request in response message, request failed if not 0 */
+	uint8_t status;
+	/* generated by sender if dir == SSSNIC_MSG_TYPE_REQ */
+	uint8_t id;
+};
+
+#define SSSNIC_MSG_REJECT -1
+#define SSSNIC_MSG_ACCEPT 0
+#define SSSNIC_MSG_DONE 1
+
+/* sssnic message handler function
+ * @return
+ *   SSSNIC_MSG_REJECT - Message failed to handle
+ *   SSSNIC_MSG_DONE   - Message succeed to handle
+ */
+typedef int sssnic_msg_handler_func_t(struct sssnic_msg *msg,
+	enum sssnic_msg_chann_id chan_id, void *priv);
+
+struct sssnic_msg_handler {
+	sssnic_msg_handler_func_t *func;
+	void *priv;
+};
+
+struct sssnic_msg_channel {
+	enum sssnic_msg_chann_id id;
+	struct sssnic_msg msg[SSSNIC_MSG_TYPE_CONUT][SSSNIC_MSG_SRC_COUNT];
+	struct sssnic_msg_handler handler[SSSNIC_MSG_TYPE_CONUT];
+};
+
+struct sssnic_msg_inbox {
+	struct sssnic_hw *hw;
+	struct sssnic_msg_channel channel[SSSNIC_MSG_CHAN_COUNT];
+};
+
+#define SSSNIC_MSG_INBOX(hw) ((hw)->msg_inbox)
+#define SSSNIC_MSG_CHANNEL(hw, chann_id)                                       \
+	(&(SSSNIC_MSG_INBOX(hw)->channel[chann_id]))
+#define SSSNIC_MSG_LOCATE(hw, chann_id, type, src)                             \
+	(&SSSNIC_MSG_CHANNEL(hw, chann_id)->msg[type][src])
+#define SSSNIC_MSG_HANDLER(hw, chann_id, type)                                 \
+	(&SSSNIC_MSG_CHANNEL(hw, chann_id)->handler[type])
+
+static inline void
+sssnic_msg_init(struct sssnic_msg *msg, uint8_t *data, uint32_t data_len,
+	uint16_t command, uint16_t func, uint32_t module,
+	enum sssnic_msg_type type)
+{
+	memset(msg, 0, sizeof(struct sssnic_msg));
+	msg->data_buf = data;
+	msg->data_len = data_len;
+	msg->command = command;
+	msg->module = module;
+	msg->func = func;
+	msg->type = type;
+}
+
+int sssnic_msg_rx_handler_register(struct sssnic_hw *hw,
+	enum sssnic_msg_chann_id chann_id, enum sssnic_msg_type msg_type,
+	sssnic_msg_handler_func_t *func, void *priv);
+int sssnic_msg_rx_handle(struct sssnic_hw *hw, struct sssnic_msg_hdr *msghdr);
+int sssnic_msg_inbox_init(struct sssnic_hw *hw);
+void sssnic_msg_inbox_shutdown(struct sssnic_hw *hw);
+int sssnic_msg_rx(struct sssnic_msg_hdr *msghdr, uint16_t max_seg_len,
+	uint16_t max_seg_id, struct sssnic_msg *msg);
+
+#endif /* _SSSNIC_MSG_H_ */
