[v2,4/4] regexdev: implement regex rte level functions

Message ID 1587127417-82492-5-git-send-email-orika@mellanox.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers
Series add RegEx class |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/Intel-compilation success Compilation OK

Commit Message

Ori Kam April 17, 2020, 12:43 p.m. UTC
  This commit implements all the RegEx public API.

Signed-off-by: Ori Kam <orika@mellanox.com>
---
v2:
* Changes based on changes in previous patch.
* Add check to configuration function.
* Replace checks with macros.
* Move enqueue and dequeue to inline.
---
 config/common_base                      |   1 +
 lib/librte_regexdev/rte_regexdev.c      | 442 +++++++++++++++++++++++++++++++-
 lib/librte_regexdev/rte_regexdev.h      |  68 ++++-
 lib/librte_regexdev/rte_regexdev_core.h |   9 +
 4 files changed, 506 insertions(+), 14 deletions(-)
  

Comments

Guy Kaneti April 21, 2020, 11:12 a.m. UTC | #1
Hi,

> +int
> +rte_regexdev_is_valid_dev(uint16_t dev_id) {
> +	if (dev_id >= RTE_MAX_REGEXDEV_DEVS ||
> +	    rte_regex_devices[dev_id].state != RTE_REGEXDEV_READY)
> +		return 0;
> +	return 1;
> +}

When is the state changed to RTE_REGEXDEV_READY?
Should the PMD change it at the end of probing?
  
Ori Kam April 21, 2020, 11:20 a.m. UTC | #2
> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Guy Kaneti
> Sent: Tuesday, April 21, 2020 2:12 PM
> To: Ori Kam <orika@mellanox.com>; Jerin Jacob Kollanukkaran
> <jerinj@marvell.com>; xiang.w.wang@intel.com
> Cc: dev@dpdk.org; Pavan Nikhilesh Bhagavatula
> <pbhagavatula@marvell.com>; Shahaf Shuler <shahafs@mellanox.com>;
> hemant.agrawal@nxp.com; Opher Reviv <opher@mellanox.com>; Alex
> Rosenbaum <alexr@mellanox.com>; Dovrat Zifroni <dovrat@marvell.com>;
> Prasun Kapoor <pkapoor@marvell.com>; nipun.gupta@nxp.com;
> bruce.richardson@intel.com; yang.a.hong@intel.com; harry.chang@intel.com;
> gu.jian1@zte.com.cn; shanjiangh@chinatelecom.cn;
> zhangy.yun@chinatelecom.cn; lixingfu@huachentel.com; wushuai@inspur.com;
> yuyingxia@yxlink.com; fanchenggang@sunyainfo.com;
> davidfgao@tencent.com; liuzhong1@chinaunicom.cn;
> zhaoyong11@huawei.com; oc@yunify.com; jim@netgate.com;
> hongjun.ni@intel.com; j.bromhead@titan-ic.com; deri@ntop.org;
> fc@napatech.com; arthur.su@lionic.com; Thomas Monjalon
> <thomas@monjalon.net>
> Subject: Re: [dpdk-dev] [PATCH v2 4/4] regexdev: implement regex rte level
> functions
> 
> Hi,
> 
> > +int
> > +rte_regexdev_is_valid_dev(uint16_t dev_id) {
> > +	if (dev_id >= RTE_MAX_REGEXDEV_DEVS ||
> > +	    rte_regex_devices[dev_id].state != RTE_REGEXDEV_READY)
> > +		return 0;
> > +	return 1;
> > +}
> 
> When is the state changed to RTE_REGEXDEV_READY?
> Should the PMD change it at the end of probing?

Yes, 

Best,
Ori
  
Guy Kaneti April 21, 2020, 11:36 a.m. UTC | #3
Hi,

