[v6,05/15] security: switch metadata to dynamic mbuf field

Message ID 20201030174441.1076264-6-thomas@monjalon.net (mailing list archive)
State Accepted, archived
Delegated to: Thomas Monjalon
Headers
Series remove mbuf userdata |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Thomas Monjalon Oct. 30, 2020, 5:44 p.m. UTC
  The device-specific metadata was stored in the deprecated field udata64.
It is moved to a dynamic mbuf field in order to allow removal of udata64.

The name rte_security_dynfield is not very descriptive
but it should be replaced later by separate fields for each type of data
that drivers pass to the upper layer.

Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
Acked-by: Haiyue Wang <haiyue.wang@intel.com>
---
 doc/guides/prog_guide/rte_security.rst        |  9 ++--
 drivers/crypto/octeontx2/otx2_cryptodev_sec.c |  5 ++-
 drivers/net/ixgbe/ixgbe_ipsec.c               |  5 ++-
 drivers/net/ixgbe/ixgbe_rxtx.c                |  6 ++-
 drivers/net/octeontx2/otx2_ethdev.h           |  1 +
 drivers/net/octeontx2/otx2_ethdev_sec.c       |  5 ++-
 drivers/net/octeontx2/otx2_ethdev_sec_tx.h    |  2 +-
 drivers/net/octeontx2/otx2_rx.h               |  2 +-
 examples/ipsec-secgw/ipsec-secgw.c            |  9 ++--
 examples/ipsec-secgw/ipsec_worker.c           | 12 ++++--
 lib/librte_security/rte_security.c            | 16 +++++++
 lib/librte_security/rte_security.h            | 42 +++++++++++++++++++
 lib/librte_security/rte_security_driver.h     |  3 ++
 lib/librte_security/version.map               |  2 +
 14 files changed, 99 insertions(+), 20 deletions(-)
  

Comments

David Marchand Oct. 31, 2020, 8:56 a.m. UTC | #1
On Fri, Oct 30, 2020 at 6:45 PM Thomas Monjalon <thomas@monjalon.net> wrote:
>
> The device-specific metadata was stored in the deprecated field udata64.
> It is moved to a dynamic mbuf field in order to allow removal of udata64.
>
> The name rte_security_dynfield is not very descriptive
> but it should be replaced later by separate fields for each type of data
> that drivers pass to the upper layer.
>
> Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
> Acked-by: Haiyue Wang <haiyue.wang@intel.com>

We have a regression in the mbuf unit test when running with probed
ixgbe devices (UNH lab).

The problem is that the security dyn field is registered when probing
the ixgbe devices.
The unit test fails later while checking one of its own registered
dynfield offset.

I can reproduce the issue by stopping at this patch in the series and
adding the below diff.
The problem can be seen with the whole series applied, there is only a
difference in reported dynfield offsets.

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index 80d1850da9..0e4f895187 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -33,6 +33,7 @@
 #include <rte_ip.h>
 #include <rte_tcp.h>
 #include <rte_mbuf_dyn.h>
+#include <rte_security_driver.h>

 #include "test.h"

@@ -2589,6 +2590,7 @@ test_mbuf_dyn(struct rte_mempool *pktmbuf_pool)
        int ret;

        printf("Test mbuf dynamic fields and flags\n");
+       rte_security_dynfield_register();
        rte_mbuf_dyn_dump(stdout);

        offset = rte_mbuf_dynfield_register(&dynfield);


Then:

# DPDK_TEST=mbuf_autotest ./build/app/test/dpdk-test
EAL: Detected 8 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: No available hugepages reported in hugepages-1048576kB
EAL: Probing VFIO support...
APP: HPET is not enabled, using TSC as default timer
RTE>>mbuf_autotest
Test mbuf dynamic fields and flags
Reserved fields:
  name=rte_security_dynfield_metadata offset=112 size=8 align=8 flags=0
Reserved flags:
Free space in mbuf (0 = occupied, value = free zone alignment):
  0000: 00 00 00 00 00 00 00 00
  0008: 00 00 00 00 00 00 00 00
  0010: 00 00 00 00 00 00 00 00
  0018: 00 00 00 00 00 00 00 00
  0020: 00 00 00 00 00 00 00 00
  0028: 00 00 00 00 00 00 00 00
  0030: 00 00 00 00 00 00 00 00
  0038: 00 00 00 00 00 00 00 00
  0040: 00 00 00 00 00 00 00 00
  0048: 00 00 00 00 00 00 00 00
  0050: 00 00 00 00 00 00 00 00
  0058: 00 00 00 00 00 00 00 00
  0060: 00 00 00 00 00 00 00 00
  0068: 00 00 00 00 00 00 00 00
  0070: 00 00 00 00 00 00 00 00
  0078: 08 08 08 08 08 08 08 08
