diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 58939ec321..3ade229ffc 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -496,6 +496,11 @@ enum index {
 	ITEM_QUOTA_STATE_NAME,
 	ITEM_AGGR_AFFINITY,
 	ITEM_AGGR_AFFINITY_VALUE,
+	ITEM_IB_BTH,
+	ITEM_IB_BTH_OPCODE,
+	ITEM_IB_BTH_PKEY,
+	ITEM_IB_BTH_DST_QPN,
+	ITEM_IB_BTH_PSN,
 
 	/* Validate/create actions. */
 	ACTIONS,
@@ -1452,6 +1457,7 @@ static const enum index next_item[] = {
 	ITEM_METER,
 	ITEM_QUOTA,
 	ITEM_AGGR_AFFINITY,
+	ITEM_IB_BTH,
 	END_SET,
 	ZERO,
 };
@@ -1953,6 +1959,15 @@ static const enum index item_aggr_affinity[] = {
 	ZERO,
 };
 
+static const enum index item_ib_bth[] = {
+	ITEM_IB_BTH_OPCODE,
+	ITEM_IB_BTH_PKEY,
+	ITEM_IB_BTH_DST_QPN,
+	ITEM_IB_BTH_PSN,
+	ITEM_NEXT,
+	ZERO,
+};
+
 static const enum index next_action[] = {
 	ACTION_END,
 	ACTION_VOID,
@@ -5523,6 +5538,46 @@ static const struct token token_list[] = {
 		.call = parse_quota_state_name,
 		.comp = comp_quota_state_name
 	},
+	[ITEM_IB_BTH] = {
+		.name = "ib_bth",
+		.help = "match ib bth fields",
+		.priv = PRIV_ITEM(IB_BTH,
+				  sizeof(struct rte_flow_item_ib_bth)),
+		.next = NEXT(item_ib_bth),
+		.call = parse_vc,
+	},
+	[ITEM_IB_BTH_OPCODE] = {
+		.name = "opcode",
+		.help = "match ib bth opcode",
+		.next = NEXT(item_ib_bth, NEXT_ENTRY(COMMON_UNSIGNED),
+				 item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ib_bth,
+						 hdr.opcode)),
+	},
+	[ITEM_IB_BTH_PKEY] = {
+		.name = "pkey",
+		.help = "partition key",
+		.next = NEXT(item_ib_bth, NEXT_ENTRY(COMMON_UNSIGNED),
+				 item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ib_bth,
+						 hdr.pkey)),
+	},
+	[ITEM_IB_BTH_DST_QPN] = {
+		.name = "dst_qp",
+		.help = "destination qp",
+		.next = NEXT(item_ib_bth, NEXT_ENTRY(COMMON_UNSIGNED),
+				 item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ib_bth,
+						 hdr.dst_qp)),
+	},
+	[ITEM_IB_BTH_PSN] = {
+		.name = "psn",
+		.help = "packet sequence number",
+		.next = NEXT(item_ib_bth, NEXT_ENTRY(COMMON_UNSIGNED),
+				 item_param),
+		.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ib_bth,
+						 hdr.psn)),
+	},
 	/* Validate/create actions. */
 	[ACTIONS] = {
 		.name = "actions",
@@ -11849,6 +11904,9 @@ flow_item_default_mask(const struct rte_flow_item *item)
 	case RTE_FLOW_ITEM_TYPE_AGGR_AFFINITY:
 		mask = &rte_flow_item_aggr_affinity_mask;
 		break;
+	case RTE_FLOW_ITEM_TYPE_IB_BTH:
+		mask = &rte_flow_item_ib_bth_mask;
+		break;
 	default:
 		break;
 	}
diff --git a/devtools/words-case.txt b/devtools/words-case.txt
index 42c7861b68..5bd34e8b88 100644
--- a/devtools/words-case.txt
+++ b/devtools/words-case.txt
@@ -27,6 +27,7 @@ GENEVE
 GTPU
 GUID
 HW
+IB
 ICMP
 ID
 IO