> +int
> +rte_regexdev_configure(uint8_t dev_id, const struct rte_regexdev_config
> +*cfg) {
> +	struct rte_regexdev *dev;
> +	struct rte_regexdev_info dev_info;
> +	int ret;
> +
> +	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
> +	if (cfg == NULL)
> +		return -EINVAL;
> +	dev = &rte_regex_devices[dev_id];
> +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -
> ENOTSUP);
> +	if (dev->data->dev_started) {
> +		RTE_REGEXDEV_LOG
> +			(ERR, "Dev %u must be stopped to allow
> configuration\n",
> +			 dev_id);
> +		return -EBUSY;
> +	}
> +	ret = regexdev_info_get(dev_id, &dev_info);
> +	if (ret < 0)
> +		return ret;
> +	if ((cfg->dev_cfg_flags &
> RTE_REGEXDEV_CFG_CROSS_BUFFER_SCAN_F) &&
> +	    !(dev_info.regexdev_capa &
> RTE_REGEXDEV_SUPP_CROSS_BUFFER_F)) {
> +		RTE_REGEXDEV_LOG(ERR,
> +				 "Dev %u doesn't support cross buffer
> scan\n",
> +				 dev_id);
> +		return -EINVAL;
> +	}
> +	if ((cfg->dev_cfg_flags & RTE_REGEXDEV_CFG_MATCH_AS_END_F)
> &&
> +	    !(dev_info.regexdev_capa &
> RTE_REGEXDEV_SUPP_MATCH_AS_END_F)) {
> +		RTE_REGEXDEV_LOG(ERR,
> +				 "Dev %u doesn't support match as end\n",
> +				 dev_id);
> +		return -EINVAL;
> +	}
> +	if ((cfg->dev_cfg_flags & RTE_REGEXDEV_CFG_MATCH_ALL_F) &&
> +	    !(dev_info.regexdev_capa &
> RTE_REGEXDEV_SUPP_MATCH_ALL_F)) {
> +		RTE_REGEXDEV_LOG(ERR,
> +				 "Dev %u doesn't support match all\n",
> +				 dev_id);
> +		return -EINVAL;
> +	}
> +	if (cfg->nb_groups == 0) {
> +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of groups must be >
> 0\n",
> +				 dev_id);
> +		return -EINVAL;
> +	}
> +	if (cfg->nb_groups >= dev_info.max_groups) {
> +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of groups %d >
> %d\n",
> +				 dev_id, cfg->nb_groups,
> dev_info.max_groups);
> +		return -EINVAL;
> +	}

The comparison should be > and not >=

> +	if (cfg->nb_max_matches == 0) {
> +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of matches must be
> > 0\n",
> +				 dev_id);
> +		return -EINVAL;
> +	}
> +	if (cfg->nb_max_matches >= dev_info.max_matches) {
> +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of matches %d >
> %d\n",
> +				 dev_id, cfg->nb_max_matches,
> +				 dev_info.max_matches);
> +		return -EINVAL;
> +	}

The comparison should be > and not >=

> +	if (cfg->nb_queue_pairs == 0) {
> +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of queues must be
> > 0\n",
> +				 dev_id);
> +		return -EINVAL;
> +	}
> +	if (cfg->nb_queue_pairs >= dev_info.max_queue_pairs) {
> +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of queues %d >
> %d\n",
> +				 dev_id, cfg->nb_queue_pairs,
> +				 dev_info.max_queue_pairs);
> +		return -EINVAL;
> +	}

The comparison should be > and not >=

> +	if (cfg->nb_rules_per_group == 0) {
> +		RTE_REGEXDEV_LOG(ERR,
> +				 "Dev %u num of rules per group must be >
> 0\n",
> +				 dev_id);
> +		return -EINVAL;
> +	}
> +	if (cfg->nb_rules_per_group >= dev_info.max_rules_per_group) {
> +		RTE_REGEXDEV_LOG(ERR,
> +				 "Dev %u num of rules per group %d > %d\n",
> +				 dev_id, cfg->nb_rules_per_group,
> +				 dev_info.max_rules_per_group);
> +		return -EINVAL;
> +	}

The comparison should be > and not >=

> +	ret = (*dev->dev_ops->dev_configure)(dev, cfg);
> +	if (ret == 0)
> +		dev->data->dev_conf = *cfg;
> +	return ret;
> +}

In general I think that the validation of the cfg values should be done by the PMD
  
Ori Kam April 22, 2020, 8:33 p.m. UTC | #4
Hi Guy,

> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Guy Kaneti
> Sent: Tuesday, April 21, 2020 2:36 PM
> To: Ori Kam <orika@mellanox.com>; Jerin Jacob Kollanukkaran
> <jerinj@marvell.com>; xiang.w.wang@intel.com
> Cc: dev@dpdk.org; Pavan Nikhilesh Bhagavatula
> <pbhagavatula@marvell.com>; Shahaf Shuler <shahafs@mellanox.com>;
> hemant.agrawal@nxp.com; Opher Reviv <opher@mellanox.com>; Alex
> Rosenbaum <alexr@mellanox.com>; Dovrat Zifroni <dovrat@marvell.com>;
> Prasun Kapoor <pkapoor@marvell.com>; nipun.gupta@nxp.com;
> bruce.richardson@intel.com; yang.a.hong@intel.com; harry.chang@intel.com;
> gu.jian1@zte.com.cn; shanjiangh@chinatelecom.cn;
> zhangy.yun@chinatelecom.cn; lixingfu@huachentel.com; wushuai@inspur.com;
> yuyingxia@yxlink.com; fanchenggang@sunyainfo.com;
> davidfgao@tencent.com; liuzhong1@chinaunicom.cn;
> zhaoyong11@huawei.com; oc@yunify.com; jim@netgate.com;
> hongjun.ni@intel.com; j.bromhead@titan-ic.com; deri@ntop.org;
> fc@napatech.com; arthur.su@lionic.com; Thomas Monjalon
> <thomas@monjalon.net>
> Subject: Re: [dpdk-dev] [PATCH v2 4/4] regexdev: implement regex rte level
> functions
> 
> Hi,
> 
> > +int
> > +rte_regexdev_configure(uint8_t dev_id, const struct rte_regexdev_config
> > +*cfg) {
> > +	struct rte_regexdev *dev;
> > +	struct rte_regexdev_info dev_info;
> > +	int ret;
> > +
> > +	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
> > +	if (cfg == NULL)
> > +		return -EINVAL;
> > +	dev = &rte_regex_devices[dev_id];
> > +	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -
> > ENOTSUP);
> > +	if (dev->data->dev_started) {
> > +		RTE_REGEXDEV_LOG
> > +			(ERR, "Dev %u must be stopped to allow
> > configuration\n",
> > +			 dev_id);
> > +		return -EBUSY;
> > +	}
> > +	ret = regexdev_info_get(dev_id, &dev_info);
> > +	if (ret < 0)
> > +		return ret;
> > +	if ((cfg->dev_cfg_flags &
> > RTE_REGEXDEV_CFG_CROSS_BUFFER_SCAN_F) &&
> > +	    !(dev_info.regexdev_capa &
> > RTE_REGEXDEV_SUPP_CROSS_BUFFER_F)) {
> > +		RTE_REGEXDEV_LOG(ERR,
> > +				 "Dev %u doesn't support cross buffer
> > scan\n",
> > +				 dev_id);
> > +		return -EINVAL;
> > +	}
> > +	if ((cfg->dev_cfg_flags & RTE_REGEXDEV_CFG_MATCH_AS_END_F)
> > &&
> > +	    !(dev_info.regexdev_capa &
> > RTE_REGEXDEV_SUPP_MATCH_AS_END_F)) {
> > +		RTE_REGEXDEV_LOG(ERR,
> > +				 "Dev %u doesn't support match as end\n",
> > +				 dev_id);
> > +		return -EINVAL;
> > +	}
> > +	if ((cfg->dev_cfg_flags & RTE_REGEXDEV_CFG_MATCH_ALL_F) &&
> > +	    !(dev_info.regexdev_capa &
> > RTE_REGEXDEV_SUPP_MATCH_ALL_F)) {
> > +		RTE_REGEXDEV_LOG(ERR,
> > +				 "Dev %u doesn't support match all\n",
> > +				 dev_id);
> > +		return -EINVAL;
> > +	}
> > +	if (cfg->nb_groups == 0) {
> > +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of groups must be >
> > 0\n",
> > +				 dev_id);
> > +		return -EINVAL;
> > +	}
> > +	if (cfg->nb_groups >= dev_info.max_groups) {
> > +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of groups %d >
> > %d\n",
> > +				 dev_id, cfg->nb_groups,
> > dev_info.max_groups);
> > +		return -EINVAL;
> > +	}
> 
> The comparison should be > and not >=
> 

Yes, you are correct will fix.

> > +	if (cfg->nb_max_matches == 0) {
> > +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of matches must be
> > > 0\n",
> > +				 dev_id);
> > +		return -EINVAL;
> > +	}
> > +	if (cfg->nb_max_matches >= dev_info.max_matches) {
> > +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of matches %d >
> > %d\n",
> > +				 dev_id, cfg->nb_max_matches,
> > +				 dev_info.max_matches);
> > +		return -EINVAL;
> > +	}
> 
> The comparison should be > and not >=
> 

Yes, will fix.