Free bit in mbuf->ol_flags (0 = occupied, 1 = free):
  0000: 0 0 0 0 0 0 0 0
  0008: 0 0 0 0 0 0 0 0
  0010: 0 0 0 0 0 0 0 1
  0018: 1 1 1 1 1 1 1 1
  0020: 1 1 1 1 1 1 1 1
  0028: 1 0 0 0 0 0 0 0
  0030: 0 0 0 0 0 0 0 0
  0038: 0 0 0 0 0 0 0 0
mbuf test FAILED (l.2615): <failed to register dynamic field 3,
offset=-1: No such file or directory>
mbuf dynflag test failed
Test Failed

A lazy fix is to simply ask for registering a field at offset
sizeof(dynfield) - 1 .. what do you think?
  
David Marchand Oct. 31, 2020, 9:26 a.m. UTC | #2
On Sat, Oct 31, 2020 at 9:56 AM David Marchand
<david.marchand@redhat.com> wrote:
> A lazy fix is to simply ask for registering a field at offset
> sizeof(dynfield) - 1 .. what do you think?

I meant sizeof(struct rte_mbuf) - 1.
  
Thomas Monjalon Oct. 31, 2020, 2:38 p.m. UTC | #3
31/10/2020 09:56, David Marchand:
> On Fri, Oct 30, 2020 at 6:45 PM Thomas Monjalon <thomas@monjalon.net> wrote:
> >
> > The device-specific metadata was stored in the deprecated field udata64.
> > It is moved to a dynamic mbuf field in order to allow removal of udata64.
> >
> > The name rte_security_dynfield is not very descriptive
> > but it should be replaced later by separate fields for each type of data
> > that drivers pass to the upper layer.
> >
> > Signed-off-by: Thomas Monjalon <thomas@monjalon.net>
> > Acked-by: Haiyue Wang <haiyue.wang@intel.com>
> 
> We have a regression in the mbuf unit test when running with probed
> ixgbe devices (UNH lab).
> 
> The problem is that the security dyn field is registered when probing
> the ixgbe devices.
> The unit test fails later while checking one of its own registered
> dynfield offset.
> 
> I can reproduce the issue by stopping at this patch in the series and
> adding the below diff.
> The problem can be seen with the whole series applied, there is only a
> difference in reported dynfield offsets.
> 
> diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
> index 80d1850da9..0e4f895187 100644
> --- a/app/test/test_mbuf.c
> +++ b/app/test/test_mbuf.c
> @@ -33,6 +33,7 @@
>  #include <rte_ip.h>
>  #include <rte_tcp.h>
>  #include <rte_mbuf_dyn.h>
> +#include <rte_security_driver.h>
> 
>  #include "test.h"
> 
> @@ -2589,6 +2590,7 @@ test_mbuf_dyn(struct rte_mempool *pktmbuf_pool)
>         int ret;
> 
>         printf("Test mbuf dynamic fields and flags\n");
> +       rte_security_dynfield_register();
>         rte_mbuf_dyn_dump(stdout);
> 
>         offset = rte_mbuf_dynfield_register(&dynfield);
> 
> 
> Then:
> 
> # DPDK_TEST=mbuf_autotest ./build/app/test/dpdk-test
> EAL: Detected 8 lcore(s)
> EAL: Detected 1 NUMA nodes
> EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
> EAL: Selected IOVA mode 'PA'
> EAL: No available hugepages reported in hugepages-1048576kB
> EAL: Probing VFIO support...
> APP: HPET is not enabled, using TSC as default timer
> RTE>>mbuf_autotest
> Test mbuf dynamic fields and flags
> Reserved fields:
>   name=rte_security_dynfield_metadata offset=112 size=8 align=8 flags=0
> Reserved flags:
> Free space in mbuf (0 = occupied, value = free zone alignment):
>   0000: 00 00 00 00 00 00 00 00
>   0008: 00 00 00 00 00 00 00 00
>   0010: 00 00 00 00 00 00 00 00
>   0018: 00 00 00 00 00 00 00 00
>   0020: 00 00 00 00 00 00 00 00
>   0028: 00 00 00 00 00 00 00 00
>   0030: 00 00 00 00 00 00 00 00
>   0038: 00 00 00 00 00 00 00 00
>   0040: 00 00 00 00 00 00 00 00
>   0048: 00 00 00 00 00 00 00 00
>   0050: 00 00 00 00 00 00 00 00
>   0058: 00 00 00 00 00 00 00 00
>   0060: 00 00 00 00 00 00 00 00
>   0068: 00 00 00 00 00 00 00 00
>   0070: 00 00 00 00 00 00 00 00
>   0078: 08 08 08 08 08 08 08 08
> Free bit in mbuf->ol_flags (0 = occupied, 1 = free):
>   0000: 0 0 0 0 0 0 0 0
>   0008: 0 0 0 0 0 0 0 0
>   0010: 0 0 0 0 0 0 0 1
>   0018: 1 1 1 1 1 1 1 1
>   0020: 1 1 1 1 1 1 1 1
>   0028: 1 0 0 0 0 0 0 0
>   0030: 0 0 0 0 0 0 0 0
>   0038: 0 0 0 0 0 0 0 0
> mbuf test FAILED (l.2615): <failed to register dynamic field 3,
> offset=-1: No such file or directory>
> mbuf dynflag test failed
> Test Failed
> 
> A lazy fix is to simply ask for registering a field at offset
> sizeof(dynfield) - 1 .. what do you think?