@@ -74,6 +75,7 @@ QinQ
 RDMA
 RETA
 ROC
+RoCE
 RQ
 RSS
 RVU
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index c709fd48ad..a98439c4fb 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -127,7 +127,8 @@ The public API headers are grouped by topics:
   [Geneve](@ref rte_geneve.h),
   [eCPRI](@ref rte_ecpri.h),
   [L2TPv2](@ref rte_l2tpv2.h),
-  [PPP](@ref rte_ppp.h)
+  [PPP](@ref rte_ppp.h),
+  [IB](@ref rte_ib.h)
 
 - **QoS**:
   [metering](@ref rte_meter.h),
diff --git a/doc/guides/nics/features/default.ini b/doc/guides/nics/features/default.ini
index 1a5087abad..1738715e26 100644
--- a/doc/guides/nics/features/default.ini
+++ b/doc/guides/nics/features/default.ini
@@ -104,6 +104,7 @@ gtpc                 =
 gtpu                 =
 gtp_psc              =
 higig2               =
+ib_bth               =
 icmp                 =
 icmp6                =
 icmp6_echo_request   =
diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 32fc45516a..e2957df71c 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -1551,6 +1551,13 @@ Matches flow quota state set by quota action.
 
 - ``state``: Flow quota state
 
+Item: ``IB_BTH``
+^^^^^^^^^^^^^^^^
+
+Matches an InfiniBand base transport header in RoCE packet.
+
+- ``hdr``: InfiniBand base transport header definition (``rte_ib.h``).
+
 Actions
 ~~~~~~~
 
diff --git a/doc/guides/rel_notes/release_23_07.rst b/doc/guides/rel_notes/release_23_07.rst
index a9b1293689..cc9ee8e170 100644
--- a/doc/guides/rel_notes/release_23_07.rst
+++ b/doc/guides/rel_notes/release_23_07.rst
@@ -55,6 +55,10 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added flow matching of infiniband BTH.**
+
+  Added ``RTE_FLOW_ITEM_TYPE_IB_BTH`` to match infiniband BTH fields.
+
 
 Removed Items
 -------------
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 8f23847859..4bad244029 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -3781,6 +3781,13 @@ This section lists supported pattern items and their attributes, if any.
 
 - ``send_to_kernel``: send packets to kernel.
 
+- ``ib_bth``: match InfiniBand BTH(base transport header).
+
+  - ``opcode {unsigned}``: Opcode.
+  - ``pkey {unsigned}``: Partition key.
+  - ``dst_qp {unsigned}``: Destination Queue Pair.
+  - ``psn {unsigned}``: Packet Sequence Number.
+
 
 Actions list
 ^^^^^^^^^^^^
diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
index 69e6e749f7..6e099deca3 100644
--- a/lib/ethdev/rte_flow.c
+++ b/lib/ethdev/rte_flow.c
@@ -164,6 +164,7 @@ static const struct rte_flow_desc_data rte_flow_desc_item[] = {
 	MK_FLOW_ITEM(IPV6_ROUTING_EXT, sizeof(struct rte_flow_item_ipv6_routing_ext)),
 	MK_FLOW_ITEM(QUOTA, sizeof(struct rte_flow_item_quota)),
 	MK_FLOW_ITEM(AGGR_AFFINITY, sizeof(struct rte_flow_item_aggr_affinity)),
+	MK_FLOW_ITEM(IB_BTH, sizeof(struct rte_flow_item_ib_bth)),
 };
 
 /** Generate flow_action[] entry. */
diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
index 713ba8b65c..2b7f144c27 100644
--- a/lib/ethdev/rte_flow.h
+++ b/lib/ethdev/rte_flow.h
@@ -38,6 +38,7 @@
 #include <rte_ppp.h>
 #include <rte_gre.h>
 #include <rte_macsec.h>
+#include <rte_ib.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -672,6 +673,13 @@ enum rte_flow_item_type {
 	 * @see struct rte_flow_item_aggr_affinity.
 	 */
 	RTE_FLOW_ITEM_TYPE_AGGR_AFFINITY,
