const uint8_t *pattern; /**< Byte string to look for. */
};
+struct roc_ether_addr {
+ uint8_t addr_bytes[PLT_ETHER_ADDR_LEN]; /**< Addr bytes in tx order */
+} plt_aligned(2);
+
+struct roc_ether_hdr {
+ struct roc_ether_addr d_addr; /**< Destination address. */
+ PLT_STD_C11
+ union {
+ struct roc_ether_addr s_addr; /**< Source address. */
+ struct {
+ struct roc_ether_addr S_addr;
+ } S_un; /**< Do not use directly; use s_addr instead.*/
+ };
+ uint16_t ether_type; /**< Frame type. */
+} plt_aligned(2);
+
+PLT_STD_C11
+struct roc_npc_flow_item_eth {
+ union {
+ struct {
+ /*
+ * These fields are retained
+ * for compatibility.
+ * Please switch to the new header field below.
+ */
+ struct roc_ether_addr dst; /**< Destination MAC. */
+ struct roc_ether_addr src; /**< Source MAC. */
+ uint16_t type; /**< EtherType or TPID. */
+ };
+ struct roc_ether_hdr hdr;
+ };
+ uint32_t has_vlan : 1; /**< Packet header contains at least one VLAN. */
+ uint32_t reserved : 31; /**< Reserved, must be zero. */
+};
+
+struct roc_vlan_hdr {
+ uint16_t vlan_tci; /**< Priority (3) + CFI (1) + Identifier Code (12) */
+ uint16_t eth_proto; /**< Ethernet type of encapsulated frame. */
+} __plt_packed;
+
+PLT_STD_C11
+struct roc_npc_flow_item_vlan {
+ union {
+ struct {
+ uint16_t tci; /**< Tag control information. */
+ uint16_t inner_type; /**< Inner EtherType or TPID. */
+ };
+ struct roc_vlan_hdr hdr;
+ };
+ uint32_t has_more_vlan : 1;
+ /**< Packet header contains at least one more VLAN, after this VLAN. */
+ uint32_t reserved : 31; /**< Reserved, must be zero. */
+};
+
#define ROC_NPC_MAX_ACTION_COUNT 19
enum roc_npc_action_type {
};
struct roc_npc_action_port_id {
- uint32_t original : 1; /**< Use original DPDK port ID if possible. */
+ uint32_t original : 1; /**< Use original port ID if possible. */
uint32_t reserved : 31; /**< Reserved, must be zero. */
uint32_t id; /**< port ID. */
};
return 0;
}
+static void
+npc_set_vlan_ltype(struct npc_parse_state *pst)
+{
+ uint64_t val, mask;
+ uint8_t lb_offset;
+
+ lb_offset =
+ __builtin_popcount(pst->npc->keyx_supp_nmask[pst->nix_intf] &
+ ((1ULL << NPC_LTYPE_LB_OFFSET) - 1));
+ lb_offset *= 4;
+
+ mask = ~((0xfULL << lb_offset));
+ pst->flow->mcam_data[0] &= mask;
+ pst->flow->mcam_mask[0] &= mask;
+ /* NPC_LT_LB_CTAG: 0b0010, NPC_LT_LB_STAG_QINQ: 0b0011
+ * Set LB layertype/mask as 0b0010/0b1110 to match both.
+ */
+ val = ((uint64_t)(NPC_LT_LB_CTAG & NPC_LT_LB_STAG_QINQ)) << lb_offset;
+ pst->flow->mcam_data[0] |= val;
+ pst->flow->mcam_mask[0] |= (0xeULL << lb_offset);
+}
+
int
npc_program_mcam(struct npc *npc, struct npc_parse_state *pst, bool mcam_alloc)
{
if (layer_info) {
for (idx = 0; idx <= 2; idx++) {
if (layer_info & (1 << idx)) {
- if (idx == 2)
+ if (idx == 2) {
data = lt;
- else if (idx == 1)
+ mask = 0xf;
+ } else if (idx == 1) {
data = ((flags >> 4) & 0xf);
- else
+ mask = ((flags >> 4) & 0xf);
+ } else {
data = (flags & 0xf);
+ mask = (flags & 0xf);
+ }
if (data_off >= 64) {
data_off = 0;
}
key_data[index] |=
((uint64_t)data << data_off);
- mask = 0xf;
+
if (lt == 0)
mask = 0;
key_mask[index] |=
memcpy(pst->flow->mcam_data, key_data, key_len);
memcpy(pst->flow->mcam_mask, key_mask, key_len);
+ if (pst->set_vlan_ltype_mask)
+ npc_set_vlan_ltype(pst);
+
if (pst->is_vf) {
(void)mbox_alloc_msg_npc_read_base_steer_rule(npc->mbox);
rc = mbox_process_msg(npc->mbox, (void *)&base_rule_rsp);
int
npc_parse_la(struct npc_parse_state *pst)
{
+ const struct roc_npc_flow_item_eth *eth_item;
uint8_t hw_mask[NPC_MAX_EXTRACT_HW_LEN];
struct npc_parse_item_info info;
int lid, lt;
if (pst->pattern->type != ROC_NPC_ITEM_TYPE_ETH)
return 0;
+ eth_item = pst->pattern->spec;
+
lid = NPC_LID_LA;
lt = NPC_LT_LA_ETHER;
info.hw_hdr_len = 0;
/* Prepare for parsing the item */
info.hw_mask = &hw_mask;
- info.len = pst->pattern->size;
+ info.len = sizeof(eth_item->hdr);
npc_get_hw_supp_mask(pst, &info, lid, lt);
info.spec = NULL;
info.mask = NULL;
if (rc)
return rc;
- /* Update pst if not validate only? clash check? */
- return npc_update_parse_state(pst, &info, lid, lt, 0);
+ rc = npc_update_parse_state(pst, &info, lid, lt, 0);
+ if (rc)
+ return rc;
+
+ if (eth_item && eth_item->has_vlan)
+ pst->set_vlan_ltype_mask = true;
+
+ return 0;
}
+#define NPC_MAX_SUPPORTED_VLANS 3
+
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;
* supported on first tag only.
*/
info.hw_mask = NULL;
- info.len = pst->pattern->size;
+ 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 */
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;
- lflags = NPC_F_STAG_CTAG;
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;
}
info.len = pattern->size;
} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_QINQ) {
+ vlan_item[0] = pst->pattern->spec;
info.hw_mask = NULL;
- info.len = pst->pattern->size;
+ info.len = sizeof(vlan_item[0]->hdr);
lt = NPC_LT_LB_STAG_QINQ;
lflags = NPC_F_STAG_CTAG;
+ if (vlan_item[0] && vlan_item[0]->has_more_vlan) {
+ lflags = NPC_F_LB_L_WITH_QINQ_CTAG &
+ NPC_F_LB_L_WITH_QINQ_QINQ;
+ }
} else if (pst->pattern->type == ROC_NPC_ITEM_TYPE_RAW) {
raw_spec = pst->pattern->spec;
if (raw_spec->relative)
#define NPC_ACTION_MAX_VLAN_PARAMS 3
#define NPC_ACTION_MAX_VLANS_STRIPPED 2
+#define NPC_LTYPE_OFFSET_START 7
+/* LB OFFSET : START + LA (2b flags + 1b ltype) + LB (2b flags) */
+#define NPC_LTYPE_LB_OFFSET (NPC_LTYPE_OFFSET_START + 5)
+#define NPC_LFLAG_LB_OFFSET (NPC_LTYPE_OFFSET_START + 3)
+
struct npc_action_vtag_info {
uint16_t vlan_id;
uint16_t vlan_ethtype;
uint8_t *mcam_data; /* point to flow->mcam_data + key_len */
uint8_t *mcam_mask; /* point to flow->mcam_mask + key_len */
bool is_vf;
+ /* adjust ltype in MCAM to match at least one vlan */
+ bool set_vlan_ltype_mask;
};
enum npc_kpu_parser_flag {
#include <rte_byteorder.h>
#include <rte_common.h>
#include <rte_cycles.h>
+#include <rte_ether.h>
#include <rte_interrupts.h>
#include <rte_io.h>
#include <rte_log.h>
#define PLT_ALIGN_CEIL RTE_ALIGN_CEIL
#define PLT_INIT RTE_INIT
+#ifndef PLT_ETHER_ADDR_LEN
+#define PLT_ETHER_ADDR_LEN RTE_ETHER_ADDR_LEN
+#endif
/** Divide ceil */
#define PLT_DIV_CEIL(x, y) \
({ \
#define plt_cpu_to_be_64 rte_cpu_to_be_64
#define plt_be_to_cpu_64 rte_be_to_cpu_64
+#define plt_aligned __rte_aligned
#define plt_align32pow2 rte_align32pow2
#define plt_align32prevpow2 rte_align32prevpow2