I think any offset could be registered,
so it looks more correct to skip the failure if rte_errno is EBUSY.
I did this fix:
	https://patches.dpdk.org/patch/83175/
  

Patch

diff --git a/doc/guides/prog_guide/rte_security.rst b/doc/guides/prog_guide/rte_security.rst
index c64aef3de9..f72bc8a78f 100644
--- a/doc/guides/prog_guide/rte_security.rst
+++ b/doc/guides/prog_guide/rte_security.rst
@@ -125,8 +125,9 @@  ESP/AH headers will be removed from the packet and the received packet
 will contains the decrypted packet only. The driver Rx path checks the
 descriptors and based on the crypto status sets additional flags in
 ``rte_mbuf.ol_flags`` field. The driver would also set device-specific
-metadata in ``rte_mbuf.udata64`` field. This will allow the application
-to identify the security processing done on the packet.
+metadata in ``RTE_SECURITY_DYNFIELD_NAME`` field.
+This will allow the application to identify the security processing
+done on the packet.
 
 .. note::
 
@@ -568,8 +569,8 @@  security session which processed the packet.
 
 .. note::
 
-    In case of inline processed packets, ``rte_mbuf.udata64`` field would be
-    used by the driver to relay information on the security processing
+    In case of inline processed packets, ``RTE_SECURITY_DYNFIELD_NAME`` field
+    would be used by the driver to relay information on the security processing
     associated with the packet. In ingress, the driver would set this in Rx
     path while in egress, ``rte_security_set_pkt_metadata()`` would perform a
     similar operation. The application is expected not to modify the field
