diff --git a/drivers/net/nfp/nfp_net_cmsg.h b/drivers/net/nfp/nfp_net_cmsg.h
index a95f4ef831..9bc064d9d7 100644
--- a/drivers/net/nfp/nfp_net_cmsg.h
+++ b/drivers/net/nfp/nfp_net_cmsg.h
@@ -21,6 +21,43 @@ struct nfp_net_cmsg_match_eth {
 	uint16_t spare;
 };
 
+/**
+ * Match IPv4 data
+ * Bit    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+ * -----\ 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * Word  +-----+-------------------------+---------------+---------------+
+ *    0  |     |        Position         |   L4 Proto    | L4 Proto Mask |
+ *       +-----+-------------------------+---------------+---------------+
+ *    1  |                             SIP4                              |
+ *       +---------------------------------------------------------------+
+ *    2  |                           SIP4 Mask                           |
+ *       +---------------------------------------------------------------+
+ *    3  |                             DIP4                              |
+ *       +---------------------------------------------------------------+
+ *    4  |                           DIP4 Mask                           |
+ *       +-------------------------------+-------------------------------+
+ *    5  |             SPort             |           SPort Mask          |
+ *       +-------------------------------+-------------------------------+
+ *    6  |             DPort             |           DPort Mask          |
+ *       +-----------------+-------------+-------------------------------+
+ *
+ * Position – Position index of the rule, 13bits.
+ *            As priority, smaller value indicates higher priority.
+ */
+struct nfp_net_cmsg_match_v4 {
+	uint8_t l4_protocol_mask;
+	uint8_t l4_protocol;
+	uint16_t position;
+	uint32_t src_ipv4;
+	uint32_t src_ipv4_mask;
+	uint32_t dst_ipv4;
+	uint32_t dst_ipv4_mask;
+	uint16_t src_port;
+	uint16_t src_port_mask;
+	uint16_t dst_port;
+	uint16_t dst_port_mask;
+};
+
 #define NFP_NET_CMSG_ACTION_DROP          (0x1 << 0) /* Drop action */
 #define NFP_NET_CMSG_ACTION_QUEUE         (0x1 << 1) /* Queue action */
 #define NFP_NET_CMSG_ACTION_MARK          (0x1 << 2) /* Mark action */
diff --git a/drivers/net/nfp/nfp_net_flow.c b/drivers/net/nfp/nfp_net_flow.c
index c8b6902bf1..6edb96c17a 100644
--- a/drivers/net/nfp/nfp_net_flow.c
+++ b/drivers/net/nfp/nfp_net_flow.c
@@ -188,6 +188,10 @@ nfp_net_flow_calculate_items(const struct rte_flow_item items[],
 			PMD_DRV_LOG(DEBUG, "RTE_FLOW_ITEM_TYPE_ETH detected");
 			*match_len = sizeof(struct nfp_net_cmsg_match_eth);
 			return 0;
+		case RTE_FLOW_ITEM_TYPE_IPV4:
+			PMD_DRV_LOG(DEBUG, "RTE_FLOW_ITEM_TYPE_IPV4 detected");
+			*match_len = sizeof(struct nfp_net_cmsg_match_v4);
+			return 0;
 		default:
 			PMD_DRV_LOG(ERR, "Can't calculate match length");
 			*match_len = 0;
@@ -220,14 +224,58 @@ nfp_net_flow_merge_eth(__rte_unused struct rte_flow *nfp_flow,
 	return 0;
 }
 
+static int
+nfp_net_flow_merge_ipv4(struct rte_flow *nfp_flow,
+		const struct rte_flow_item *item,
+		const struct nfp_net_flow_item_proc *proc)
+{
+	struct nfp_net_cmsg_match_v4 *ipv4;
+	const struct rte_flow_item_ipv4 *mask;
+	const struct rte_flow_item_ipv4 *spec;
+
+	spec = item->spec;
+	if (spec == NULL) {
+		PMD_DRV_LOG(DEBUG, "NFP flow merge ipv4: no item->spec!");
+		return 0;
+	}
+
+	mask = (item->mask != NULL) ? item->mask : proc->mask_default;
+
+	nfp_flow->payload.cmsg_type = NFP_NET_CFG_MBOX_CMD_FS_ADD_V4;
+	ipv4 = (struct nfp_net_cmsg_match_v4 *)nfp_flow->payload.match_data;
+
+	ipv4->l4_protocol_mask = mask->hdr.next_proto_id;
+	ipv4->src_ipv4_mask    = rte_be_to_cpu_32(mask->hdr.src_addr);
+	ipv4->dst_ipv4_mask    = rte_be_to_cpu_32(mask->hdr.dst_addr);
+
+	ipv4->l4_protocol  = spec->hdr.next_proto_id;
+	ipv4->src_ipv4     = rte_be_to_cpu_32(spec->hdr.src_addr);
+	ipv4->dst_ipv4     = rte_be_to_cpu_32(spec->hdr.dst_addr);
+
+	return 0;
+}
+
 /* Graph of supported items and associated process function */
 static const struct nfp_net_flow_item_proc nfp_net_flow_item_proc_list[] = {
 	[RTE_FLOW_ITEM_TYPE_END] = {
-		.next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_ETH),
+		.next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_ETH,
+				RTE_FLOW_ITEM_TYPE_IPV4),
 	},
 	[RTE_FLOW_ITEM_TYPE_ETH] = {
 		.merge = nfp_net_flow_merge_eth,
 	},
+	[RTE_FLOW_ITEM_TYPE_IPV4] = {
+		.mask_support = &(const struct rte_flow_item_ipv4){
+			.hdr = {
+				.next_proto_id = 0xff,
+				.src_addr      = RTE_BE32(0xffffffff),
+				.dst_addr      = RTE_BE32(0xffffffff),
+			},
+		},
+		.mask_default = &rte_flow_item_ipv4_mask,
+		.mask_sz = sizeof(struct rte_flow_item_ipv4),
+		.merge = nfp_net_flow_merge_ipv4,
+	},
 };
 
 static int
@@ -367,10 +415,16 @@ nfp_net_flow_compile_actions(const struct rte_flow_action actions[],
 }
 
 static void
-nfp_net_flow_process_priority(__rte_unused struct rte_flow *nfp_flow,
+nfp_net_flow_process_priority(struct rte_flow *nfp_flow,
 		uint32_t match_len)
 {
+	struct nfp_net_cmsg_match_v4 *ipv4;
+
 	switch (match_len) {
+	case sizeof(struct nfp_net_cmsg_match_v4):
+		ipv4 = (struct nfp_net_cmsg_match_v4 *)nfp_flow->payload.match_data;
+		ipv4->position = nfp_flow->position;
+		break;
 	default:
 		break;
 	}
