diff mbox

[API-NEXT,PATCHv2,2/4] linux-generic: classification: implement pmr create api

Message ID 1454331360-16717-2-git-send-email-bala.manoharan@linaro.org
State Superseded
Headers show

Commit Message

Balasubramanian Manoharan Feb. 1, 2016, 12:55 p.m. UTC
Implements packet match rule create functions.
If a packet match rule needs to be applied at the pktio level it has to be
configured to the default class of service.

Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>
---
 .../include/odp_classification_datamodel.h         |  48 +---
 .../include/odp_classification_internal.h          |  21 +-
 platform/linux-generic/odp_classification.c        | 313 ++++++---------------
 platform/linux-generic/odp_packet_io.c             |  24 +-
 4 files changed, 94 insertions(+), 312 deletions(-)
diff mbox

Patch

diff --git a/platform/linux-generic/include/odp_classification_datamodel.h b/platform/linux-generic/include/odp_classification_datamodel.h
index 27d8a52..6301f18 100644
--- a/platform/linux-generic/include/odp_classification_datamodel.h
+++ b/platform/linux-generic/include/odp_classification_datamodel.h
@@ -28,14 +28,12 @@  extern "C" {
 
 /* Maximum Class Of Service Entry */
 #define ODP_COS_MAX_ENTRY		64
-/* Maximum PMR Set Entry */
-#define ODP_PMRSET_MAX_ENTRY		64
 /* Maximum PMR Entry */
-#define ODP_PMR_MAX_ENTRY		64
+#define ODP_PMR_MAX_ENTRY		256
 /* Maximum PMR Terms in a PMR Set */
 #define ODP_PMRTERM_MAX			8
 /* Maximum PMRs attached in PKTIO Level */
-#define ODP_PKTIO_MAX_PMR		8
+#define ODP_PMR_PER_COS_MAX		8
 /* L2 Priority Bits */
 #define ODP_COS_L2_QOS_BITS		3
 /* Max L2 QoS value */
@@ -67,15 +65,16 @@  Class Of Service
 struct cos_s {
 	queue_entry_t *queue;		/* Associated Queue */
 	pool_entry_t *pool;		/* Associated Buffer pool */
-	union pmr_u *pmr;		/* Chained PMR */
-	union cos_u *linked_cos;	/* CoS linked with the PMR */
+	union pmr_u *pmr[ODP_PMR_PER_COS_MAX];	/* Chained PMR */
+	union cos_u *linked_cos[ODP_PMR_PER_COS_MAX]; /* Chained CoS with PMR*/
 	uint32_t valid;			/* validity Flag */
-	odp_cls_drop_t drop_policy;		/* Associated Drop Policy */
+	odp_cls_drop_t drop_policy;	/* Associated Drop Policy */
 	odp_queue_group_t queue_group;	/* Associated Queue Group */
 	odp_cos_flow_set_t flow_set;	/* Assigned Flow Set */
-	char name[ODP_COS_NAME_LEN];	/* name */
 	size_t headroom;		/* Headroom for this CoS */
 	odp_spinlock_t lock;		/* cos lock */
+	odp_atomic_u32_t num_rule;	/* num of PMRs attached with this CoS */
+	char name[ODP_COS_NAME_LEN];	/* name */
 };
 
 typedef union cos_u {
@@ -93,7 +92,9 @@  struct pmr_s {
 	odp_atomic_u32_t count;		/* num of packets matching this rule */
 	uint32_t num_pmr;		/* num of PMR Term Values*/
 	odp_spinlock_t lock;		/* pmr lock*/
-	pmr_term_value_t  pmr_term_value[1];	/* Associated PMR Term */
+	cos_t *src_cos;			/* source CoS where PMR is attached */
+	pmr_term_value_t  pmr_term_value[ODP_PMRTERM_MAX];
+			/* List of associated PMR Terms */
 };
 
 typedef union pmr_u {
@@ -102,24 +103,6 @@  typedef union pmr_u {
 } pmr_t;
 
 /**
-Packet Matching Rule Set
-
-This structure is implemented as a extension over struct pmr_s
-In order to use same pointer to access both pmr_s and pmr_set_s
-'num_pmr' value is used to differentiate between pmr_s and pmr_set_s struct
-**/
-struct pmr_set_s {
-	pmr_t pmr;
-	pmr_term_value_t  pmr_term_value[ODP_PMRTERM_MAX - 1];
-			/* List of associated PMR Terms */
-};
-
-typedef union pmr_set_u {
-	struct pmr_set_s s;
-	uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct pmr_set_s))];
-} pmr_set_t;
-
-/**
 L2 QoS and CoS Map
 
 This structure holds the mapping between L2 QoS value and
@@ -148,10 +131,6 @@  This structure is stored in pktio_entry and holds all
 the classifier configuration value.
 **/
 typedef struct classifier {
-	odp_spinlock_t lock;		/*pktio_cos lock */
-	uint32_t num_pmr;		/* num of PMRs linked to given PKTIO*/
-	pmr_t *pmr[ODP_PKTIO_MAX_PMR];	/* PMRs linked with this PKTIO */
-	cos_t *cos[ODP_PKTIO_MAX_PMR];	/* CoS linked with this PKTIO */
 	cos_t *error_cos;		/* Associated Error CoS */
 	cos_t *default_cos;		/* Associated Default CoS */
 	uint32_t l3_precedence;		/* L3 QoS precedence */
@@ -171,13 +150,6 @@  typedef struct odp_cos_table {
 } cos_tbl_t;
 
 /**
-PMR set table
-**/
-typedef struct pmr_set_tbl {
-	pmr_set_t pmr_set[ODP_PMRSET_MAX_ENTRY];
-} pmr_set_tbl_t;
-
-/**
 PMR table
 **/
 typedef struct pmr_tbl {
diff --git a/platform/linux-generic/include/odp_classification_internal.h b/platform/linux-generic/include/odp_classification_internal.h
index 1e8f291..3fa18ad 100644
--- a/platform/linux-generic/include/odp_classification_internal.h
+++ b/platform/linux-generic/include/odp_classification_internal.h
@@ -117,12 +117,6 @@  int update_flow_signature(uint8_t *pkt_addr, cos_t *cos);
 
 /**
 @internal
-Allocate a odp_pmr_set_t Handle
-*/
-odp_pmr_set_t alloc_pmr_set(pmr_t **pmr);
-
-/**
-@internal
 Allocate a odp_pmr_t Handle
 */
 odp_pmr_t alloc_pmr(pmr_t **pmr);
@@ -132,24 +126,11 @@  odp_pmr_t alloc_pmr(pmr_t **pmr);
 Pointer to pmr_set_t Handle
 This function checks for validity of pmr_set_t Handle
 */
-pmr_set_t *get_pmr_set_entry(odp_pmr_set_t pmr_set_id);
-
-/**
-@internal
-Pointer to pmr_set_t Handle
-*/
-pmr_set_t *get_pmr_set_entry_internal(odp_pmr_set_t pmr_set_id);
-
-/**
-@internal
-Pointer to pmr_set_t Handle
-This function checks for validity of pmr_set_t Handle
-*/
 pmr_t *get_pmr_entry(odp_pmr_t pmr_id);
 
 /**
 @internal
-Pointer to pmr_set_t Handle
+Pointer to pmr_t Handle
 */
 pmr_t *get_pmr_entry_internal(odp_pmr_t pmr_id);
 
diff --git a/platform/linux-generic/odp_classification.c b/platform/linux-generic/odp_classification.c
index da195ad..88017ce 100644
--- a/platform/linux-generic/odp_classification.c
+++ b/platform/linux-generic/odp_classification.c
@@ -27,7 +27,6 @@ 
 #define LOCK_INIT(a)	odp_spinlock_init(a)
 
 static cos_tbl_t *cos_tbl;
-static pmr_set_tbl_t	*pmr_set_tbl;
 static pmr_tbl_t	*pmr_tbl;
 
 cos_t *get_cos_entry_internal(odp_cos_t cos_id)
@@ -35,11 +34,6 @@  cos_t *get_cos_entry_internal(odp_cos_t cos_id)
 	return &(cos_tbl->cos_entry[_odp_typeval(cos_id)]);
 }
 
-pmr_set_t *get_pmr_set_entry_internal(odp_pmr_set_t pmr_set_id)
-{
-	return &(pmr_set_tbl->pmr_set[_odp_typeval(pmr_set_id)]);
-}
-
 pmr_t *get_pmr_entry_internal(odp_pmr_t pmr_id)
 {
 	return &(pmr_tbl->pmr[_odp_typeval(pmr_id)]);
@@ -49,7 +43,6 @@  int odp_classification_init_global(void)
 {
 	odp_shm_t cos_shm;
 	odp_shm_t pmr_shm;
-	odp_shm_t pmr_set_shm;
 	int i;
 
 	cos_shm = odp_shm_reserve("shm_odp_cos_tbl",
@@ -94,32 +87,8 @@  int odp_classification_init_global(void)
 		LOCK_INIT(&pmr->s.lock);
 	}
 
-	pmr_set_shm = odp_shm_reserve("shm_odp_pmr_set_tbl",
-			sizeof(pmr_set_tbl_t),
-			sizeof(pmr_set_t), 0);
-
-	if (pmr_set_shm == ODP_SHM_INVALID) {
-		ODP_ERR("shm allocation failed for shm_odp_pmr_set_tbl");
-		goto error_pmr;
-	}
-
-	pmr_set_tbl = odp_shm_addr(pmr_set_shm);
-	if (pmr_set_tbl == NULL)
-		goto error_pmrset;
-
-	memset(pmr_set_tbl, 0, sizeof(pmr_set_tbl_t));
-	for (i = 0; i < ODP_PMRSET_MAX_ENTRY; i++) {
-		/* init locks */
-		pmr_set_t *pmr =
-			get_pmr_set_entry_internal
-			(_odp_cast_scalar(odp_pmr_set_t, i));
-		LOCK_INIT(&pmr->s.pmr.s.lock);
-	}
-
 	return 0;
 
-error_pmrset:
-	odp_shm_free(pmr_set_shm);
 error_pmr:
 	odp_shm_free(pmr_shm);
 error_cos:
@@ -145,12 +114,6 @@  int odp_classification_term_global(void)
 		rc = -1;
 	}
 
-	ret = odp_shm_free(odp_shm_lookup("shm_odp_pmr_set_tbl"));
-	if (ret < 0) {
-		ODP_ERR("shm free failed for shm_odp_pmr_tbl");
-		rc = -1;
-	}
-
 	return rc;
 }
 
@@ -163,7 +126,7 @@  void odp_cls_cos_param_init(odp_cls_cos_param_t *param)
 
 odp_cos_t odp_cls_cos_create(const char *name, odp_cls_cos_param_t *param)
 {
-	int i;
+	int i, j;
 	queue_entry_t *queue;
 	pool_entry_t *pool;
 	odp_cls_drop_t drop_policy;
@@ -187,14 +150,18 @@  odp_cos_t odp_cls_cos_create(const char *name, odp_cls_cos_param_t *param)
 			strncpy(cos_tbl->cos_entry[i].s.name, name,
 				ODP_COS_NAME_LEN - 1);
 			cos_tbl->cos_entry[i].s.name[ODP_COS_NAME_LEN - 1] = 0;
-			cos_tbl->cos_entry[i].s.pmr = NULL;
-			cos_tbl->cos_entry[i].s.linked_cos = NULL;
+			for (j = 0; j < ODP_PMR_PER_COS_MAX; j++) {
+				cos_tbl->cos_entry[i].s.pmr[j] = NULL;
+				cos_tbl->cos_entry[i].s.linked_cos[j] = NULL;
+			}
 			cos_tbl->cos_entry[i].s.queue = queue;
 			cos_tbl->cos_entry[i].s.pool = pool;
 			cos_tbl->cos_entry[i].s.flow_set = 0;
 			cos_tbl->cos_entry[i].s.headroom = 0;
 			cos_tbl->cos_entry[i].s.valid = 1;
 			cos_tbl->cos_entry[i].s.drop_policy = drop_policy;
+			odp_atomic_init_u32(&cos_tbl->cos_entry[i]
+					    .s.num_rule, 0);
 			UNLOCK(&cos_tbl->cos_entry[i].s.lock);
 			return _odp_cast_scalar(odp_cos_t, i);
 		}
@@ -205,27 +172,6 @@  odp_cos_t odp_cls_cos_create(const char *name, odp_cls_cos_param_t *param)
 	return ODP_COS_INVALID;
 }
 
