@@ -239,10 +239,189 @@ npc_parse_la(struct npc_parse_state *pst)
#define NPC_MAX_SUPPORTED_VLANS 3
+static int
+npc_parse_vlan_count(const struct roc_npc_item_info *pattern,
+ const struct roc_npc_item_info **pattern_list,
+ const struct roc_npc_flow_item_vlan **vlan_items, int *vlan_count)
+{
+ *vlan_count = 0;
+ while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
+ if (*vlan_count > NPC_MAX_SUPPORTED_VLANS - 1)
+ return NPC_ERR_PATTERN_NOTSUP;
+
+ /* Don't support ranges */
+ if (pattern->last != NULL)
+ return NPC_ERR_INVALID_RANGE;
+
+ /* If spec is NULL, both mask and last must be NULL, this
+ * makes it to match ANY value (eq to mask = 0).
+ * Setting either mask or last without spec is an error
+ */
+ if (pattern->spec == NULL) {
+ if (pattern->last != NULL && pattern->mask != NULL)
+ return NPC_ERR_INVALID_SPEC;
+ }
+
+ pattern_list[*vlan_count] = pattern;
+ vlan_items[*vlan_count] = pattern->spec;
+ (*vlan_count)++;
+
+ pattern++;
+ pattern = npc_parse_skip_void_and_any_items(pattern);
+ }
+
+ return 0;
+}
+
+static int
+npc_parse_vlan_ltype_get(struct npc_parse_state *pst,
+ const struct roc_npc_flow_item_vlan **vlan_item, int vlan_count,
+ int *ltype, int *lflags)
+{
+ switch (vlan_count) {
+ case 1:
+ *ltype = NPC_LT_LB_CTAG;
+ if (vlan_item[0] && vlan_item[0]->has_more_vlan)
+ *ltype = NPC_LT_LB_STAG_QINQ;
+ break;
+ case 2:
+ if (vlan_item[1] && vlan_item[1]->has_more_vlan) {
+ if (!(pst->npc->keyx_supp_nmask[pst->nix_intf] &
+ 0x3ULL << NPC_LFLAG_LB_OFFSET))
+ return NPC_ERR_PATTERN_NOTSUP;
+
+ /* This lflag value will match either one of
+ * NPC_F_LB_L_WITH_STAG_STAG,
+ * NPC_F_LB_L_WITH_QINQ_CTAG,
+ * NPC_F_LB_L_WITH_QINQ_QINQ and
+ * NPC_F_LB_L_WITH_ITAG (0b0100 to 0b0111). For
+ * NPC_F_LB_L_WITH_ITAG, ltype is NPC_LT_LB_ETAG
+ * hence will not match.
+ */
+
+ *lflags = NPC_F_LB_L_WITH_QINQ_CTAG & NPC_F_LB_L_WITH_QINQ_QINQ &
+ NPC_F_LB_L_WITH_STAG_STAG;
+ }
+ *ltype = NPC_LT_LB_STAG_QINQ;
+ break;
+ case 3:
+ if (vlan_item[2] && vlan_item[2]->has_more_vlan)
+ return NPC_ERR_PATTERN_NOTSUP;
+ if (!(pst->npc->keyx_supp_nmask[pst->nix_intf] & 0x3ULL << NPC_LFLAG_LB_OFFSET))
+ return NPC_ERR_PATTERN_NOTSUP;
+ *ltype = NPC_LT_LB_STAG_QINQ;
+ *lflags = NPC_F_STAG_STAG_CTAG;
+ break;
+ default:
+ return NPC_ERR_PATTERN_NOTSUP;
+ }
+
+ return 0;
+}
+
+static int
+npc_update_vlan_parse_state(struct npc_parse_state *pst, const struct roc_npc_item_info *pattern,
+ int lid, int lt, uint8_t lflags, int vlan_count)
+{
+ uint8_t vlan_spec[NPC_MAX_SUPPORTED_VLANS * sizeof(struct roc_vlan_hdr)];
+ uint8_t vlan_mask[NPC_MAX_SUPPORTED_VLANS * sizeof(struct roc_vlan_hdr)];
+ int rc = 0, i, offset = NPC_TPID_LENGTH;
+ struct npc_parse_item_info parse_info;
+ char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
+
+ memset(vlan_spec, 0, sizeof(struct roc_vlan_hdr) * NPC_MAX_SUPPORTED_VLANS);
+ memset(vlan_mask, 0, sizeof(struct roc_vlan_hdr) * NPC_MAX_SUPPORTED_VLANS);
+ memset(&parse_info, 0, sizeof(parse_info));
+
+ if (vlan_count > 2)
+ vlan_count = 2;
+
+ for (i = 0; i < vlan_count; i++) {
+ if (pattern[i].spec)
+ memcpy(vlan_spec + offset, pattern[i].spec, sizeof(struct roc_vlan_hdr));
+ if (pattern[i].mask)
+ memcpy(vlan_mask + offset, pattern[i].mask, sizeof(struct roc_vlan_hdr));
+
+ offset += 4;
+ }
+
+ parse_info.def_mask = NULL;
+ parse_info.spec = vlan_spec;
+ parse_info.mask = vlan_mask;
+ parse_info.def_mask = NULL;
+ parse_info.hw_hdr_len = 0;
+
+ lid = NPC_LID_LB;
+ parse_info.hw_mask = hw_mask;
+
+ if (lt == NPC_LT_LB_CTAG)
+ parse_info.len = sizeof(struct roc_vlan_hdr) + NPC_TPID_LENGTH;
+
+ if (lt == NPC_LT_LB_STAG_QINQ)
+ parse_info.len = sizeof(struct roc_vlan_hdr) * 2 + NPC_TPID_LENGTH;
+
+ memset(hw_mask, 0, sizeof(hw_mask));
+
+ parse_info.hw_mask = &hw_mask;
+ npc_get_hw_supp_mask(pst, &parse_info, lid, lt);
+
+ rc = npc_mask_is_supported(parse_info.mask, parse_info.hw_mask, parse_info.len);
+ if (!rc)
+ return NPC_ERR_INVALID_MASK;
+
+ /* Point pattern to last item consumed */
+ pst->pattern = pattern;
+ return npc_update_parse_state(pst, &parse_info, lid, lt, lflags);
+}
+
+static int
+npc_parse_lb_vlan(struct npc_parse_state *pst)
+{
+ const struct roc_npc_flow_item_vlan *vlan_items[NPC_MAX_SUPPORTED_VLANS];
+ const struct roc_npc_item_info *pattern_list[NPC_MAX_SUPPORTED_VLANS];
+ const struct roc_npc_item_info *last_pattern;
+ int vlan_count = 0, rc = 0;
+ int lid, lt, lflags;
+
+ lid = NPC_LID_LB;
+ lflags = 0;
+ last_pattern = pst->pattern;
+
+ rc = npc_parse_vlan_count(pst->pattern, pattern_list, vlan_items, &vlan_count);
+ if (rc)
+ return rc;
+
+ rc = npc_parse_vlan_ltype_get(pst, vlan_items, vlan_count, <, &lflags);
+ if (rc)
+ return rc;
+
+ if (vlan_count == 1) {
+ return npc_update_vlan_parse_state(pst, pattern_list[0], lid, lt, lflags,
+ vlan_count);
+ } else if (vlan_count == 2) {
+ rc = npc_update_vlan_parse_state(pst, pattern_list[0], lid, lt, lflags, vlan_count);
+ if (rc)
+ return rc;
+
+ pst->pattern = last_pattern + 2;
+ } else if (vlan_count == 3) {
+ if (pattern_list[2]->spec != NULL && pattern_list[2]->mask != NULL &&
+ pattern_list[2]->last != NULL)
+ return NPC_ERR_PATTERN_NOTSUP;
+
+ rc = npc_update_vlan_parse_state(pst, pattern_list[0], lid, lt, lflags, 2);
+ if (rc)
+ return rc;
+
+ pst->pattern = last_pattern + 3;
+ }
+
+ return 0;
+}
+
int
npc_parse_lb(struct npc_parse_state *pst)
{
- const struct roc_npc_flow_item_vlan *vlan_item[NPC_MAX_SUPPORTED_VLANS];
const struct roc_npc_item_info *pattern = pst->pattern;
const struct roc_npc_item_info *last_pattern;
const struct roc_npc_flow_item_raw *raw_spec;
@@ -251,7 +430,6 @@ npc_parse_lb(struct npc_parse_state *pst)
char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt, lflags, len = 0;
- int nr_vlans = 0;
int rc;
info.def_mask = NULL;
@@ -268,68 +446,10 @@ npc_parse_lb(struct npc_parse_state *pst)
/* RTE vlan is either 802.1q or 802.1ad,
* this maps to either CTAG/STAG. We need to decide
* based on number of VLANS present. Matching is
- * supported on first tag only.
+ * supported on first two tags.
*/
- info.hw_mask = NULL;
- info.len = sizeof(vlan_item[0]->hdr);
-
- pattern = pst->pattern;
- while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
- if (nr_vlans > NPC_MAX_SUPPORTED_VLANS - 1)
- return NPC_ERR_PATTERN_NOTSUP;
-
- vlan_item[nr_vlans] = pattern->spec;
- nr_vlans++;
- /* Basic validation of Second/Third vlan item */
- if (nr_vlans > 1) {
- rc = npc_parse_item_basic(pattern, &info);
- if (rc != 0)
- return rc;
- }
- last_pattern = pattern;
- pattern++;
- pattern = npc_parse_skip_void_and_any_items(pattern);
- }
-
- switch (nr_vlans) {
- case 1:
- lt = NPC_LT_LB_CTAG;
- if (vlan_item[0] && vlan_item[0]->has_more_vlan)
- lt = NPC_LT_LB_STAG_QINQ;
- break;
- case 2:
- if (vlan_item[1] && vlan_item[1]->has_more_vlan) {
- if (!(pst->npc->keyx_supp_nmask[pst->nix_intf] &
- 0x3ULL << NPC_LFLAG_LB_OFFSET))
- return NPC_ERR_PATTERN_NOTSUP;
-
- /* This lflag value will match either one of
- * NPC_F_LB_L_WITH_STAG_STAG,
- * NPC_F_LB_L_WITH_QINQ_CTAG,
- * NPC_F_LB_L_WITH_QINQ_QINQ and
- * NPC_F_LB_L_WITH_ITAG (0b0100 to 0b0111). For
- * NPC_F_LB_L_WITH_ITAG, ltype is NPC_LT_LB_ETAG
- * hence will not match.
- */
-
- lflags = NPC_F_LB_L_WITH_QINQ_CTAG &
- NPC_F_LB_L_WITH_QINQ_QINQ &
- NPC_F_LB_L_WITH_STAG_STAG;
- } else {
- lflags = NPC_F_LB_L_WITH_CTAG;
- }
- lt = NPC_LT_LB_STAG_QINQ;
- break;
- case 3:
- if (vlan_item[2] && vlan_item[2]->has_more_vlan)
- return NPC_ERR_PATTERN_NOTSUP;
- lt = NPC_LT_LB_STAG_QINQ;
- lflags = NPC_F_STAG_STAG_CTAG;
- break;
- default:
- return NPC_ERR_PATTERN_NOTSUP;
- }
+ return npc_parse_lb_vlan(pst);
} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_E_TAG) {
/* we can support ETAG and match a subsequent CTAG
* without any matching support.
@@ -418,17 +418,15 @@ int npc_mcam_alloc_entry(struct npc *npc, struct roc_npc_flow *mcam,
int npc_mcam_alloc_entries(struct mbox *mbox, int ref_mcam, int *alloc_entry, int req_count,
int prio, int *resp_count, bool is_conti);
-int npc_mcam_ena_dis_entry(struct npc *npc, struct roc_npc_flow *mcam,
- bool enable);
+int npc_mcam_ena_dis_entry(struct npc *npc, struct roc_npc_flow *mcam, bool enable);
int npc_mcam_write_entry(struct mbox *mbox, struct roc_npc_flow *mcam);
int npc_flow_enable_all_entries(struct npc *npc, bool enable);
-int npc_update_parse_state(struct npc_parse_state *pst,
- struct npc_parse_item_info *info, int lid, int lt,
- uint8_t flags);
-void npc_get_hw_supp_mask(struct npc_parse_state *pst,
- struct npc_parse_item_info *info, int lid, int lt);
-int npc_parse_item_basic(const struct roc_npc_item_info *item,
- struct npc_parse_item_info *info);
+int npc_update_parse_state(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
+ int lt, uint8_t flags);
+void npc_get_hw_supp_mask(struct npc_parse_state *pst, struct npc_parse_item_info *info, int lid,
+ int lt);
+int npc_mask_is_supported(const char *mask, const char *hw_mask, int len);
+int npc_parse_item_basic(const struct roc_npc_item_info *item, struct npc_parse_item_info *info);
int npc_parse_meta_items(struct npc_parse_state *pst);
int npc_parse_mark_item(struct npc_parse_state *pst);
int npc_parse_pre_l2(struct npc_parse_state *pst);
@@ -88,7 +88,7 @@ npc_get_hw_supp_mask(struct npc_parse_state *pst,
}
}
-static inline int
+inline int
npc_mask_is_supported(const char *mask, const char *hw_mask, int len)
{
/*