> > +	if (cfg->nb_queue_pairs == 0) {
> > +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of queues must be
> > > 0\n",
> > +				 dev_id);
> > +		return -EINVAL;
> > +	}
> > +	if (cfg->nb_queue_pairs >= dev_info.max_queue_pairs) {
> > +		RTE_REGEXDEV_LOG(ERR, "Dev %u num of queues %d >
> > %d\n",
> > +				 dev_id, cfg->nb_queue_pairs,
> > +				 dev_info.max_queue_pairs);
> > +		return -EINVAL;
> > +	}
> 
> The comparison should be > and not >=
> 

Will fix.

> > +	if (cfg->nb_rules_per_group == 0) {
> > +		RTE_REGEXDEV_LOG(ERR,
> > +				 "Dev %u num of rules per group must be >
> > 0\n",
> > +				 dev_id);
> > +		return -EINVAL;
> > +	}
> > +	if (cfg->nb_rules_per_group >= dev_info.max_rules_per_group) {
> > +		RTE_REGEXDEV_LOG(ERR,
> > +				 "Dev %u num of rules per group %d > %d\n",
> > +				 dev_id, cfg->nb_rules_per_group,
> > +				 dev_info.max_rules_per_group);
> > +		return -EINVAL;
> > +	}
> 
> The comparison should be > and not >=
> 

Will fix.

> > +	ret = (*dev->dev_ops->dev_configure)(dev, cfg);
> > +	if (ret == 0)
> > +		dev->data->dev_conf = *cfg;
> > +	return ret;
> > +}
> 
> In general I think that the validation of the cfg values should be done by the
> PMD

This was done in the first version.
after comments from the community, I changed it.
As much as I like the idea that PMD should handle everything by itself.
there is no point of code duplication, all PMD will require to do those test,
and there is no advantage of doing it inside the PMD.
Also it is common practice in DPDK to assume that the input was tested in the above 
layer. (you can see ethdev)
  

Patch

diff --git a/config/common_base b/config/common_base
index 005cb11..b4ab3a4 100644
--- a/config/common_base
+++ b/config/common_base
@@ -829,6 +829,7 @@  CONFIG_RTE_LIBRTE_PMD_NTB_RAWDEV=y
 # Compile RexEx device support
 #
 CONFIG_RTE_LIBRTE_REGEXDEV=y
+CONFIG_RTE_LIBRTE_REGEXDEV_DEBUG=n
 CONFIG_RTE_MAX_REGEXDEV_DEVS=32
 
 #
diff --git a/lib/librte_regexdev/rte_regexdev.c b/lib/librte_regexdev/rte_regexdev.c
index 10adc54..d469094 100644
--- a/lib/librte_regexdev/rte_regexdev.c
+++ b/lib/librte_regexdev/rte_regexdev.c
@@ -15,7 +15,7 @@ 
 #include "rte_regexdev_driver.h"
 
 static const char *MZ_RTE_REGEXDEV_DATA = "rte_regexdev_data";
-static struct rte_regexdev regex_devices[RTE_MAX_REGEXDEV_DEVS];
+struct rte_regexdev rte_regex_devices[RTE_MAX_REGEXDEV_DEVS];
 /* Shared memory between primary and secondary processes. */
 static struct {
 	struct rte_regexdev_data data[RTE_MAX_REGEXDEV_DEVS];
@@ -29,7 +29,7 @@ 
 	uint16_t i;
 
 	for (i = 0; i < RTE_MAX_REGEXDEV_DEVS; i++) {
-		if (regex_devices[i].state == RTE_REGEXDEV_UNUSED)
+		if (rte_regex_devices[i].state == RTE_REGEXDEV_UNUSED)
 			return i;
 	}
 	return RTE_MAX_REGEXDEV_DEVS;
@@ -41,9 +41,9 @@ 
 	uint16_t i;
 
 	for (i = 0; i < RTE_MAX_REGEXDEV_DEVS; i++) {
-		if (regex_devices[i].state != RTE_REGEXDEV_UNUSED)
-			if (!strcmp(name, regex_devices[i].data->dev_name))
-				return &regex_devices[i];
+		if (rte_regex_devices[i].state != RTE_REGEXDEV_UNUSED)
+			if (!strcmp(name, rte_regex_devices[i].data->dev_name))
+				return &rte_regex_devices[i];
 	}
 	return NULL;
 }