-odp_pmr_set_t alloc_pmr_set(pmr_t **pmr)
-{
-	int i;
-
-	for (i = 0; i < ODP_PMRSET_MAX_ENTRY; i++) {
-		LOCK(&pmr_set_tbl->pmr_set[i].s.pmr.s.lock);
-		if (0 == pmr_set_tbl->pmr_set[i].s.pmr.s.valid) {
-			pmr_set_tbl->pmr_set[i].s.pmr.s.valid = 1;
-			pmr_set_tbl->pmr_set[i].s.pmr.s.num_pmr = 0;
-			*pmr = (pmr_t *)&pmr_set_tbl->pmr_set[i];
-			odp_atomic_init_u32(&pmr_set_tbl->pmr_set[i]
-					    .s.pmr.s.count, 0);
-			/* return as locked */
-			return _odp_cast_scalar(odp_pmr_set_t, i);
-		}
-		UNLOCK(&pmr_set_tbl->pmr_set[i].s.pmr.s.lock);
-	}
-	ODP_ERR("ODP_PMRSET_MAX_ENTRY reached");
-	return ODP_PMR_SET_INVAL;
-}
-
 odp_pmr_t alloc_pmr(pmr_t **pmr)
 {
 	int i;
@@ -257,17 +203,6 @@  cos_t *get_cos_entry(odp_cos_t cos_id)
 	return &(cos_tbl->cos_entry[_odp_typeval(cos_id)]);
 }
 