diff --git a/drivers/crypto/octeontx2/otx2_cryptodev_sec.c b/drivers/crypto/octeontx2/otx2_cryptodev_sec.c
index b80ec7bff2..4e2a0e3afe 100644
--- a/drivers/crypto/octeontx2/otx2_cryptodev_sec.c
+++ b/drivers/crypto/octeontx2/otx2_cryptodev_sec.c
@@ -455,6 +455,9 @@  otx2_crypto_sec_session_create(void *device,
 	if (conf->action_type != RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL)
 		return -ENOTSUP;
 
+	if (rte_security_dynfield_register() < 0)
+		return -rte_errno;
+
 	if (rte_mempool_get(mempool, (void **)&priv)) {
 		otx2_err("Could not allocate security session private data");
 		return -ENOMEM;
@@ -514,7 +517,7 @@  otx2_crypto_sec_set_pkt_mdata(void *device __rte_unused,
 			      struct rte_mbuf *m, void *params __rte_unused)
 {
 	/* Set security session as the pkt metadata */
-	m->udata64 = (uint64_t)session;
+	*rte_security_dynfield(m) = (rte_security_dynfield_t)session;
 
 	return 0;
 }
diff --git a/drivers/net/ixgbe/ixgbe_ipsec.c b/drivers/net/ixgbe/ixgbe_ipsec.c
index 48f5082d49..62f2a5f764 100644
--- a/drivers/net/ixgbe/ixgbe_ipsec.c
+++ b/drivers/net/ixgbe/ixgbe_ipsec.c
@@ -484,7 +484,8 @@  ixgbe_crypto_update_mb(void *device __rte_unused,
 			get_sec_session_private_data(session);
 	if (ic_session->op == IXGBE_OP_AUTHENTICATED_ENCRYPTION) {
 		union ixgbe_crypto_tx_desc_md *mdata =
-			(union ixgbe_crypto_tx_desc_md *)&m->udata64;
+			(union ixgbe_crypto_tx_desc_md *)
+				rte_security_dynfield(m);
 		mdata->enc = 1;
 		mdata->sa_idx = ic_session->sa_index;
 		mdata->pad_len = ixgbe_crypto_compute_pad_len(m);
@@ -751,5 +752,7 @@  ixgbe_ipsec_ctx_create(struct rte_eth_dev *dev)
 			return -ENOMEM;
 		}
 	}
+	if (rte_security_dynfield_register() < 0)
+		return -rte_errno;
 	return 0;
 }
diff --git a/drivers/net/ixgbe/ixgbe_rxtx.c b/drivers/net/ixgbe/ixgbe_rxtx.c
index 5f19972031..6cfbb582e2 100644
--- a/drivers/net/ixgbe/ixgbe_rxtx.c
+++ b/drivers/net/ixgbe/ixgbe_rxtx.c
@@ -34,6 +34,7 @@ 
 #include <rte_mbuf.h>
 #include <rte_ether.h>
 #include <rte_ethdev_driver.h>
+#include <rte_security_driver.h>
 #include <rte_prefetch.h>
 #include <rte_udp.h>
 #include <rte_tcp.h>
@@ -694,7 +695,7 @@  ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 			if (use_ipsec) {
 				union ixgbe_crypto_tx_desc_md *ipsec_mdata =
 					(union ixgbe_crypto_tx_desc_md *)
-							&tx_pkt->udata64;
+						rte_security_dynfield(tx_pkt);
 				tx_offload.sa_idx = ipsec_mdata->sa_idx;
 				tx_offload.sec_pad_len = ipsec_mdata->pad_len;
 			}
@@ -859,7 +860,8 @@  ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 				}
 
 				ixgbe_set_xmit_ctx(txq, ctx_txd, tx_ol_req,
-					tx_offload, &tx_pkt->udata64);
+					tx_offload,
+					rte_security_dynfield(tx_pkt));
 
 				txe->last_id = tx_last;
 				tx_id = txe->next_id;
diff --git a/drivers/net/octeontx2/otx2_ethdev.h b/drivers/net/octeontx2/otx2_ethdev.h
index b20f399a15..3b9871f4dc 100644
--- a/drivers/net/octeontx2/otx2_ethdev.h
+++ b/drivers/net/octeontx2/otx2_ethdev.h
@@ -13,6 +13,7 @@ 
 #include <rte_kvargs.h>
 #include <rte_mbuf.h>
 #include <rte_mempool.h>
+#include <rte_security_driver.h>
 #include <rte_string_fns.h>
 #include <rte_time.h>
 
diff --git a/drivers/net/octeontx2/otx2_ethdev_sec.c b/drivers/net/octeontx2/otx2_ethdev_sec.c
index 4e0dd4e49e..1ee597ff6e 100644
--- a/drivers/net/octeontx2/otx2_ethdev_sec.c
+++ b/drivers/net/octeontx2/otx2_ethdev_sec.c
@@ -684,7 +684,7 @@  otx2_eth_sec_set_pkt_mdata(void *device __rte_unused,
 			    struct rte_mbuf *m, void *params __rte_unused)
 {
 	/* Set security session as the pkt metadata */
-	m->udata64 = (uint64_t)session;
+	*rte_security_dynfield(m) = (rte_security_dynfield_t)session;
 
 	return 0;
 }
@@ -831,6 +831,9 @@  otx2_eth_sec_init(struct rte_eth_dev *eth_dev)
 	    !(dev->rx_offloads & DEV_RX_OFFLOAD_SECURITY))
 		return 0;
 
+	if (rte_security_dynfield_register() < 0)
+		return -rte_errno;
+
 	nb_sa = dev->ipsec_in_max_spi;
 	mz_sz = nb_sa * sa_width;
 	in_sa_mz_name_get(name, RTE_MEMZONE_NAMESIZE, port);
