diff --git a/drivers/net/spnic/base/spnic_nic_cfg.c b/drivers/net/spnic/base/spnic_nic_cfg.c
index 258c6cf8c7..e740138b8e 100644
--- a/drivers/net/spnic/base/spnic_nic_cfg.c
+++ b/drivers/net/spnic/base/spnic_nic_cfg.c
@@ -493,6 +493,124 @@ int spnic_get_pause_info(void *hwdev, struct nic_pause_config *nic_pause)
 	return spnic_cfg_hw_pause(hwdev, SPNIC_CMD_OP_GET, nic_pause);
 }
 
+int spnic_get_vport_stats(void *hwdev, struct spnic_vport_stats *stats)
+{
+	struct spnic_port_stats_info stats_info;
+	struct spnic_cmd_vport_stats vport_stats;
+	u16 out_size = sizeof(vport_stats);
+	int err;
+
+	if (!hwdev || !stats)
+		return -EINVAL;
+
+	memset(&stats_info, 0, sizeof(stats_info));
+	memset(&vport_stats, 0, sizeof(vport_stats));
+
+	stats_info.func_id = spnic_global_func_id(hwdev);
+
+	err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_GET_VPORT_STAT,
+				     &stats_info, sizeof(stats_info),
+				     &vport_stats, &out_size);
+	if (err || !out_size || vport_stats.msg_head.status) {
+		PMD_DRV_LOG(ERR, "Get function stats failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, vport_stats.msg_head.status, out_size);
+		return -EIO;
+	}
+
+	memcpy(stats, &vport_stats.stats, sizeof(*stats));
+
+	return 0;
+}
+
+int spnic_get_phy_port_stats(void *hwdev, struct mag_phy_port_stats *stats)
+{
+	struct mag_cmd_get_port_stat *port_stats = NULL;
+	struct mag_cmd_port_stats_info stats_info;
+	u16 out_size = sizeof(*port_stats);
+	int err;
+
+	port_stats = rte_zmalloc("port_stats", sizeof(*port_stats), 0);
+	if (!port_stats)
+		return -ENOMEM;
+
+	memset(&stats_info, 0, sizeof(stats_info));
+	stats_info.port_id = spnic_physical_port_id(hwdev);
+
+	err = mag_msg_to_mgmt_sync(hwdev, MAG_CMD_GET_PORT_STAT,
+				   &stats_info, sizeof(stats_info),
+				   port_stats, &out_size);
+	if (err || !out_size || port_stats->head.status) {
+		PMD_DRV_LOG(ERR,
+			"Failed to get port statistics, err: %d, status: 0x%x, out size: 0x%x\n",
+			err, port_stats->head.status, out_size);
+		err = -EIO;
+		goto out;
+	}
+
+	memcpy(stats, &port_stats->counter, sizeof(*stats));
+
+out:
+	rte_free(port_stats);
+
+	return err;
+}
+
+int spnic_clear_vport_stats(void *hwdev)
+{
+	struct spnic_cmd_clear_vport_stats clear_vport_stats;
+	u16 out_size = sizeof(clear_vport_stats);
+	int err;
+
+	if (!hwdev) {
+		PMD_DRV_LOG(ERR, "Hwdev is NULL");
+		return -EINVAL;
+	}
+
+	memset(&clear_vport_stats, 0, sizeof(clear_vport_stats));
+	clear_vport_stats.func_id = spnic_global_func_id(hwdev);
+
+	err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_CLEAN_VPORT_STAT,
+				     &clear_vport_stats,
+				     sizeof(clear_vport_stats),
+				     &clear_vport_stats, &out_size);
+	if (err || !out_size || clear_vport_stats.msg_head.status) {
+		PMD_DRV_LOG(ERR, "Clear vport stats failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, clear_vport_stats.msg_head.status, out_size);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int spnic_clear_phy_port_stats(void *hwdev)
+{
+	struct mag_cmd_clr_port_stat *port_stats = NULL;
+	u16 out_size = sizeof(*port_stats);
+	int err;
+
+	port_stats = rte_zmalloc("port_stats", sizeof(*port_stats), 0);
+	if (!port_stats)
+		return -ENOMEM;
+
+	port_stats->port_id = spnic_physical_port_id(hwdev);
+
+	err = mag_msg_to_mgmt_sync(hwdev, MAG_CMD_GET_PORT_STAT,
+				   &port_stats, sizeof(port_stats),
+				   port_stats, &out_size);
+	if (err || !out_size || port_stats->head.status) {
+		PMD_DRV_LOG(ERR,
+			"Failed to get port statistics, err: %d, status: 0x%x, out size: 0x%x\n",
+			err, port_stats->head.status, out_size);
+		err = -EIO;
+		goto out;
+	}
+
+out:
+	rte_free(port_stats);
+
+	return err;
+}
+
 static int spnic_set_function_table(void *hwdev, u32 cfg_bitmap,
 				     struct spnic_func_tbl_cfg *cfg)
 {
diff --git a/drivers/net/spnic/base/spnic_nic_cfg.h b/drivers/net/spnic/base/spnic_nic_cfg.h
index bc4707c05b..560c9e4e7d 100644
--- a/drivers/net/spnic/base/spnic_nic_cfg.h
+++ b/drivers/net/spnic/base/spnic_nic_cfg.h
@@ -259,6 +259,160 @@ struct spnic_cmd_clear_qp_resource {
 	u16 rsvd1;
 };
 
+struct spnic_port_stats_info {
+	struct mgmt_msg_head msg_head;
+
+	u16 func_id;
+	u16 rsvd1;
+};
+
+struct spnic_vport_stats {
+	u64 tx_unicast_pkts_vport;
+	u64 tx_unicast_bytes_vport;
+	u64 tx_multicast_pkts_vport;
+	u64 tx_multicast_bytes_vport;
+	u64 tx_broadcast_pkts_vport;
+	u64 tx_broadcast_bytes_vport;
+
+	u64 rx_unicast_pkts_vport;
+	u64 rx_unicast_bytes_vport;
+	u64 rx_multicast_pkts_vport;
+	u64 rx_multicast_bytes_vport;
+	u64 rx_broadcast_pkts_vport;
+	u64 rx_broadcast_bytes_vport;
+
+	u64 tx_discard_vport;
+	u64 rx_discard_vport;
+	u64 tx_err_vport;
+	u64 rx_err_vport;
+};
+
+struct spnic_cmd_vport_stats {
+	struct mgmt_msg_head msg_head;
+
+	u32 stats_size;
+	u32 rsvd1;
+	struct spnic_vport_stats stats;
+	u64 rsvd2[6];
+};
+
+struct mag_phy_port_stats {
+	u64 mac_tx_fragment_pkt_num;
+	u64 mac_tx_undersize_pkt_num;
+	u64 mac_tx_undermin_pkt_num;
+	u64 mac_tx_64_oct_pkt_num;
+	u64 mac_tx_65_127_oct_pkt_num;
+	u64 mac_tx_128_255_oct_pkt_num;
+	u64 mac_tx_256_511_oct_pkt_num;
+	u64 mac_tx_512_1023_oct_pkt_num;
+	u64 mac_tx_1024_1518_oct_pkt_num;
+	u64 mac_tx_1519_2047_oct_pkt_num;
+	u64 mac_tx_2048_4095_oct_pkt_num;
+	u64 mac_tx_4096_8191_oct_pkt_num;
+	u64 mac_tx_8192_9216_oct_pkt_num;
+	u64 mac_tx_9217_12287_oct_pkt_num;
+	u64 mac_tx_12288_16383_oct_pkt_num;
+	u64 mac_tx_1519_max_bad_pkt_num;
+	u64 mac_tx_1519_max_good_pkt_num;
+	u64 mac_tx_oversize_pkt_num;
+	u64 mac_tx_jabber_pkt_num;
+	u64 mac_tx_bad_pkt_num;
+	u64 mac_tx_bad_oct_num;
+	u64 mac_tx_good_pkt_num;
+	u64 mac_tx_good_oct_num;
+	u64 mac_tx_total_pkt_num;
+	u64 mac_tx_total_oct_num;
+	u64 mac_tx_uni_pkt_num;
+	u64 mac_tx_multi_pkt_num;
+	u64 mac_tx_broad_pkt_num;
+	u64 mac_tx_pause_num;
+	u64 mac_tx_pfc_pkt_num;
+	u64 mac_tx_pfc_pri0_pkt_num;
+	u64 mac_tx_pfc_pri1_pkt_num;
+	u64 mac_tx_pfc_pri2_pkt_num;
+	u64 mac_tx_pfc_pri3_pkt_num;
+	u64 mac_tx_pfc_pri4_pkt_num;
+	u64 mac_tx_pfc_pri5_pkt_num;
+	u64 mac_tx_pfc_pri6_pkt_num;
+	u64 mac_tx_pfc_pri7_pkt_num;
+	u64 mac_tx_control_pkt_num;
+	u64 mac_tx_err_all_pkt_num;
+	u64 mac_tx_from_app_good_pkt_num;
+	u64 mac_tx_from_app_bad_pkt_num;
+
+	u64 mac_rx_fragment_pkt_num;
+	u64 mac_rx_undersize_pkt_num;
+	u64 mac_rx_undermin_pkt_num;
+	u64 mac_rx_64_oct_pkt_num;
+	u64 mac_rx_65_127_oct_pkt_num;
+	u64 mac_rx_128_255_oct_pkt_num;
+	u64 mac_rx_256_511_oct_pkt_num;
+	u64 mac_rx_512_1023_oct_pkt_num;
+	u64 mac_rx_1024_1518_oct_pkt_num;
+	u64 mac_rx_1519_2047_oct_pkt_num;
+	u64 mac_rx_2048_4095_oct_pkt_num;
+	u64 mac_rx_4096_8191_oct_pkt_num;
+	u64 mac_rx_8192_9216_oct_pkt_num;
+	u64 mac_rx_9217_12287_oct_pkt_num;
+	u64 mac_rx_12288_16383_oct_pkt_num;
+	u64 mac_rx_1519_max_bad_pkt_num;
+	u64 mac_rx_1519_max_good_pkt_num;
+	u64 mac_rx_oversize_pkt_num;
+	u64 mac_rx_jabber_pkt_num;
+	u64 mac_rx_bad_pkt_num;
+	u64 mac_rx_bad_oct_num;
+	u64 mac_rx_good_pkt_num;
+	u64 mac_rx_good_oct_num;
+	u64 mac_rx_total_pkt_num;
+	u64 mac_rx_total_oct_num;
+	u64 mac_rx_uni_pkt_num;
+	u64 mac_rx_multi_pkt_num;
+	u64 mac_rx_broad_pkt_num;
+	u64 mac_rx_pause_num;
+	u64 mac_rx_pfc_pkt_num;
+	u64 mac_rx_pfc_pri0_pkt_num;
+	u64 mac_rx_pfc_pri1_pkt_num;
+	u64 mac_rx_pfc_pri2_pkt_num;
+	u64 mac_rx_pfc_pri3_pkt_num;
+	u64 mac_rx_pfc_pri4_pkt_num;
+	u64 mac_rx_pfc_pri5_pkt_num;
+	u64 mac_rx_pfc_pri6_pkt_num;
+	u64 mac_rx_pfc_pri7_pkt_num;
+	u64 mac_rx_control_pkt_num;
+	u64 mac_rx_sym_err_pkt_num;
+	u64 mac_rx_fcs_err_pkt_num;
+	u64 mac_rx_send_app_good_pkt_num;
+	u64 mac_rx_send_app_bad_pkt_num;
+	u64 mac_rx_unfilter_pkt_num;
+};
+
+struct mag_cmd_port_stats_info {
+	struct mgmt_msg_head head;
+
+	u8 port_id;
+	u8 rsvd0[3];
+};
+
+struct mag_cmd_get_port_stat {
+	struct mgmt_msg_head head;
+
+	struct mag_phy_port_stats counter;
+	u64 rsvd1[15];
+};
+
+struct mag_cmd_clr_port_stat {
+	struct mgmt_msg_head head;
+
+	u8 port_id;
+	u8 rsvd0[3];
+};
+
+struct spnic_cmd_clear_vport_stats {
+	struct mgmt_msg_head msg_head;
+
+	u16 func_id;
+	u16 rsvd;
+};
 
 enum spnic_func_tbl_cfg_bitmap {
 	FUNC_CFG_INIT,
@@ -586,6 +740,58 @@ int spnic_set_pause_info(void *hwdev, struct nic_pause_config nic_pause);
  */
 int spnic_get_pause_info(void *hwdev, struct nic_pause_config *nic_pause);
 
+/**
+ * Get function stats
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[out] stats
+ *   Function stats
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_get_vport_stats(void *hwdev, struct spnic_vport_stats *stats);
+
+/**
+ * Get port stats
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[out] stats
+ *   Port stats
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_get_phy_port_stats(void *hwdev, struct mag_phy_port_stats *stats);
+
+/**
+ * Clear function stats
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[out] stats
+ *   Function stats
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_clear_vport_stats(void *hwdev);
+
+/**
+ * Clear port stats
+ *
+ * @param[in] hwdev
+ *   Device pointer to hwdev
+ * @param[out] stats
+ *   Port stats
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_clear_phy_port_stats(void *hwdev);
+
 /**
  * Init nic hwdev
  *
diff --git a/drivers/net/spnic/spnic_ethdev.c b/drivers/net/spnic/spnic_ethdev.c
index 0dc7c367e7..b53eb96903 100644
--- a/drivers/net/spnic/spnic_ethdev.c
+++ b/drivers/net/spnic/spnic_ethdev.c
@@ -66,6 +66,171 @@ enum spnic_rx_mod {
 #define SPNIC_DEFAULT_RX_MODE	(SPNIC_RX_MODE_UC | SPNIC_RX_MODE_MC | \
 				SPNIC_RX_MODE_BC)
 
+struct spnic_xstats_name_off {
+	char name[RTE_ETH_XSTATS_NAME_SIZE];
+	u32  offset;
+};
+
+#define SPNIC_FUNC_STAT(_stat_item) {	\
+	.name = #_stat_item, \
+	.offset = offsetof(struct spnic_vport_stats, _stat_item) \
+}
+
+#define SPNIC_PORT_STAT(_stat_item) { \
+	.name = #_stat_item, \
+	.offset = offsetof(struct mag_phy_port_stats, _stat_item) \
+}
+
+static const struct spnic_xstats_name_off spnic_vport_stats_strings[] = {
+	SPNIC_FUNC_STAT(tx_unicast_pkts_vport),
+	SPNIC_FUNC_STAT(tx_unicast_bytes_vport),
+	SPNIC_FUNC_STAT(tx_multicast_pkts_vport),
+	SPNIC_FUNC_STAT(tx_multicast_bytes_vport),
+	SPNIC_FUNC_STAT(tx_broadcast_pkts_vport),
+	SPNIC_FUNC_STAT(tx_broadcast_bytes_vport),
+
+	SPNIC_FUNC_STAT(rx_unicast_pkts_vport),
+	SPNIC_FUNC_STAT(rx_unicast_bytes_vport),
+	SPNIC_FUNC_STAT(rx_multicast_pkts_vport),
+	SPNIC_FUNC_STAT(rx_multicast_bytes_vport),
+	SPNIC_FUNC_STAT(rx_broadcast_pkts_vport),
+	SPNIC_FUNC_STAT(rx_broadcast_bytes_vport),
+
+	SPNIC_FUNC_STAT(tx_discard_vport),
+	SPNIC_FUNC_STAT(rx_discard_vport),
+	SPNIC_FUNC_STAT(tx_err_vport),
+	SPNIC_FUNC_STAT(rx_err_vport),
+};
+
+#define SPNIC_VPORT_XSTATS_NUM (sizeof(spnic_vport_stats_strings) / \
+		sizeof(spnic_vport_stats_strings[0]))
+
+static const struct spnic_xstats_name_off spnic_phyport_stats_strings[] = {
+	SPNIC_PORT_STAT(mac_tx_fragment_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_undersize_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_undermin_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_64_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_65_127_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_128_255_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_256_511_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_512_1023_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_1024_1518_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_1519_2047_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_2048_4095_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_4096_8191_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_8192_9216_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_9217_12287_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_12288_16383_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_1519_max_bad_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_1519_max_good_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_oversize_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_jabber_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_bad_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_bad_oct_num),
+	SPNIC_PORT_STAT(mac_tx_good_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_good_oct_num),
+	SPNIC_PORT_STAT(mac_tx_total_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_total_oct_num),
+	SPNIC_PORT_STAT(mac_tx_uni_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_multi_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_broad_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_pause_num),
+	SPNIC_PORT_STAT(mac_tx_pfc_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_pfc_pri0_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_pfc_pri1_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_pfc_pri2_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_pfc_pri3_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_pfc_pri4_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_pfc_pri5_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_pfc_pri6_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_pfc_pri7_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_control_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_err_all_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_from_app_good_pkt_num),
+	SPNIC_PORT_STAT(mac_tx_from_app_bad_pkt_num),
+
+	SPNIC_PORT_STAT(mac_rx_fragment_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_undersize_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_undermin_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_64_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_65_127_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_128_255_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_256_511_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_512_1023_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_1024_1518_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_1519_2047_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_2048_4095_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_4096_8191_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_8192_9216_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_9217_12287_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_12288_16383_oct_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_1519_max_bad_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_1519_max_good_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_oversize_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_jabber_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_bad_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_bad_oct_num),
+	SPNIC_PORT_STAT(mac_rx_good_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_good_oct_num),
+	SPNIC_PORT_STAT(mac_rx_total_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_total_oct_num),
+	SPNIC_PORT_STAT(mac_rx_uni_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_multi_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_broad_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_pause_num),
+	SPNIC_PORT_STAT(mac_rx_pfc_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_pfc_pri0_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_pfc_pri1_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_pfc_pri2_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_pfc_pri3_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_pfc_pri4_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_pfc_pri5_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_pfc_pri6_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_pfc_pri7_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_control_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_sym_err_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_fcs_err_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_send_app_good_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_send_app_bad_pkt_num),
+	SPNIC_PORT_STAT(mac_rx_unfilter_pkt_num)
+};
+
+#define SPNIC_PHYPORT_XSTATS_NUM (sizeof(spnic_phyport_stats_strings) / \
+		sizeof(spnic_phyport_stats_strings[0]))
+
+static const struct spnic_xstats_name_off spnic_rxq_stats_strings[] = {
+	{"rx_nombuf", offsetof(struct spnic_rxq_stats, rx_nombuf)},
+	{"burst_pkt", offsetof(struct spnic_rxq_stats, burst_pkts)},
+};
+
+#define SPNIC_RXQ_XSTATS_NUM (sizeof(spnic_rxq_stats_strings) / \
+		sizeof(spnic_rxq_stats_strings[0]))
+
+static const struct spnic_xstats_name_off spnic_txq_stats_strings[] = {
+	{"tx_busy", offsetof(struct spnic_txq_stats, tx_busy)},
+	{"offload_errors", offsetof(struct spnic_txq_stats, off_errs)},
+	{"burst_pkts", offsetof(struct spnic_txq_stats, burst_pkts)},
+	{"sge_len0", offsetof(struct spnic_txq_stats, sge_len0)},
+	{"mbuf_null", offsetof(struct spnic_txq_stats, mbuf_null)},
+};
+
+#define SPNIC_TXQ_XSTATS_NUM (sizeof(spnic_txq_stats_strings) / \
+		sizeof(spnic_txq_stats_strings[0]))
+
+static int spnic_xstats_calc_num(struct spnic_nic_dev *nic_dev)
+{
+	if (SPNIC_IS_VF(nic_dev->hwdev)) {
+		return (SPNIC_VPORT_XSTATS_NUM +
+			SPNIC_RXQ_XSTATS_NUM * nic_dev->num_rqs +
+			SPNIC_TXQ_XSTATS_NUM * nic_dev->num_sqs);
+	} else {
+		return (SPNIC_VPORT_XSTATS_NUM +
+			SPNIC_PHYPORT_XSTATS_NUM +
+			SPNIC_RXQ_XSTATS_NUM * nic_dev->num_rqs +
+			SPNIC_TXQ_XSTATS_NUM * nic_dev->num_sqs);
+	}
+}
+
 #define SPNIC_MAX_QUEUE_DEPTH		16384
 #define SPNIC_MIN_QUEUE_DEPTH		128
 #define SPNIC_TXD_ALIGN			1
@@ -1827,6 +1992,305 @@ static int spnic_rss_reta_update(struct rte_eth_dev *dev,
 	return err;
 }
 
+/**
+ * Get device generic statistics.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ * @param[out] stats
+ *   Stats structure output buffer.
+ *
+ * @retval zero: Success
+ * @retval non-zero: Failure
+ */
+static int spnic_dev_stats_get(struct rte_eth_dev *dev,
+			       struct rte_eth_stats *stats)
+{
+	struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	struct spnic_vport_stats vport_stats;
+	struct spnic_rxq *rxq = NULL;
+	struct spnic_txq *txq = NULL;
+	int i, err, q_num;
+	u64 rx_discards_pmd = 0;
+
+	err = spnic_get_vport_stats(nic_dev->hwdev, &vport_stats);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Get vport stats from fw failed, nic_dev: %s",
+			    nic_dev->dev_name);
+		return err;
+	}
+
+	dev->data->rx_mbuf_alloc_failed = 0;
+
+	/* Rx queue stats */
+	q_num = (nic_dev->num_rqs < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
+		nic_dev->num_rqs : RTE_ETHDEV_QUEUE_STAT_CNTRS;
+	for (i = 0; i < q_num; i++) {
+		rxq = nic_dev->rxqs[i];
+		stats->q_ipackets[i] = rxq->rxq_stats.packets;
+		stats->q_ibytes[i] = rxq->rxq_stats.bytes;
+		stats->q_errors[i] = rxq->rxq_stats.dropped;
+
+		stats->ierrors += rxq->rxq_stats.errors;
+		rx_discards_pmd += rxq->rxq_stats.dropped;
+		dev->data->rx_mbuf_alloc_failed += rxq->rxq_stats.rx_nombuf;
+	}
+
+	/* Tx queue stats */
+	q_num = (nic_dev->num_sqs < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
+		nic_dev->num_sqs : RTE_ETHDEV_QUEUE_STAT_CNTRS;
+	for (i = 0; i < q_num; i++) {
+		txq = nic_dev->txqs[i];
+		stats->q_opackets[i] = txq->txq_stats.packets;
+		stats->q_obytes[i] = txq->txq_stats.bytes;
+		stats->oerrors += (txq->txq_stats.tx_busy +
+				  txq->txq_stats.off_errs);
+	}
+
+	/* Vport stats */
+	stats->oerrors += vport_stats.tx_discard_vport;
+
+	stats->imissed = vport_stats.rx_discard_vport + rx_discards_pmd;
+
+	stats->ipackets = (vport_stats.rx_unicast_pkts_vport +
+			  vport_stats.rx_multicast_pkts_vport +
+			  vport_stats.rx_broadcast_pkts_vport -
+			  rx_discards_pmd);
+
+	stats->opackets = (vport_stats.tx_unicast_pkts_vport +
+			  vport_stats.tx_multicast_pkts_vport +
+			  vport_stats.tx_broadcast_pkts_vport);
+
+	stats->ibytes = (vport_stats.rx_unicast_bytes_vport +
+			vport_stats.rx_multicast_bytes_vport +
+			vport_stats.rx_broadcast_bytes_vport);
+
+	stats->obytes = (vport_stats.tx_unicast_bytes_vport +
+			vport_stats.tx_multicast_bytes_vport +
+			vport_stats.tx_broadcast_bytes_vport);
+	return 0;
+}
+
+/**
+ * Clear device generic statistics.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ *
+ * @retval zero: Success
+ * @retval non-zero: Failure
+ */
+static int spnic_dev_stats_reset(struct rte_eth_dev *dev)
+{
+	struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	struct spnic_rxq *rxq = NULL;
+	struct spnic_txq *txq = NULL;
+	int qid;
+	int err;
+
+	err = spnic_clear_vport_stats(nic_dev->hwdev);
+	if (err)
+		return err;
+
+	for (qid = 0; qid < nic_dev->num_rqs; qid++) {
+		rxq = nic_dev->rxqs[qid];
+		memset(&rxq->rxq_stats, 0, sizeof(struct spnic_rxq_stats));
+	}
+
+	for (qid = 0; qid < nic_dev->num_sqs; qid++) {
+		txq = nic_dev->txqs[qid];
+		memset(&txq->txq_stats, 0, sizeof(struct spnic_txq_stats));
+	}
+
+	return 0;
+}
+
+/**
+ * Get device extended statistics.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ * @param[out] xstats
+ *   Pointer to rte extended stats table.
+ * @param[in] n
+ *   The size of the stats table.
+ *
+ * @retval positive: Number of extended stats on success and stats is filled
+ * @retval negative: Failure
+ */
+static int spnic_dev_xstats_get(struct rte_eth_dev *dev,
+				struct rte_eth_xstat *xstats, unsigned int n)
+{
+	struct spnic_nic_dev *nic_dev;
+	struct mag_phy_port_stats port_stats;
+	struct spnic_vport_stats vport_stats;
+	struct spnic_rxq *rxq = NULL;
+	struct spnic_rxq_stats rxq_stats;
+	struct spnic_txq *txq = NULL;
+	struct spnic_txq_stats txq_stats;
+	u16 qid;
+	u32 i;
+	int err, count;
+
+	nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	count = spnic_xstats_calc_num(nic_dev);
+	if ((int)n < count)
+		return count;
+
+	count = 0;
+
+	/* Get stats from rxq stats structure */
+	for (qid = 0; qid < nic_dev->num_rqs; qid++) {
+		rxq = nic_dev->rxqs[qid];
+		memcpy(&rxq_stats, &rxq->rxq_stats, sizeof(rxq->rxq_stats));
+
+		for (i = 0; i < SPNIC_RXQ_XSTATS_NUM; i++) {
+			xstats[count].value =
+				*(uint64_t *)(((char *)&rxq_stats) +
+				spnic_rxq_stats_strings[i].offset);
+			xstats[count].id = count;
+			count++;
+		}
+	}
+
+	/* Get stats from txq stats structure */
+	for (qid = 0; qid < nic_dev->num_sqs; qid++) {
+		txq = nic_dev->txqs[qid];
+		memcpy(&txq_stats, &txq->txq_stats, sizeof(txq->txq_stats));
+
+		for (i = 0; i < SPNIC_TXQ_XSTATS_NUM; i++) {
+			xstats[count].value =
+				*(uint64_t *)(((char *)&txq_stats) +
+				spnic_txq_stats_strings[i].offset);
+			xstats[count].id = count;
+			count++;
+		}
+	}
+
+	/* Get stats from vport stats structure */
+	err = spnic_get_vport_stats(nic_dev->hwdev, &vport_stats);
+	if (err)
+		return err;
+
+	for (i = 0; i < SPNIC_VPORT_XSTATS_NUM; i++) {
+		xstats[count].value =
+			*(uint64_t *)(((char *)&vport_stats) +
+			spnic_vport_stats_strings[i].offset);
+		xstats[count].id = count;
+		count++;
+	}
+
+	if (SPNIC_IS_VF(nic_dev->hwdev))
+		return count;
+
+	/* Get stats from phy port stats structure */
+	err = spnic_get_phy_port_stats(nic_dev->hwdev, &port_stats);
+	if (err)
+		return err;
+
+	for (i = 0; i < SPNIC_PHYPORT_XSTATS_NUM; i++) {
+		xstats[count].value = *(uint64_t *)(((char *)&port_stats) +
+				spnic_phyport_stats_strings[i].offset);
+		xstats[count].id = count;
+		count++;
+	}
+
+	return count;
+}
+
+/**
+ * Clear device extended statistics.
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ *
+ * @retval zero: Success
+ * @retval non-zero: Failure
+ */
+static int spnic_dev_xstats_reset(struct rte_eth_dev *dev)
+{
+	struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	int err;
+
+	err = spnic_dev_stats_reset(dev);
+	if (err)
+		return err;
+
+	if (spnic_func_type(nic_dev->hwdev) != TYPE_VF) {
+		err = spnic_clear_phy_port_stats(nic_dev->hwdev);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * Retrieve names of extended device statistics
+ *
+ * @param[in] dev
+ *   Pointer to ethernet device structure.
+ * @param[out] xstats_names
+ *   Buffer to insert names into.
+ *
+ * @return
+ *   Number of xstats names.
+ */
+static int spnic_dev_xstats_get_names(struct rte_eth_dev *dev,
+				      struct rte_eth_xstat_name *xstats_names,
+				      __rte_unused unsigned int limit)
+{
+	struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+	int count = 0;
+	u16 i, q_num;
+
+	if (xstats_names == NULL)
+		return spnic_xstats_calc_num(nic_dev);
+
+	/* Get pmd rxq stats name */
+	for (q_num = 0; q_num < nic_dev->num_rqs; q_num++) {
+		for (i = 0; i < SPNIC_RXQ_XSTATS_NUM; i++) {
+			snprintf(xstats_names[count].name,
+				 sizeof(xstats_names[count].name),
+				 "rxq%d_%s_pmd", q_num,
+				 spnic_rxq_stats_strings[i].name);
+			count++;
+		}
+	}
+
+	/* Get pmd txq stats name */
+	for (q_num = 0; q_num < nic_dev->num_sqs; q_num++) {
+		for (i = 0; i < SPNIC_TXQ_XSTATS_NUM; i++) {
+			snprintf(xstats_names[count].name,
+				 sizeof(xstats_names[count].name),
+				 "txq%d_%s_pmd", q_num,
+				 spnic_txq_stats_strings[i].name);
+			count++;
+		}
+	}
+
+	/* Get vport stats name */
+	for (i = 0; i < SPNIC_VPORT_XSTATS_NUM; i++) {
+		snprintf(xstats_names[count].name,
+			 sizeof(xstats_names[count].name),
+			 "%s", spnic_vport_stats_strings[i].name);
+		count++;
+	}
+
+	if (SPNIC_IS_VF(nic_dev->hwdev))
+		return count;
+
+	/* Get phy port stats name */
+	for (i = 0; i < SPNIC_PHYPORT_XSTATS_NUM; i++) {
+		snprintf(xstats_names[count].name,
+			 sizeof(xstats_names[count].name),
+			 "%s", spnic_phyport_stats_strings[i].name);
+		count++;
+	}
+
+	return count;
+}
+
 static void spnic_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
 			       struct rte_eth_rxq_info *rxq_info)
 {
@@ -2059,6 +2523,11 @@ static const struct eth_dev_ops spnic_pmd_ops = {
 	.rss_hash_conf_get             = spnic_rss_conf_get,
 	.reta_update                   = spnic_rss_reta_update,
 	.reta_query                    = spnic_rss_reta_query,
+	.stats_get                     = spnic_dev_stats_get,
+	.stats_reset                   = spnic_dev_stats_reset,
+	.xstats_get                    = spnic_dev_xstats_get,
+	.xstats_reset                  = spnic_dev_xstats_reset,
+	.xstats_get_names              = spnic_dev_xstats_get_names,
 	.rxq_info_get                  = spnic_rxq_info_get,
 	.txq_info_get                  = spnic_txq_info_get,
 	.mac_addr_set                  = spnic_set_mac_addr,
@@ -2092,6 +2561,11 @@ static const struct eth_dev_ops spnic_pmd_vf_ops = {
 	.rss_hash_conf_get             = spnic_rss_conf_get,
 	.reta_update                   = spnic_rss_reta_update,
 	.reta_query                    = spnic_rss_reta_query,
+	.stats_get                     = spnic_dev_stats_get,
+	.stats_reset                   = spnic_dev_stats_reset,
+	.xstats_get                    = spnic_dev_xstats_get,
+	.xstats_reset                  = spnic_dev_xstats_reset,
+	.xstats_get_names              = spnic_dev_xstats_get_names,
 	.rxq_info_get                  = spnic_rxq_info_get,
 	.txq_info_get                  = spnic_txq_info_get,
 	.mac_addr_set                  = spnic_set_mac_addr,