-
-pmr_set_t *get_pmr_set_entry(odp_pmr_set_t pmr_set_id)
-{
-	if (_odp_typeval(pmr_set_id) >= ODP_PMRSET_MAX_ENTRY ||
-	    pmr_set_id == ODP_PMR_SET_INVAL)
-		return NULL;
-	if (pmr_set_tbl->pmr_set[_odp_typeval(pmr_set_id)].s.pmr.s.valid == 0)
-		return NULL;
-	return &(pmr_set_tbl->pmr_set[_odp_typeval(pmr_set_id)]);
-}
-
 pmr_t *get_pmr_entry(odp_pmr_t pmr_id)
 {
 	if (_odp_typeval(pmr_id) >= ODP_PMR_MAX_ENTRY ||
@@ -487,95 +422,39 @@  static void odp_pmr_create_term(pmr_term_value_t *value,
 	value->val &= value->mask;
 }
 
-odp_pmr_t odp_pmr_create(const odp_pmr_match_t *match)
+int odp_cls_pmr_destroy(odp_pmr_t pmr_id)
 {
+	cos_t *src_cos;
+	uint32_t loc;
 	pmr_t *pmr;
-	odp_pmr_t id;
-	if (match->val_sz > ODP_PMR_TERM_BYTES_MAX) {
-		ODP_ERR("val_sz greater than max supported limit");
-		return ODP_PMR_INVAL;
-	}
-
-	id = alloc_pmr(&pmr);
-	/*if alloc_pmr() is successful it returns with lock acquired*/
-	if (id == ODP_PMR_INVAL)
-		return ODP_PMR_INVAL;
-
-	pmr->s.num_pmr = 1;
-	odp_pmr_create_term(&pmr->s.pmr_term_value[0], match);
-	UNLOCK(&pmr->s.lock);
-	return id;
-}
-
-int odp_pmr_destroy(odp_pmr_t pmr_id)
-{
-	pmr_t *pmr = get_pmr_entry(pmr_id);
-
-	if (pmr == NULL)
-		return -1;
-	pmr->s.valid = 0;
-	return 0;
-}
-
-int odp_pktio_pmr_cos(odp_pmr_t pmr_id,
-		      odp_pktio_t src_pktio,
-		      odp_cos_t dst_cos)
-{
-	uint8_t num_pmr;
-	pktio_entry_t *pktio_entry;
-	pmr_t *pmr;
-	cos_t *cos;
-
-	pktio_entry = get_pktio_entry(src_pktio);
-	if (pktio_entry == NULL) {
-		ODP_ERR("Invalid odp_pktio_t handle");
-		return -1;
-	}
+	uint8_t i;
 
 	pmr = get_pmr_entry(pmr_id);
-	if (pmr == NULL) {
-		ODP_ERR("Invalid odp_pmr_t handle");
-		return -1;
-	}
-
-	cos = get_cos_entry(dst_cos);
-	if (cos == NULL) {
-		ODP_ERR("Invalid odp_cos_t handle");
-		return -1;
-	}
-
-	LOCK(&pktio_entry->s.cls.lock);
-	num_pmr = pktio_entry->s.cls.num_pmr;
-	if (num_pmr >= ODP_PKTIO_MAX_PMR) {
-		ODP_ERR("ODP_PKTIO_MAX_PMR reached");
-		UNLOCK(&pktio_entry->s.cls.lock);
-		return -1;
-	}
-
-	pktio_entry->s.cls.pmr[num_pmr] = pmr;
-	pktio_entry->s.cls.cos[num_pmr] = cos;
-	pktio_entry->s.cls.num_pmr++;
-	pktio_cls_enabled_set(pktio_entry, 1);
-	UNLOCK(&pktio_entry->s.cls.lock);
+	if (pmr == NULL || pmr->s.src_cos == NULL)
+		return -1;
+
+	src_cos = pmr->s.src_cos;
+	LOCK(&src_cos->s.lock);
+	loc = odp_atomic_load_u32(&src_cos->s.num_rule);
+	if (loc == 0)
+		goto no_rule;
+	loc -= 1;
+	for (i = 0; i <= loc; i++)
+		if (src_cos->s.pmr[i] == pmr) {
+			src_cos->s.pmr[i] = src_cos->s.pmr[loc];
+			src_cos->s.linked_cos[i] = src_cos->s.linked_cos[loc];
+		}
+	odp_atomic_dec_u32(&src_cos->s.num_rule);
 
+no_rule:
+	pmr->s.valid = 0;
+	UNLOCK(&src_cos->s.lock);
 	return 0;
 }
 
-int odp_cos_pmr_cos(odp_pmr_t pmr_id, odp_cos_t src_cos, odp_cos_t dst_cos)
+int odp_cls_pmr_num_terms(void)
 {
-	cos_t *cos_src = get_cos_entry(src_cos);
-	cos_t *cos_dst = get_cos_entry(dst_cos);
-	pmr_t *pmr = get_pmr_entry(pmr_id);
-	if (NULL == cos_src || NULL == cos_dst || NULL == pmr) {
-		ODP_ERR("Invalid input handle");
-		return -1;
-	}
-
-	/*Locking is not required as intermittent stale data is acceptable*/
-	cos_src->s.pmr = pmr;
-	cos_src->s.linked_cos = cos_dst;
-
-	return 0;
+	return ODP_PMRTERM_MAX;
 }
 
 unsigned long long odp_pmr_terms_cap(void)
@@ -604,91 +483,53 @@  unsigned odp_pmr_terms_avail(void)
 	return count;
 }
 
-int odp_pmr_match_set_create(int num_terms, const odp_pmr_match_t *terms,
-			     odp_pmr_set_t *pmr_set_id)
+odp_pmr_t odp_cls_pmr_create(int num_terms, const odp_pmr_match_t *terms,
+			     odp_cos_t src_cos, odp_cos_t dst_cos)
 {
 	pmr_t *pmr;
 	int i;
-	odp_pmr_set_t id;
+	odp_pmr_t id;
 	int val_sz;
-	int count = 0;
+	uint32_t loc;
+	cos_t *cos_src = get_cos_entry(src_cos);
+	cos_t *cos_dst = get_cos_entry(dst_cos);
+
+	if (NULL == cos_src || NULL == cos_dst) {
+		ODP_ERR("Invalid input handle");
+		return ODP_PMR_INVAL;
+	}
 
 	if (num_terms > ODP_PMRTERM_MAX) {
 		ODP_ERR("no of terms greater than supported ODP_PMRTERM_MAX");
-		return -1;
+		return ODP_PMR_INVAL;
 	}
 
-	id = alloc_pmr_set(&pmr);
-	/*if alloc_pmr_set is successful it returns with the acquired lock*/
-	if (id == ODP_PMR_SET_INVAL) {
-		*pmr_set_id = id;
-		return -1;
-	}
+	if (ODP_PMR_PER_COS_MAX == odp_atomic_load_u32(&cos_src->s.num_rule))
+		return ODP_PMR_INVAL;
+
+	id = alloc_pmr(&pmr);
+	/*if alloc_pmr is successful it returns with the acquired lock*/
+	if (id == ODP_PMR_INVAL)
+		return id;
 
 	pmr->s.num_pmr = num_terms;
 	for (i = 0; i < num_terms; i++) {
 		val_sz = terms[i].val_sz;
-		if (val_sz > ODP_PMR_TERM_BYTES_MAX)
-			continue;
+		if (val_sz > ODP_PMR_TERM_BYTES_MAX) {
+			pmr->s.valid = 0;
+			UNLOCK(&pmr->s.lock);
+			return ODP_PMR_INVAL;
+		}
 		odp_pmr_create_term(&pmr->s.pmr_term_value[i], &terms[i]);
-		count++;
-	}
-	*pmr_set_id = id;
-	UNLOCK(&pmr->s.lock);
-	return count;
-}
-
-int odp_pmr_match_set_destroy(odp_pmr_set_t pmr_set_id)
-{
-	pmr_set_t *pmr_set = get_pmr_set_entry(pmr_set_id);
-	if (pmr_set == NULL)
-		return -1;
-
-	pmr_set->s.pmr.s.valid = 0;
-	return 0;
-}
-
-int odp_pktio_pmr_match_set_cos(odp_pmr_set_t pmr_set_id, odp_pktio_t src_pktio,
-		odp_cos_t dst_cos)
-{
-	uint8_t num_pmr;
-	pktio_entry_t *pktio_entry;
-	pmr_t *pmr;
-	cos_t *cos;
-
-	pktio_entry = get_pktio_entry(src_pktio);
-	if (pktio_entry == NULL) {
-		ODP_ERR("Invalid odp_pktio_t handle");
-		return -1;
 	}
 
-	pmr = (pmr_t *)get_pmr_set_entry(pmr_set_id);
-	if (pmr == NULL) {
-		ODP_ERR("Invalid odp_pmr_set_t handle");
-		return -1;
-	}
+	loc = odp_atomic_fetch_inc_u32(&cos_src->s.num_rule);
+	cos_src->s.pmr[loc] = pmr;
+	cos_src->s.linked_cos[loc] = cos_dst;
+	pmr->s.src_cos = cos_src;
 
-	cos = get_cos_entry(dst_cos);
-	if (cos == NULL) {
-		ODP_ERR("Invalid odp_cos_t handle");
-		return -1;
-	}
-
-	LOCK(&pktio_entry->s.cls.lock);
-	num_pmr = pktio_entry->s.cls.num_pmr;
-	if (num_pmr >= ODP_PKTIO_MAX_PMR) {
-		ODP_ERR("ODP_PKTIO_MAX_PMR reached");
-		UNLOCK(&pktio_entry->s.cls.lock);
-		return -1;
-	}
-
-	pktio_entry->s.cls.pmr[num_pmr] = pmr;
-	pktio_entry->s.cls.cos[num_pmr] = cos;
-	pktio_entry->s.cls.num_pmr++;
-	pktio_cls_enabled_set(pktio_entry, 1);
-	UNLOCK(&pktio_entry->s.cls.lock);
-
-	return 0;
+	UNLOCK(&pmr->s.lock);
+	return id;
 }
 
 int odp_cls_cos_pool_set(odp_cos_t cos_id, odp_pool_t pool_id)
@@ -846,7 +687,10 @@  int verify_pmr(pmr_t *pmr, const uint8_t *pkt_addr, odp_packet_hdr_t *pkt_hdr)
 cos_t *match_pmr_cos(cos_t *cos, const uint8_t *pkt_addr, pmr_t *pmr,
 		     odp_packet_hdr_t *hdr)
 {
-	cos_t *retcos = NULL;
+	cos_t *retcos;
+	uint32_t i;
+
+	retcos  = NULL;
 
 	if (cos == NULL || pmr == NULL)
 		return NULL;
@@ -857,10 +701,15 @@  cos_t *match_pmr_cos(cos_t *cos, const uint8_t *pkt_addr, pmr_t *pmr,
 	if (verify_pmr(pmr, pkt_addr, hdr)) {
 		/** This gets called recursively to check all the PMRs in
 		 * a PMR chain */
-		retcos = match_pmr_cos(cos->s.linked_cos, pkt_addr,
-				       cos->s.pmr, hdr);
-		if (!retcos)
+		if (0 == odp_atomic_load_u32(&cos->s.num_rule))
 			return cos;
+
+		for (i = 0; i < odp_atomic_load_u32(&cos->s.num_rule); i++) {
+			retcos = match_pmr_cos(cos->s.linked_cos[i], pkt_addr,
+					       cos->s.pmr[i], hdr);
+			if (!retcos)
+				return cos;
+		}
 	}
 	return retcos;
 }
@@ -868,23 +717,17 @@  cos_t *match_pmr_cos(cos_t *cos, const uint8_t *pkt_addr, pmr_t *pmr,
 int pktio_classifier_init(pktio_entry_t *entry)
 {
 	classifier_t *cls;
-	int i;
+
 	/* classifier lock should be acquired by the calling function */
 	if (entry == NULL)
 		return -1;
 	cls = &entry->s.cls;
-	cls->num_pmr = 0;
 	cls->flow_set = 0;
 	cls->error_cos = NULL;
 	cls->default_cos = NULL;
 	cls->headroom = 0;
 	cls->skip = 0;
 
-	for (i = 0; i < ODP_PKTIO_MAX_PMR; i++) {
-		cls->pmr[i] = NULL;
-		cls->cos[i] = NULL;
-	}
-
 	return 0;
 }
 
@@ -946,10 +789,12 @@  cos_t *pktio_select_cos(pktio_entry_t *entry, const uint8_t *pkt_addr,
 {
 	pmr_t *pmr;
 	cos_t *cos;
+	cos_t *default_cos;
 	uint32_t i;
 	classifier_t *cls;
 
 	cls = &entry->s.cls;
+	default_cos = cls->default_cos;
 
 	/* Check for lazy parse needed */
 	if (packet_parse_not_complete(pkt_hdr))
@@ -959,9 +804,9 @@  cos_t *pktio_select_cos(pktio_entry_t *entry, const uint8_t *pkt_addr,
 	if (pkt_hdr->error_flags.all)
 		return cls->error_cos;
 	/* Calls all the PMRs attached at the PKTIO level*/
-	for (i = 0; i < cls->num_pmr; i++) {
-		pmr = entry->s.cls.pmr[i];
-		cos = entry->s.cls.cos[i];
+	for (i = 0; i < odp_atomic_load_u32(&default_cos->s.num_rule); i++) {
+		pmr = default_cos->s.pmr[i];
+		cos = default_cos->s.linked_cos[i];
 		cos = match_pmr_cos(cos, pkt_addr, pmr, pkt_hdr);
 		if (cos)
 			return cos;
diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c
index b24cb1a..ed49198 100644
--- a/platform/linux-generic/odp_packet_io.c
+++ b/platform/linux-generic/odp_packet_io.c
@@ -57,7 +57,6 @@  int odp_pktio_init_global(void)
 
 		odp_ticketlock_init(&pktio_entry->s.rxl);
 		odp_ticketlock_init(&pktio_entry->s.txl);
-		odp_spinlock_init(&pktio_entry->s.cls.lock);
 		odp_spinlock_init(&pktio_entry->s.cls.l2_cos_table.lock);
 		odp_spinlock_init(&pktio_entry->s.cls.l3_cos_table.lock);
 
@@ -117,20 +116,6 @@  static void unlock_entry(pktio_entry_t *entry)
 	odp_ticketlock_unlock(&entry->s.rxl);
 }
 
-static void lock_entry_classifier(pktio_entry_t *entry)
-{
-	odp_ticketlock_lock(&entry->s.rxl);
-	odp_ticketlock_lock(&entry->s.txl);
-	odp_spinlock_lock(&entry->s.cls.lock);
-}
-
-static void unlock_entry_classifier(pktio_entry_t *entry)
-{
-	odp_spinlock_unlock(&entry->s.cls.lock);
-	odp_ticketlock_unlock(&entry->s.txl);
-	odp_ticketlock_unlock(&entry->s.rxl);
-}
-
 static void init_pktio_entry(pktio_entry_t *entry)
 {
 	int i;
@@ -156,13 +141,13 @@  static odp_pktio_t alloc_lock_pktio_entry(void)
 	for (i = 0; i < ODP_CONFIG_PKTIO_ENTRIES; ++i) {
 		entry = &pktio_tbl->entries[i];
 		if (is_free(entry)) {
-			lock_entry_classifier(entry);
+			lock_entry(entry);
 			if (is_free(entry)) {
 				init_pktio_entry(entry);
 				id = _odp_cast_scalar(odp_pktio_t, i + 1);
 				return id; /* return with entry locked! */
 			}
-			unlock_entry_classifier(entry);
+			unlock_entry(entry);
 		}
 	}
 
@@ -201,8 +186,8 @@  static odp_pktio_t setup_pktio_entry(const char *dev, odp_pool_t pool,
 		ODP_ERR("No resources available.\n");
 		return ODP_PKTIO_INVALID;
 	}
-	/* if successful, alloc_pktio_entry() returns with the entry locked */
 
+	/* if successful, alloc_pktio_entry() returns with the entry locked */
 	pktio_entry = get_pktio_entry(id);
 	if (!pktio_entry)
 		return ODP_PKTIO_INVALID;
@@ -222,7 +207,6 @@  static odp_pktio_t setup_pktio_entry(const char *dev, odp_pool_t pool,
 	}
 
 	if (ret != 0) {
-		unlock_entry_classifier(pktio_entry);
 		free_pktio_entry(id);
 		id = ODP_PKTIO_INVALID;
 		ODP_ERR("Unable to init any I/O type.\n");
@@ -230,10 +214,10 @@  static odp_pktio_t setup_pktio_entry(const char *dev, odp_pool_t pool,
 		snprintf(pktio_entry->s.name,
 			 sizeof(pktio_entry->s.name), "%s", dev);
 		pktio_entry->s.state = STATE_STOP;
-		unlock_entry_classifier(pktio_entry);
 	}
 
 	pktio_entry->s.handle = id;
+	unlock_entry(pktio_entry);
 
 	return id;
 }