@@ -101,7 +101,7 @@  struct rte_regexdev *
 		return NULL;
 	}
 
-	dev = &regex_devices[dev_id];
+	dev = &rte_regex_devices[dev_id];
 	dev->state = RTE_REGEXDEV_REGISTERED;
 	if (dev->data == NULL)
 		dev->data = &rte_regexdev_shared_data->data[dev_id];
@@ -117,3 +117,433 @@  struct rte_regexdev *
 {
 	dev->state = RTE_REGEXDEV_UNUSED;
 }
+
+uint8_t
+rte_regexdev_count(void)
+{
+	int i;
+	int count = 0;
+
+	for (i = 0; i < RTE_MAX_REGEXDEV_DEVS; i++) {
+		if (rte_regex_devices[i].state != RTE_REGEXDEV_UNUSED)
+			count++;
+	}
+	return count;
+}
+
+int
+rte_regexdev_get_dev_id(const char *name)
+{
+	int i;
+	int id = -EINVAL;
+
+	if (name == NULL)
+		return -EINVAL;
+	for (i = 0; i < RTE_MAX_REGEXDEV_DEVS; i++) {
+		if (rte_regex_devices[i].state != RTE_REGEXDEV_UNUSED)
+			if (strcmp(name, rte_regex_devices[i].data->dev_name)) {
+				id = rte_regex_devices[i].data->dev_id;
+				break;
+			}
+	}
+	return id;
+}
+
+int
+rte_regexdev_is_valid_dev(uint16_t dev_id)
+{
+	if (dev_id >= RTE_MAX_REGEXDEV_DEVS ||
+	    rte_regex_devices[dev_id].state != RTE_REGEXDEV_READY)
+		return 0;
+	return 1;
+}
+
+static int
+regexdev_info_get(uint8_t dev_id, struct rte_regexdev_info *dev_info)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	if (dev_info == NULL)
+		return -EINVAL;
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_info_get, -ENOTSUP);
+	return (*dev->dev_ops->dev_info_get)(dev, dev_info);
+
+}
+
+int
+rte_regexdev_info_get(uint8_t dev_id, struct rte_regexdev_info *dev_info)
+{
+	return regexdev_info_get(dev_id, dev_info);
+}
+
+int
+rte_regexdev_configure(uint8_t dev_id, const struct rte_regexdev_config *cfg)
+{
+	struct rte_regexdev *dev;
+	struct rte_regexdev_info dev_info;
+	int ret;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	if (cfg == NULL)
+		return -EINVAL;
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -ENOTSUP);
+	if (dev->data->dev_started) {
+		RTE_REGEXDEV_LOG
+			(ERR, "Dev %u must be stopped to allow configuration\n",
+			 dev_id);
+		return -EBUSY;
+	}
+	ret = regexdev_info_get(dev_id, &dev_info);
+	if (ret < 0)
+		return ret;
+	if ((cfg->dev_cfg_flags & RTE_REGEXDEV_CFG_CROSS_BUFFER_SCAN_F) &&
+	    !(dev_info.regexdev_capa & RTE_REGEXDEV_SUPP_CROSS_BUFFER_F)) {
+		RTE_REGEXDEV_LOG(ERR,
+				 "Dev %u doesn't support cross buffer scan\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	if ((cfg->dev_cfg_flags & RTE_REGEXDEV_CFG_MATCH_AS_END_F) &&
+	    !(dev_info.regexdev_capa & RTE_REGEXDEV_SUPP_MATCH_AS_END_F)) {
+		RTE_REGEXDEV_LOG(ERR,
+				 "Dev %u doesn't support match as end\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	if ((cfg->dev_cfg_flags & RTE_REGEXDEV_CFG_MATCH_ALL_F) &&
+	    !(dev_info.regexdev_capa & RTE_REGEXDEV_SUPP_MATCH_ALL_F)) {
+		RTE_REGEXDEV_LOG(ERR,
+				 "Dev %u doesn't support match all\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	if (cfg->nb_groups == 0) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %u num of groups must be > 0\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	if (cfg->nb_groups >= dev_info.max_groups) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %u num of groups %d > %d\n",
+				 dev_id, cfg->nb_groups, dev_info.max_groups);
+		return -EINVAL;
+	}
+	if (cfg->nb_max_matches == 0) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %u num of matches must be > 0\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	if (cfg->nb_max_matches >= dev_info.max_matches) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %u num of matches %d > %d\n",
+				 dev_id, cfg->nb_max_matches,
+				 dev_info.max_matches);
+		return -EINVAL;
+	}
+	if (cfg->nb_queue_pairs == 0) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %u num of queues must be > 0\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	if (cfg->nb_queue_pairs >= dev_info.max_queue_pairs) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %u num of queues %d > %d\n",
+				 dev_id, cfg->nb_queue_pairs,
+				 dev_info.max_queue_pairs);
+		return -EINVAL;
+	}
+	if (cfg->nb_rules_per_group == 0) {
+		RTE_REGEXDEV_LOG(ERR,
+				 "Dev %u num of rules per group must be > 0\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	if (cfg->nb_rules_per_group >= dev_info.max_rules_per_group) {
+		RTE_REGEXDEV_LOG(ERR,
+				 "Dev %u num of rules per group %d > %d\n",
+				 dev_id, cfg->nb_rules_per_group,
+				 dev_info.max_rules_per_group);
+		return -EINVAL;
+	}
+	ret = (*dev->dev_ops->dev_configure)(dev, cfg);
+	if (ret == 0)
+		dev->data->dev_conf = *cfg;
+	return ret;
+}
+
+int
+rte_regexdev_queue_pair_setup(uint8_t dev_id, uint16_t queue_pair_id,
+			   const struct rte_regexdev_qp_conf *qp_conf)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_qp_setup, -ENOTSUP);
+	if (dev->data->dev_started) {
+		RTE_REGEXDEV_LOG
+			(ERR, "Dev %u must be stopped to allow configuration\n",
+			 dev_id);
+		return -EBUSY;
+	}
+	if (queue_pair_id >= dev->data->dev_conf.nb_queue_pairs) {
+		RTE_REGEXDEV_LOG(ERR,
+				 "Dev %u invalid queue %d > %d\n",
+				 dev_id, queue_pair_id,
+				 dev->data->dev_conf.nb_queue_pairs);
+		return -EINVAL;
+	}
+	if (dev->data->dev_started) {
+		RTE_REGEXDEV_LOG
+			(ERR, "Dev %u must be stopped to allow configuration\n",
+			 dev_id);
+		return -EBUSY;
+	}
+	return (*dev->dev_ops->dev_qp_setup)(dev, queue_pair_id, qp_conf);
+}
+
+int
+rte_regexdev_start(uint8_t dev_id)
+{
+	struct rte_regexdev *dev;
+	int ret;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_start, -ENOTSUP);
+	ret = (*dev->dev_ops->dev_start)(dev);
+	if (ret == 0)
+		dev->data->dev_started = 1;
+	return ret;
+}
+
+int
+rte_regexdev_stop(uint8_t dev_id)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_stop, -ENOTSUP);
+	(*dev->dev_ops->dev_stop)(dev);
+	dev->data->dev_started = 0;
+	return 0;
+}
+
+int
+rte_regexdev_close(uint8_t dev_id)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_close, -ENOTSUP);
+	(*dev->dev_ops->dev_close)(dev);
+	dev->data->dev_started = 0;
+	dev->state = RTE_REGEXDEV_UNUSED;
+	return 0;
+}
+
+int
+rte_regexdev_attr_get(uint8_t dev_id, enum rte_regexdev_attr_id attr_id,
+		      void *attr_value)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_attr_get, -ENOTSUP);
+	if (attr_value == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d attribute value can't be NULL\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	return (*dev->dev_ops->dev_attr_get)(dev, attr_id, attr_value);
+}
+
+int
+rte_regexdev_attr_set(uint8_t dev_id, enum rte_regexdev_attr_id attr_id,
+		      const void *attr_value)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_attr_set, -ENOTSUP);
+	if (attr_value == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d attribute value can't be NULL\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	return (*dev->dev_ops->dev_attr_set)(dev, attr_id, attr_value);
+}
+
+int
+rte_regexdev_rule_db_update(uint8_t dev_id,
+			    const struct rte_regexdev_rule *rules,
+			    uint32_t nb_rules)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_rule_db_update, -ENOTSUP);
+	if (rules == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d rules can't be NULL\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	return (*dev->dev_ops->dev_rule_db_update)(dev, rules, nb_rules);
+}
+
+int
+rte_regexdev_rule_db_compile_activate(uint8_t dev_id)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_rule_db_compile_activate,
+				-ENOTSUP);
+	return (*dev->dev_ops->dev_rule_db_compile_activate)(dev);
+}
+
+int
+rte_regexdev_rule_db_import(uint8_t dev_id, const char *rule_db,
+			    uint32_t rule_db_len)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_db_import,
+				-ENOTSUP);
+	if (rule_db == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d rules can't be NULL\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	return (*dev->dev_ops->dev_db_import)(dev, rule_db, rule_db_len);
+}
+
+int
+rte_regexdev_rule_db_export(uint8_t dev_id, char *rule_db)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_db_export,
+				-ENOTSUP);
+	if (rule_db == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d rules can't be NULL\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	return (*dev->dev_ops->dev_db_export)(dev, rule_db);
+}
+
+int
+rte_regexdev_xstats_names_get(uint8_t dev_id,
+			      struct rte_regexdev_xstats_map *xstats_map)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_xstats_names_get,
+				-ENOTSUP);
+	if (xstats_map == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d xstats map can't be NULL\n",
+				 dev_id);
+		return -EINVAL;
+	}
+	return (*dev->dev_ops->dev_xstats_names_get)(dev, xstats_map);
+}
+
+int
+rte_regexdev_xstats_get(uint8_t dev_id, const uint16_t *ids,
+			uint64_t *values, uint16_t n)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_xstats_get, -ENOTSUP);
+	if (ids == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d ids can't be NULL\n", dev_id);
+		return -EINVAL;
+	}
+	if (values == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d values can't be NULL\n", dev_id);
+		return -EINVAL;
+	}
+	return (*dev->dev_ops->dev_xstats_get)(dev, ids, values, n);
+}
+
+int
+rte_regexdev_xstats_by_name_get(uint8_t dev_id, const char *name,
+				uint16_t *id, uint64_t *value)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_xstats_by_name_get,
+				-ENOTSUP);
+	if (name == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d name can't be NULL\n", dev_id);
+		return -EINVAL;
+	}
+	if (id == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d id can't be NULL\n", dev_id);
+		return -EINVAL;
+	}
+	if (value == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d value can't be NULL\n", dev_id);
+		return -EINVAL;
+	}
+	return (*dev->dev_ops->dev_xstats_by_name_get)(dev, name, id, value);
+}
+
+int
+rte_regexdev_xstats_reset(uint8_t dev_id, const uint16_t *ids,
+			  uint16_t nb_ids)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_xstats_reset, -ENOTSUP);
+	if (ids == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d ids can't be NULL\n", dev_id);
+		return -EINVAL;
+	}
+	return (*dev->dev_ops->dev_xstats_reset)(dev, ids, nb_ids);
+}
+
+int
+rte_regexdev_selftest(uint8_t dev_id)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_selftest, -ENOTSUP);
+	return (*dev->dev_ops->dev_selftest)(dev);
+}
+
+int
+rte_regexdev_dump(uint8_t dev_id, FILE *f)
+{
+	struct rte_regexdev *dev;
+
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_regex_devices[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_dump, -ENOTSUP);
+	if (f == NULL) {
+		RTE_REGEXDEV_LOG(ERR, "Dev %d file can't be NULL\n", dev_id);
+		return -EINVAL;
+	}
+	return (*dev->dev_ops->dev_dump)(dev, f);
+}
diff --git a/lib/librte_regexdev/rte_regexdev.h b/lib/librte_regexdev/rte_regexdev.h
index 1e1ba8b..f87b1f9 100644
--- a/lib/librte_regexdev/rte_regexdev.h
+++ b/lib/librte_regexdev/rte_regexdev.h
@@ -213,6 +213,33 @@ 
 #define RTE_REGEXDEV_LOG(level, ...) \
 	rte_log(RTE_LOG_ ## level, rte_regexdev_logtype, "" __VA_ARGS__)
 
+/* Macros to check for valid port */
+#define RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, retval) do { \
+	if (!rte_regexdev_is_valid_dev(dev_id)) { \
+		RTE_REGEXDEV_LOG(ERR, "Invalid dev_id=%u\n", dev_id); \
+		return retval; \
+	} \
+} while (0)
+
+#define RTE_REGEXDEV_VALID_DEV_ID_OR_RET(dev_id) do { \
+	if (!rte_regexdev_is_valid_dev(dev_id)) { \
+		RTE_REGEXDEV_LOG(ERR, "Invalid dev_id=%u\n", dev_id); \
+		return; \
+	} \
+} while (0)
+
+/**
+ * Check if dev_id is ready.
+ *
+ * @param dev_id
+ *   The dev identifier of the RegEx device.
+ *
+ * @return
+ *   - 0 if device state is not in ready state.
+ *   - 1 if device state is ready state.
+ */
+int rte_regexdev_is_valid_dev(uint16_t dev_id);
+
 /**
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice.
@@ -803,10 +830,11 @@  struct rte_regexdev_qp_conf {
  * @param dev_id
  *   RegEx device identifier.
  *
- * @see struct rte_regexdev_qp_conf::cb, rte_regexdev_queue_pair_setup()
+ * @return
+ *   0 on success. Otherwise negative errno is returned.
  */
 __rte_experimental
