common/cnxk: add NPC parsing API

Adding npc parsing API support to parse different patterns and actions.
Based on the pattern and actions ltype values will be chosen and
mcam data will be configured at perticular offsets.

Signed-off-by: Kiran Kumar K <kirankumark@marvell.com>
This commit is contained in:
Kiran Kumar K 2021-04-06 20:11:35 +05:30 committed by Jerin Jacob
parent f9af908074
commit c34ea71b87
3 changed files with 717 additions and 0 deletions

View File

@ -35,6 +35,7 @@ sources = files('roc_dev.c',
'roc_npa_debug.c',
'roc_npa_irq.c',
'roc_npc_mcam.c',
'roc_npc_parse.c',
'roc_npc_utils.c',
'roc_platform.c',
'roc_utils.c')

View File

@ -0,0 +1,703 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(C) 2021 Marvell.
*/
#include "roc_api.h"
#include "roc_priv.h"
const struct roc_npc_item_info *
npc_parse_skip_void_and_any_items(const struct roc_npc_item_info *pattern)
{
while ((pattern->type == ROC_NPC_ITEM_TYPE_VOID) ||
(pattern->type == ROC_NPC_ITEM_TYPE_ANY))
pattern++;
return pattern;
}
int
npc_parse_meta_items(struct npc_parse_state *pst)
{
PLT_SET_USED(pst);
return 0;
}
int
npc_parse_cpt_hdr(struct npc_parse_state *pst)
{
uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt;
int rc;
/* Identify the pattern type into lid, lt */
if (pst->pattern->type != ROC_NPC_ITEM_TYPE_CPT_HDR)
return 0;
lid = NPC_LID_LA;
lt = NPC_LT_LA_CPT_HDR;
info.hw_hdr_len = 0;
/* Prepare for parsing the item */
info.hw_mask = &hw_mask;
info.len = pst->pattern->size;
npc_get_hw_supp_mask(pst, &info, lid, lt);
info.spec = NULL;
info.mask = NULL;
/* Basic validation of item parameters */
rc = npc_parse_item_basic(pst->pattern, &info);
if (rc)
return rc;
/* Update pst if not validate only? clash check? */
return npc_update_parse_state(pst, &info, lid, lt, 0);
}
int
npc_parse_higig2_hdr(struct npc_parse_state *pst)
{
uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt;
int rc;
/* Identify the pattern type into lid, lt */
if (pst->pattern->type != ROC_NPC_ITEM_TYPE_HIGIG2)
return 0;
lid = NPC_LID_LA;
lt = NPC_LT_LA_HIGIG2_ETHER;
info.hw_hdr_len = 0;
if (pst->flow->nix_intf == NIX_INTF_TX) {
lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
info.hw_hdr_len = NPC_IH_LENGTH;
}
/* Prepare for parsing the item */
info.hw_mask = &hw_mask;
info.len = pst->pattern->size;
npc_get_hw_supp_mask(pst, &info, lid, lt);
info.spec = NULL;
info.mask = NULL;
/* Basic validation of item parameters */
rc = npc_parse_item_basic(pst->pattern, &info);
if (rc)
return rc;
/* Update pst if not validate only? clash check? */
return npc_update_parse_state(pst, &info, lid, lt, 0);
}
int
npc_parse_la(struct npc_parse_state *pst)
{
uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt;
int rc;
/* Identify the pattern type into lid, lt */
if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
return 0;
lid = NPC_LID_LA;
lt = NPC_LT_LA_ETHER;
info.hw_hdr_len = 0;
if (pst->flow->nix_intf == NIX_INTF_TX) {
lt = NPC_LT_LA_IH_NIX_ETHER;
info.hw_hdr_len = NPC_IH_LENGTH;
if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
lt = NPC_LT_LA_IH_NIX_HIGIG2_ETHER;
info.hw_hdr_len += NPC_HIGIG2_LENGTH;
}
} else {
if (pst->npc->switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
lt = NPC_LT_LA_HIGIG2_ETHER;
info.hw_hdr_len = NPC_HIGIG2_LENGTH;
}
}
/* Prepare for parsing the item */
info.hw_mask = &hw_mask;
info.len = pst->pattern->size;
npc_get_hw_supp_mask(pst, &info, lid, lt);
info.spec = NULL;
info.mask = NULL;
/* Basic validation of item parameters */
rc = npc_parse_item_basic(pst->pattern, &info);
if (rc)
return rc;
/* Update pst if not validate only? clash check? */
return npc_update_parse_state(pst, &info, lid, lt, 0);
}
int
npc_parse_lb(struct npc_parse_state *pst)
{
const struct roc_npc_item_info *pattern = pst->pattern;
const struct roc_npc_item_info *last_pattern;
char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt, lflags;
int nr_vlans = 0;
int rc;
info.spec = NULL;
info.mask = NULL;
info.def_mask = NULL;
info.hw_hdr_len = NPC_TPID_LENGTH;
lid = NPC_LID_LB;
lflags = 0;
last_pattern = pattern;
if (pst->pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
/* 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.
*/
info.hw_mask = NULL;
info.len = pst->pattern->size;
pattern = pst->pattern;
while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
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;
break;
case 2:
lt = NPC_LT_LB_STAG_QINQ;
lflags = NPC_F_STAG_CTAG;
break;
case 3:
lt = NPC_LT_LB_STAG_QINQ;
lflags = NPC_F_STAG_STAG_CTAG;
break;
default:
return NPC_ERR_PATTERN_NOTSUP;
}
} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_E_TAG) {
/* we can support ETAG and match a subsequent CTAG
* without any matching support.
*/
lt = NPC_LT_LB_ETAG;
lflags = 0;
last_pattern = pst->pattern;
pattern = npc_parse_skip_void_and_any_items(pst->pattern + 1);
if (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
/* set supported mask to NULL for vlan tag */
info.hw_mask = NULL;
info.len = pattern->size;
rc = npc_parse_item_basic(pattern, &info);
if (rc != 0)
return rc;
lflags = NPC_F_ETAG_CTAG;
last_pattern = pattern;
}
info.len = pattern->size;
} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_QINQ) {
info.hw_mask = NULL;
info.len = pst->pattern->size;
lt = NPC_LT_LB_STAG_QINQ;
lflags = NPC_F_STAG_CTAG;
} else {
return 0;
}
info.hw_mask = &hw_mask;
info.spec = NULL;
info.mask = NULL;
npc_get_hw_supp_mask(pst, &info, lid, lt);
rc = npc_parse_item_basic(pst->pattern, &info);
if (rc != 0)
return rc;
/* Point pattern to last item consumed */
pst->pattern = last_pattern;
return npc_update_parse_state(pst, &info, lid, lt, lflags);
}
static int
npc_parse_mpls_label_stack(struct npc_parse_state *pst, int *flag)
{
uint8_t flag_list[] = {0, NPC_F_MPLS_2_LABELS, NPC_F_MPLS_3_LABELS,
NPC_F_MPLS_4_LABELS};
const struct roc_npc_item_info *pattern = pst->pattern;
struct npc_parse_item_info info;
int nr_labels = 0;
int rc;
/*
* pst->pattern points to first MPLS label. We only check
* that subsequent labels do not have anything to match.
*/
info.hw_mask = NULL;
info.len = pattern->size;
info.spec = NULL;
info.mask = NULL;
info.hw_hdr_len = 0;
info.def_mask = NULL;
while (pattern->type == ROC_NPC_ITEM_TYPE_MPLS) {
nr_labels++;
/* Basic validation of Second/Third/Fourth mpls item */
if (nr_labels > 1) {
rc = npc_parse_item_basic(pattern, &info);
if (rc != 0)
return rc;
}
pst->last_pattern = pattern;
pattern++;
pattern = npc_parse_skip_void_and_any_items(pattern);
}
if (nr_labels < 1 || nr_labels > 4)
return NPC_ERR_PATTERN_NOTSUP;
*flag = flag_list[nr_labels - 1];
return 0;
}
static int
npc_parse_mpls(struct npc_parse_state *pst, int lid)
{
/* Find number of MPLS labels */
uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lt, lflags;
int rc;
lflags = 0;
if (lid == NPC_LID_LC)
lt = NPC_LT_LC_MPLS;
else if (lid == NPC_LID_LD)
lt = NPC_LT_LD_TU_MPLS_IN_IP;
else
lt = NPC_LT_LE_TU_MPLS_IN_UDP;
/* Prepare for parsing the first item */
info.hw_mask = &hw_mask;
info.len = pst->pattern->size;
info.spec = NULL;
info.mask = NULL;
info.hw_hdr_len = 0;
npc_get_hw_supp_mask(pst, &info, lid, lt);
rc = npc_parse_item_basic(pst->pattern, &info);
if (rc != 0)
return rc;
/*
* Parse for more labels.
* This sets lflags and pst->last_pattern correctly.
*/
rc = npc_parse_mpls_label_stack(pst, &lflags);
if (rc != 0)
return rc;
pst->tunnel = 1;
pst->pattern = pst->last_pattern;
return npc_update_parse_state(pst, &info, lid, lt, lflags);
}
static inline void
npc_check_lc_ip_tunnel(struct npc_parse_state *pst)
{
const struct roc_npc_item_info *pattern = pst->pattern + 1;
pattern = npc_parse_skip_void_and_any_items(pattern);
if (pattern->type == ROC_NPC_ITEM_TYPE_MPLS ||
pattern->type == ROC_NPC_ITEM_TYPE_IPV4 ||
pattern->type == ROC_NPC_ITEM_TYPE_IPV6)
pst->tunnel = 1;
}
int
npc_parse_lc(struct npc_parse_state *pst)
{
uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt;
int rc;
if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
return npc_parse_mpls(pst, NPC_LID_LC);
info.hw_mask = &hw_mask;
info.spec = NULL;
info.mask = NULL;
info.hw_hdr_len = 0;
lid = NPC_LID_LC;
switch (pst->pattern->type) {
case ROC_NPC_ITEM_TYPE_IPV4:
lt = NPC_LT_LC_IP;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_IPV6:
lid = NPC_LID_LC;
lt = NPC_LT_LC_IP6;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_ARP_ETH_IPV4:
lt = NPC_LT_LC_ARP;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_IPV6_EXT:
lid = NPC_LID_LC;
lt = NPC_LT_LC_IP6_EXT;
info.len = pst->pattern->size;
info.hw_hdr_len = 40;
break;
case ROC_NPC_ITEM_TYPE_L3_CUSTOM:
lt = NPC_LT_LC_CUSTOM0;
info.len = pst->pattern->size;
break;
default:
/* No match at this layer */
return 0;
}
/* Identify if IP tunnels MPLS or IPv4/v6 */
npc_check_lc_ip_tunnel(pst);
npc_get_hw_supp_mask(pst, &info, lid, lt);
rc = npc_parse_item_basic(pst->pattern, &info);
if (rc != 0)
return rc;
return npc_update_parse_state(pst, &info, lid, lt, 0);
}
int
npc_parse_ld(struct npc_parse_state *pst)
{
char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt, lflags;
int rc;
if (pst->tunnel) {
/* We have already parsed MPLS or IPv4/v6 followed
* by MPLS or IPv4/v6. Subsequent TCP/UDP etc
* would be parsed as tunneled versions. Skip
* this layer, except for tunneled MPLS. If LC is
* MPLS, we have anyway skipped all stacked MPLS
* labels.
*/
if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
return npc_parse_mpls(pst, NPC_LID_LD);
return 0;
}
info.hw_mask = &hw_mask;
info.spec = NULL;
info.mask = NULL;
info.def_mask = NULL;
info.len = 0;
info.hw_hdr_len = 0;
lid = NPC_LID_LD;
lflags = 0;
switch (pst->pattern->type) {
case ROC_NPC_ITEM_TYPE_ICMP:
if (pst->lt[NPC_LID_LC] == NPC_LT_LC_IP6)
lt = NPC_LT_LD_ICMP6;
else
lt = NPC_LT_LD_ICMP;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_UDP:
lt = NPC_LT_LD_UDP;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_IGMP:
lt = NPC_LT_LD_IGMP;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_TCP:
lt = NPC_LT_LD_TCP;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_SCTP:
lt = NPC_LT_LD_SCTP;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_GRE:
lt = NPC_LT_LD_GRE;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_GRE_KEY:
lt = NPC_LT_LD_GRE;
info.len = pst->pattern->size;
info.hw_hdr_len = 4;
break;
case ROC_NPC_ITEM_TYPE_NVGRE:
lt = NPC_LT_LD_NVGRE;
lflags = NPC_F_GRE_NVGRE;
info.len = pst->pattern->size;
/* Further IP/Ethernet are parsed as tunneled */
pst->tunnel = 1;
break;
default:
return 0;
}
npc_get_hw_supp_mask(pst, &info, lid, lt);
rc = npc_parse_item_basic(pst->pattern, &info);
if (rc != 0)
return rc;
return npc_update_parse_state(pst, &info, lid, lt, lflags);
}
int
npc_parse_le(struct npc_parse_state *pst)
{
const struct roc_npc_item_info *pattern = pst->pattern;
char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt, lflags;
int rc;
if (pst->tunnel)
return 0;
if (pst->pattern->type == ROC_NPC_ITEM_TYPE_MPLS)
return npc_parse_mpls(pst, NPC_LID_LE);
info.spec = NULL;
info.mask = NULL;
info.hw_mask = NULL;
info.def_mask = NULL;
info.len = 0;
info.hw_hdr_len = 0;
lid = NPC_LID_LE;
lflags = 0;
/* Ensure we are not matching anything in UDP */
rc = npc_parse_item_basic(pattern, &info);
if (rc)
return rc;
info.hw_mask = &hw_mask;
pattern = npc_parse_skip_void_and_any_items(pattern);
switch (pattern->type) {
case ROC_NPC_ITEM_TYPE_VXLAN:
lflags = NPC_F_UDP_VXLAN;
info.len = pattern->size;
lt = NPC_LT_LE_VXLAN;
break;
case ROC_NPC_ITEM_TYPE_GTPC:
lflags = NPC_F_UDP_GTP_GTPC;
info.len = pattern->size;
lt = NPC_LT_LE_GTPC;
break;
case ROC_NPC_ITEM_TYPE_GTPU:
lflags = NPC_F_UDP_GTP_GTPU_G_PDU;
info.len = pattern->size;
lt = NPC_LT_LE_GTPU;
break;
case ROC_NPC_ITEM_TYPE_GENEVE:
lflags = NPC_F_UDP_GENEVE;
info.len = pattern->size;
lt = NPC_LT_LE_GENEVE;
break;
case ROC_NPC_ITEM_TYPE_VXLAN_GPE:
lflags = NPC_F_UDP_VXLANGPE;
info.len = pattern->size;
lt = NPC_LT_LE_VXLANGPE;
break;
case ROC_NPC_ITEM_TYPE_ESP:
lt = NPC_LT_LE_ESP;
info.len = pst->pattern->size;
break;
default:
return 0;
}
pst->tunnel = 1;
npc_get_hw_supp_mask(pst, &info, lid, lt);
rc = npc_parse_item_basic(pattern, &info);
if (rc != 0)
return rc;
return npc_update_parse_state(pst, &info, lid, lt, lflags);
}
int
npc_parse_lf(struct npc_parse_state *pst)
{
const struct roc_npc_item_info *pattern, *last_pattern;
char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt, lflags;
int nr_vlans = 0;
int rc;
/* We hit this layer if there is a tunneling protocol */
if (!pst->tunnel)
return 0;
if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
return 0;
lid = NPC_LID_LF;
lt = NPC_LT_LF_TU_ETHER;
lflags = 0;
/* No match support for vlan tags */
info.hw_mask = NULL;
info.len = pst->pattern->size;
info.spec = NULL;
info.mask = NULL;
info.hw_hdr_len = 0;
/* Look ahead and find out any VLAN tags. These can be
* detected but no data matching is available.
*/
last_pattern = pst->pattern;
pattern = pst->pattern + 1;
pattern = npc_parse_skip_void_and_any_items(pattern);
while (pattern->type == ROC_NPC_ITEM_TYPE_VLAN) {
nr_vlans++;
last_pattern = pattern;
pattern++;
pattern = npc_parse_skip_void_and_any_items(pattern);
}
switch (nr_vlans) {
case 0:
break;
case 1:
lflags = NPC_F_TU_ETHER_CTAG;
break;
case 2:
lflags = NPC_F_TU_ETHER_STAG_CTAG;
break;
default:
return NPC_ERR_PATTERN_NOTSUP;
}
info.hw_mask = &hw_mask;
info.len = pst->pattern->size;
info.hw_hdr_len = 0;
npc_get_hw_supp_mask(pst, &info, lid, lt);
info.spec = NULL;
info.mask = NULL;
rc = npc_parse_item_basic(pst->pattern, &info);
if (rc != 0)
return rc;
pst->pattern = last_pattern;
return npc_update_parse_state(pst, &info, lid, lt, lflags);
}
int
npc_parse_lg(struct npc_parse_state *pst)
{
char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt;
int rc;
if (!pst->tunnel)
return 0;
info.hw_mask = &hw_mask;
info.spec = NULL;
info.mask = NULL;
info.hw_hdr_len = 0;
lid = NPC_LID_LG;
if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV4) {
lt = NPC_LT_LG_TU_IP;
info.len = pst->pattern->size;
} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_IPV6) {
lt = NPC_LT_LG_TU_IP6;
info.len = pst->pattern->size;
} else {
/* There is no tunneled IP header */
return 0;
}
npc_get_hw_supp_mask(pst, &info, lid, lt);
rc = npc_parse_item_basic(pst->pattern, &info);
if (rc != 0)
return rc;
return npc_update_parse_state(pst, &info, lid, lt, 0);
}
int
npc_parse_lh(struct npc_parse_state *pst)
{
char hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt;
int rc;
if (!pst->tunnel)
return 0;
info.hw_mask = &hw_mask;
info.spec = NULL;
info.mask = NULL;
info.hw_hdr_len = 0;
lid = NPC_LID_LH;
switch (pst->pattern->type) {
case ROC_NPC_ITEM_TYPE_UDP:
lt = NPC_LT_LH_TU_UDP;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_TCP:
lt = NPC_LT_LH_TU_TCP;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_SCTP:
lt = NPC_LT_LH_TU_SCTP;
info.len = pst->pattern->size;
break;
case ROC_NPC_ITEM_TYPE_ESP:
lt = NPC_LT_LH_TU_ESP;
info.len = pst->pattern->size;
break;
default:
return 0;
}
npc_get_hw_supp_mask(pst, &info, lid, lt);
rc = npc_parse_item_basic(pst->pattern, &info);
if (rc != 0)
return rc;
return npc_update_parse_state(pst, &info, lid, lt, 0);
}

View File

@ -402,11 +402,24 @@ 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_parse_meta_items(struct npc_parse_state *pst);
int npc_parse_higig2_hdr(struct npc_parse_state *pst);
int npc_parse_cpt_hdr(struct npc_parse_state *pst);
int npc_parse_la(struct npc_parse_state *pst);
int npc_parse_lb(struct npc_parse_state *pst);
int npc_parse_lc(struct npc_parse_state *pst);
int npc_parse_ld(struct npc_parse_state *pst);
int npc_parse_le(struct npc_parse_state *pst);
int npc_parse_lf(struct npc_parse_state *pst);
int npc_parse_lg(struct npc_parse_state *pst);
int npc_parse_lh(struct npc_parse_state *pst);
int npc_mcam_fetch_kex_cfg(struct npc *npc);
int npc_check_preallocated_entry_cache(struct mbox *mbox,
struct roc_npc_flow *flow,
struct npc *npc);
int npc_flow_free_all_resources(struct npc *npc);
const struct roc_npc_item_info *
npc_parse_skip_void_and_any_items(const struct roc_npc_item_info *pattern);
int npc_program_mcam(struct npc *npc, struct npc_parse_state *pst,
bool mcam_alloc);
uint64_t npc_get_kex_capability(struct npc *npc);