+
+	/**
+	 * Matches an InfiniBand base transport header in RoCE packet.
+	 *
+	 * See struct rte_flow_item_ib_bth.
+	 */
+	RTE_FLOW_ITEM_TYPE_IB_BTH,
 };
 
 /**
@@ -2260,6 +2268,25 @@ rte_flow_item_aggr_affinity_mask = {
 };
 #endif
 
+/**
+ * RTE_FLOW_ITEM_TYPE_IB_BTH.
+ *
+ * Matches an InfiniBand base transport header in RoCE packet.
+ */
+struct rte_flow_item_ib_bth {
+	struct rte_ib_bth hdr; /**< InfiniBand base transport header definition. */
+};
+
+/** Default mask for RTE_FLOW_ITEM_TYPE_IB_BTH. */
+#ifndef __cplusplus
+static const struct rte_flow_item_ib_bth rte_flow_item_ib_bth_mask = {
+	.hdr = {
+		.opcode = 0xff,
+		.dst_qp = "\xff\xff\xff",
+	},
+};
+#endif
+
 /**
  * Action types.
  *
diff --git a/lib/net/meson.build b/lib/net/meson.build
index 379d161ee0..b7a0684101 100644
--- a/lib/net/meson.build
+++ b/lib/net/meson.build
@@ -22,6 +22,7 @@ headers = files(
         'rte_geneve.h',
         'rte_l2tpv2.h',
         'rte_ppp.h',
+        'rte_ib.h',
 )
 
 sources = files(
diff --git a/lib/net/rte_ib.h b/lib/net/rte_ib.h
new file mode 100644
index 0000000000..9eab5f9e15
--- /dev/null
+++ b/lib/net/rte_ib.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2023 NVIDIA Corporation & Affiliates
+ */
+
+#ifndef RTE_IB_H
+#define RTE_IB_H
+
+/**
+ * @file
+ *
+ * InfiniBand headers definitions
+ *
+ * The infiniBand headers are used by RoCE (RDMA over Converged Ethernet).
+ */
+
+#include <stdint.h>
+
+#include <rte_byteorder.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * InfiniBand Base Transport Header according to
+ * IB Specification Vol 1-Release-1.4.
+ */
+__extension__
+struct rte_ib_bth {
+	uint8_t	opcode;		/**< Opcode. */
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+	uint8_t	tver:4;		/**< Transport Header Version. */
+	uint8_t	padcnt:2;	/**< Pad Count. */
+	uint8_t	m:1;		/**< MigReq. */
+	uint8_t	se:1;		/**< Solicited Event. */
+#elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+	uint8_t	se:1;		/**< Solicited Event. */
+	uint8_t	m:1;		/**< MigReq. */
+	uint8_t	padcnt:2;	/**< Pad Count. */
+	uint8_t	tver:4;		/**< Transport Header Version. */
+#endif
+	rte_be16_t pkey;	/**< Partition key. */
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+	uint8_t	rsvd0:6;	/**< Reserved. */
+	uint8_t	b:1;		/**< BECN. */
+	uint8_t	f:1;		/**< FECN. */
+#elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+	uint8_t	f:1;		/**< FECN. */
+	uint8_t	b:1;		/**< BECN. */
+	uint8_t	rsvd0:6;	/**< Reserved. */
+#endif
+	uint8_t	dst_qp[3];	/**< Destination QP */
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+	uint8_t	rsvd1:7;	/**< Reserved. */
+	uint8_t	a:1;		/**< Acknowledge Request. */
+#elif RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+	uint8_t	a:1;		/**< Acknowledge Request. */
+	uint8_t	rsvd1:7;	/**< Reserved. */
+#endif
+	uint8_t	psn[3];		/**< Packet Sequence Number */
+} __rte_packed;
+
+/** RoCEv2 default port. */
+#define RTE_ROCEV2_DEFAULT_PORT 4791
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_IB_H */