diff --git a/drivers/net/octeontx2/otx2_ethdev_sec_tx.h b/drivers/net/octeontx2/otx2_ethdev_sec_tx.h
index 5bf8c19995..284bcd5367 100644
--- a/drivers/net/octeontx2/otx2_ethdev_sec_tx.h
+++ b/drivers/net/octeontx2/otx2_ethdev_sec_tx.h
@@ -55,7 +55,7 @@  otx2_sec_event_tx(struct otx2_ssogws *ws, struct rte_event *ev,
 		struct nix_iova_s nix_iova;
 	} *sd;
 
-	priv = get_sec_session_private_data((void *)(m->udata64));
+	priv = get_sec_session_private_data((void *)(*rte_security_dynfield(m)));
 	sess = &priv->ipsec.ip;
 	sa = &sess->out_sa;
 
diff --git a/drivers/net/octeontx2/otx2_rx.h b/drivers/net/octeontx2/otx2_rx.h
index f29a0542f9..61a5c436dd 100644
--- a/drivers/net/octeontx2/otx2_rx.h
+++ b/drivers/net/octeontx2/otx2_rx.h
@@ -241,7 +241,7 @@  nix_rx_sec_mbuf_update(const struct nix_cqe_hdr_s *cq, struct rte_mbuf *m,
 	spi = cq->tag & 0xFFFFF;
 
 	sa = nix_rx_sec_sa_get(lookup_mem, spi, m->port);
-	m->udata64 = (uint64_t)sa->userdata;
+	*rte_security_dynfield(m) = sa->udata64;
 
 	data = rte_pktmbuf_mtod(m, char *);
 
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 2219148285..bbe7ce48d9 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -426,7 +426,8 @@  prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
 	 * with the security session.
 	 */
 
-	if (pkt->ol_flags & PKT_RX_SEC_OFFLOAD) {
+	if (pkt->ol_flags & PKT_RX_SEC_OFFLOAD &&
+			rte_security_dynfield_is_registered()) {
 		struct ipsec_sa *sa;
 		struct ipsec_mbuf_metadata *priv;
 		struct rte_security_ctx *ctx = (struct rte_security_ctx *)
@@ -436,10 +437,8 @@  prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
 		/* Retrieve the userdata registered. Here, the userdata
 		 * registered is the SA pointer.
 		 */
-
-		sa = (struct ipsec_sa *)
-				rte_security_get_userdata(ctx, pkt->udata64);
-
+		sa = (struct ipsec_sa *)rte_security_get_userdata(ctx,
+				*rte_security_dynfield(pkt));
 		if (sa == NULL) {
 			/* userdata could not be retrieved */
 			return;
diff --git a/examples/ipsec-secgw/ipsec_worker.c b/examples/ipsec-secgw/ipsec_worker.c
index b6c851f257..647e22df59 100644
--- a/examples/ipsec-secgw/ipsec_worker.c
+++ b/examples/ipsec-secgw/ipsec_worker.c
@@ -208,7 +208,7 @@  process_ipsec_ev_inbound(struct ipsec_ctx *ctx, struct route_table *rt,
 					"Inbound security offload failed\n");
 				goto drop_pkt_and_exit;
 			}
-			sa = pkt->userdata;
+			sa = *(struct ipsec_sa **)rte_security_dynfield(pkt);
 		}
 
 		/* Check if we have a match */
@@ -226,7 +226,7 @@  process_ipsec_ev_inbound(struct ipsec_ctx *ctx, struct route_table *rt,
 					"Inbound security offload failed\n");
 				goto drop_pkt_and_exit;
 			}
-			sa = pkt->userdata;
+			sa = *(struct ipsec_sa **)rte_security_dynfield(pkt);
 		}
 
 		/* Check if we have a match */
@@ -357,7 +357,8 @@  process_ipsec_ev_outbound(struct ipsec_ctx *ctx, struct route_table *rt,
 	}
 
 	if (sess->security.ol_flags & RTE_SECURITY_TX_OLOAD_NEED_MDATA)
-		pkt->userdata = sess->security.ses;
+		*(struct rte_security_session **)rte_security_dynfield(pkt) =
+				sess->security.ses;
 
 	/* Mark the packet for Tx security offload */
 	pkt->ol_flags |= PKT_TX_SEC_OFFLOAD;
@@ -465,7 +466,10 @@  ipsec_wrkr_non_burst_int_port_drv_mode(struct eh_event_link_info *links,
 			}
 
 			/* Save security session */