-void
+int
 rte_regexdev_stop(uint8_t dev_id);
 
 /**
@@ -1384,6 +1412,8 @@  struct rte_regex_ops {
 	 */
 };
 
+#include "rte_regexdev_core.h"
+
 /**
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice.
@@ -1422,9 +1452,21 @@  struct rte_regex_ops {
  *   to take care of them.
  */
 __rte_experimental
-uint16_t
+static inline uint16_t
 rte_regexdev_enqueue_burst(uint8_t dev_id, uint16_t qp_id,
-			   struct rte_regex_ops **ops, uint16_t nb_ops);
+			   struct rte_regex_ops **ops, uint16_t nb_ops)
+{
+	struct rte_regexdev *dev = &rte_regex_devices[dev_id];
+#ifdef RTE_LIBRTE_REGEXDEV_DEBUG
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->enqueue, -ENOTSUP);
+	if (qp_id >= dev->data->dev_conf.nb_queue_pairs) {
+		RTE_REGEXDEV_LOG(ERR, "Invalid queue %d\n", qp_id);
+		return -EINVAL;
+	}
+#endif
+	return (*dev->enqueue)(dev, qp_id, ops, nb_ops);
+}
 
 /**
  * @warning
@@ -1469,11 +1511,21 @@  struct rte_regex_ops {
  *   of them.
  */
 __rte_experimental