-			pkt->userdata = sess_tbl[port_id];
+			if (rte_security_dynfield_is_registered())
+				*(struct rte_security_session **)
+					rte_security_dynfield(pkt) =
+						sess_tbl[port_id];
 
 			/* Mark the packet for Tx security offload */
 			pkt->ol_flags |= PKT_TX_SEC_OFFLOAD;
diff --git a/lib/librte_security/rte_security.c b/lib/librte_security/rte_security.c
index ee4666026a..e8116d5447 100644
--- a/lib/librte_security/rte_security.c
+++ b/lib/librte_security/rte_security.c
@@ -23,6 +23,22 @@ 
 	RTE_PTR_OR_ERR_RET(p1->p2->p3, last_retval);			\
 } while (0)
 
+#define RTE_SECURITY_DYNFIELD_NAME "rte_security_dynfield_metadata"
+int rte_security_dynfield_offset = -1;
+
+int
+rte_security_dynfield_register(void)
+{
+	static const struct rte_mbuf_dynfield dynfield_desc = {
+		.name = RTE_SECURITY_DYNFIELD_NAME,
+		.size = sizeof(rte_security_dynfield_t),
+		.align = __alignof__(rte_security_dynfield_t),
+	};
+	rte_security_dynfield_offset =
+		rte_mbuf_dynfield_register(&dynfield_desc);
+	return rte_security_dynfield_offset;
+}
+
 struct rte_security_session *
 rte_security_session_create(struct rte_security_ctx *instance,
 			    struct rte_security_session_conf *conf,
diff --git a/lib/librte_security/rte_security.h b/lib/librte_security/rte_security.h
index 271531af12..88d31de0a6 100644
--- a/lib/librte_security/rte_security.h
+++ b/lib/librte_security/rte_security.h
@@ -27,6 +27,7 @@  extern "C" {
 #include <rte_common.h>
 #include <rte_crypto.h>
 #include <rte_mbuf.h>
+#include <rte_mbuf_dyn.h>
 #include <rte_memory.h>
 #include <rte_mempool.h>
 
@@ -451,6 +452,47 @@  int
 rte_security_session_destroy(struct rte_security_ctx *instance,
 			     struct rte_security_session *sess);
 
+/** Device-specific metadata field type */
+typedef uint64_t rte_security_dynfield_t;
+/** Dynamic mbuf field for device-specific metadata */
+extern int rte_security_dynfield_offset;
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Get pointer to mbuf field for device-specific metadata.
+ *
+ * For performance reason, no check is done,
+ * the dynamic field may not be registered.
+ * @see rte_security_dynfield_is_registered
+ *
+ * @param	mbuf	packet to access
+ * @return pointer to mbuf field
+ */
+__rte_experimental
+static inline rte_security_dynfield_t *
+rte_security_dynfield(struct rte_mbuf *mbuf)
+{
+	return RTE_MBUF_DYNFIELD(mbuf,
+		rte_security_dynfield_offset,
+		rte_security_dynfield_t *);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Check whether the dynamic field is registered.
+ *
+ * @return true if rte_security_dynfield_register() has been called.
+ */
+__rte_experimental
+static inline bool rte_security_dynfield_is_registered(void)
+{
+	return rte_security_dynfield_offset >= 0;
+}
+
 /**
  *  Updates the buffer with device-specific defined metadata
  *
diff --git a/lib/librte_security/rte_security_driver.h b/lib/librte_security/rte_security_driver.h
index 1b561f8528..c5abb07990 100644
--- a/lib/librte_security/rte_security_driver.h
+++ b/lib/librte_security/rte_security_driver.h
@@ -89,6 +89,9 @@  typedef int (*security_session_stats_get_t)(void *device,
 		struct rte_security_session *sess,
 		struct rte_security_stats *stats);
 
+__rte_experimental
+int rte_security_dynfield_register(void);
+
 /**
  * Update the mbuf with provided metadata.
  *
diff --git a/lib/librte_security/version.map b/lib/librte_security/version.map
index d84eec0a88..22775558c8 100644
--- a/lib/librte_security/version.map
+++ b/lib/librte_security/version.map
@@ -15,6 +15,8 @@  DPDK_21 {
 EXPERIMENTAL {
 	global:
 
+	rte_security_dynfield_offset;
+	rte_security_dynfield_register;
 	rte_security_get_userdata;
 	rte_security_session_stats_get;
 	rte_security_session_update;