-uint16_t
+static inline uint16_t
 rte_regexdev_dequeue_burst(uint8_t dev_id, uint16_t qp_id,
-			   struct rte_regex_ops **ops, uint16_t nb_ops);
-
-#include "rte_regexdev_core.h"
+			   struct rte_regex_ops **ops, uint16_t nb_ops)
+{
+	struct rte_regexdev *dev = &rte_regex_devices[dev_id];
+#ifdef RTE_LIBRTE_REGEXDEV_DEBUG
+	RTE_REGEXDEV_VALID_DEV_ID_OR_ERR_RET(dev_id, -EINVAL);
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dequeue, -ENOTSUP);
+	if (qp_id >= dev->data->dev_conf.nb_queue_pairs) {
+		RTE_REGEXDEV_LOG(ERR, "Invalid queue %d\n", qp_id);
+		return -EINVAL;
+	}
+#endif
+	return (*dev->dequeue)(dev, qp_id, ops, nb_ops);
+}
 
 #ifdef __cplusplus
 }
diff --git a/lib/librte_regexdev/rte_regexdev_core.h b/lib/librte_regexdev/rte_regexdev_core.h
index baded23..c748de4 100644
--- a/lib/librte_regexdev/rte_regexdev_core.h
+++ b/lib/librte_regexdev/rte_regexdev_core.h
@@ -149,6 +149,8 @@  struct rte_regexdev_data {
 	void *dev_private; /**< PMD-specific private data. */
 	char dev_name[RTE_REGEXDEV_NAME_MAX_LEN]; /**< Unique identifier name */
 	uint16_t dev_id; /**< Device [external]  identifier. */
+	struct rte_regexdev_config dev_conf; /**< RegEx configuration. */
+	uint8_t dev_started : 1; /**< Device started to work. */
 } __rte_cache_aligned;
 
 /**
@@ -171,4 +173,11 @@  struct rte_regexdev {
 	struct rte_regexdev_data *data;  /**< Pointer to device data. */
 } __rte_cache_aligned;
 
+/**
+ * @internal
+ * The pool of *rte_regexdev* structures. The size of the pool
+ * is configured at compile-time in the <rte_regexdev.c> file.
+ */
+extern struct rte_regexdev rte_regex_devices[];
+
 #endif /* _RTE_REGEX_CORE_H_ */