Commit 2cee6401 authored by Suman Ghosh's avatar Suman Ghosh Committed by Jakub Kicinski

octeontx2-af: Allow mkex profile without DMAC and add L2M/L2B header extraction support

1. It is possible to have custom mkex profiles which do not extract
DMAC at all into the key. Hence allow mkex profiles which do not
have DMAC to be loaded into MCAM hardware. This patch also adds
debugging prints needed to identify profiles with wrong
configuration.

2. If a mkex profile set "l2l3mb" field for Rx interface,
then Rx multicast and broadcast entry should be configured.
Signed-off-by: default avatarSuman Ghosh <sumang@marvell.com>
Link: https://lore.kernel.org/r/20221031090856.1404303-1-sumang@marvell.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent b54a0d40
...@@ -620,6 +620,7 @@ struct rvu_npc_mcam_rule { ...@@ -620,6 +620,7 @@ struct rvu_npc_mcam_rule {
bool vfvlan_cfg; bool vfvlan_cfg;
u16 chan; u16 chan;
u16 chan_mask; u16 chan_mask;
u8 lxmb;
}; };
#endif /* NPC_H */ #endif /* NPC_H */
...@@ -2756,6 +2756,12 @@ static void rvu_dbg_npc_mcam_show_flows(struct seq_file *s, ...@@ -2756,6 +2756,12 @@ static void rvu_dbg_npc_mcam_show_flows(struct seq_file *s,
for_each_set_bit(bit, (unsigned long *)&rule->features, 64) { for_each_set_bit(bit, (unsigned long *)&rule->features, 64) {
seq_printf(s, "\t%s ", npc_get_field_name(bit)); seq_printf(s, "\t%s ", npc_get_field_name(bit));
switch (bit) { switch (bit) {
case NPC_LXMB:
if (rule->lxmb == 1)
seq_puts(s, "\tL2M nibble is set\n");
else
seq_puts(s, "\tL2B nibble is set\n");
break;
case NPC_DMAC: case NPC_DMAC:
seq_printf(s, "%pM ", rule->packet.dmac); seq_printf(s, "%pM ", rule->packet.dmac);
seq_printf(s, "mask %pM\n", rule->mask.dmac); seq_printf(s, "mask %pM\n", rule->mask.dmac);
......
...@@ -43,6 +43,7 @@ static const char * const npc_flow_names[] = { ...@@ -43,6 +43,7 @@ static const char * const npc_flow_names[] = {
[NPC_DPORT_UDP] = "udp destination port", [NPC_DPORT_UDP] = "udp destination port",
[NPC_SPORT_SCTP] = "sctp source port", [NPC_SPORT_SCTP] = "sctp source port",
[NPC_DPORT_SCTP] = "sctp destination port", [NPC_DPORT_SCTP] = "sctp destination port",
[NPC_LXMB] = "Mcast/Bcast header ",
[NPC_UNKNOWN] = "unknown", [NPC_UNKNOWN] = "unknown",
}; };
...@@ -340,8 +341,10 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf) ...@@ -340,8 +341,10 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
vlan_tag2 = &key_fields[NPC_VLAN_TAG2]; vlan_tag2 = &key_fields[NPC_VLAN_TAG2];
/* if key profile programmed does not extract Ethertype at all */ /* if key profile programmed does not extract Ethertype at all */
if (!etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws) if (!etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws) {
dev_err(rvu->dev, "mkex: Ethertype is not extracted.\n");
goto vlan_tci; goto vlan_tci;
}
/* if key profile programmed extracts Ethertype from one layer */ /* if key profile programmed extracts Ethertype from one layer */
if (etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws) if (etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws)
...@@ -354,35 +357,45 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf) ...@@ -354,35 +357,45 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
/* if key profile programmed extracts Ethertype from multiple layers */ /* if key profile programmed extracts Ethertype from multiple layers */
if (etype_ether->nr_kws && etype_tag1->nr_kws) { if (etype_ether->nr_kws && etype_tag1->nr_kws) {
for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) { for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
if (etype_ether->kw_mask[i] != etype_tag1->kw_mask[i]) if (etype_ether->kw_mask[i] != etype_tag1->kw_mask[i]) {
dev_err(rvu->dev, "mkex: Etype pos is different for untagged and tagged pkts.\n");
goto vlan_tci; goto vlan_tci;
}
} }
key_fields[NPC_ETYPE] = *etype_tag1; key_fields[NPC_ETYPE] = *etype_tag1;
} }
if (etype_ether->nr_kws && etype_tag2->nr_kws) { if (etype_ether->nr_kws && etype_tag2->nr_kws) {
for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) { for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
if (etype_ether->kw_mask[i] != etype_tag2->kw_mask[i]) if (etype_ether->kw_mask[i] != etype_tag2->kw_mask[i]) {
dev_err(rvu->dev, "mkex: Etype pos is different for untagged and double tagged pkts.\n");
goto vlan_tci; goto vlan_tci;
}
} }
key_fields[NPC_ETYPE] = *etype_tag2; key_fields[NPC_ETYPE] = *etype_tag2;
} }
if (etype_tag1->nr_kws && etype_tag2->nr_kws) { if (etype_tag1->nr_kws && etype_tag2->nr_kws) {
for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) { for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
if (etype_tag1->kw_mask[i] != etype_tag2->kw_mask[i]) if (etype_tag1->kw_mask[i] != etype_tag2->kw_mask[i]) {
dev_err(rvu->dev, "mkex: Etype pos is different for tagged and double tagged pkts.\n");
goto vlan_tci; goto vlan_tci;
}
} }
key_fields[NPC_ETYPE] = *etype_tag2; key_fields[NPC_ETYPE] = *etype_tag2;
} }
/* check none of higher layers overwrite Ethertype */ /* check none of higher layers overwrite Ethertype */
start_lid = key_fields[NPC_ETYPE].layer_mdata.lid + 1; start_lid = key_fields[NPC_ETYPE].layer_mdata.lid + 1;
if (npc_check_overlap(rvu, blkaddr, NPC_ETYPE, start_lid, intf)) if (npc_check_overlap(rvu, blkaddr, NPC_ETYPE, start_lid, intf)) {
dev_err(rvu->dev, "mkex: Ethertype is overwritten by higher layers.\n");
goto vlan_tci; goto vlan_tci;
}
*features |= BIT_ULL(NPC_ETYPE); *features |= BIT_ULL(NPC_ETYPE);
vlan_tci: vlan_tci:
/* if key profile does not extract outer vlan tci at all */ /* if key profile does not extract outer vlan tci at all */
if (!vlan_tag1->nr_kws && !vlan_tag2->nr_kws) if (!vlan_tag1->nr_kws && !vlan_tag2->nr_kws) {
dev_err(rvu->dev, "mkex: Outer vlan tci is not extracted.\n");
goto done; goto done;
}
/* if key profile extracts outer vlan tci from one layer */ /* if key profile extracts outer vlan tci from one layer */
if (vlan_tag1->nr_kws && !vlan_tag2->nr_kws) if (vlan_tag1->nr_kws && !vlan_tag2->nr_kws)
...@@ -393,15 +406,19 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf) ...@@ -393,15 +406,19 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
/* if key profile extracts outer vlan tci from multiple layers */ /* if key profile extracts outer vlan tci from multiple layers */
if (vlan_tag1->nr_kws && vlan_tag2->nr_kws) { if (vlan_tag1->nr_kws && vlan_tag2->nr_kws) {
for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) { for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
if (vlan_tag1->kw_mask[i] != vlan_tag2->kw_mask[i]) if (vlan_tag1->kw_mask[i] != vlan_tag2->kw_mask[i]) {
dev_err(rvu->dev, "mkex: Out vlan tci pos is different for tagged and double tagged pkts.\n");
goto done; goto done;
}
} }
key_fields[NPC_OUTER_VID] = *vlan_tag2; key_fields[NPC_OUTER_VID] = *vlan_tag2;
} }
/* check none of higher layers overwrite outer vlan tci */ /* check none of higher layers overwrite outer vlan tci */
start_lid = key_fields[NPC_OUTER_VID].layer_mdata.lid + 1; start_lid = key_fields[NPC_OUTER_VID].layer_mdata.lid + 1;
if (npc_check_overlap(rvu, blkaddr, NPC_OUTER_VID, start_lid, intf)) if (npc_check_overlap(rvu, blkaddr, NPC_OUTER_VID, start_lid, intf)) {
dev_err(rvu->dev, "mkex: Outer vlan tci is overwritten by higher layers.\n");
goto done; goto done;
}
*features |= BIT_ULL(NPC_OUTER_VID); *features |= BIT_ULL(NPC_OUTER_VID);
done: done:
return; return;
...@@ -522,6 +539,10 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf) ...@@ -522,6 +539,10 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf)
if (npc_check_field(rvu, blkaddr, NPC_LB, intf)) if (npc_check_field(rvu, blkaddr, NPC_LB, intf))
*features |= BIT_ULL(NPC_VLAN_ETYPE_CTAG) | *features |= BIT_ULL(NPC_VLAN_ETYPE_CTAG) |
BIT_ULL(NPC_VLAN_ETYPE_STAG); BIT_ULL(NPC_VLAN_ETYPE_STAG);
/* for L2M/L2B/L3M/L3B, check if the type is present in the key */
if (npc_check_field(rvu, blkaddr, NPC_LXMB, intf))
*features |= BIT_ULL(NPC_LXMB);
} }
/* Scan key extraction profile and record how fields of our interest /* Scan key extraction profile and record how fields of our interest
...@@ -599,16 +620,6 @@ static int npc_scan_verify_kex(struct rvu *rvu, int blkaddr) ...@@ -599,16 +620,6 @@ static int npc_scan_verify_kex(struct rvu *rvu, int blkaddr)
dev_err(rvu->dev, "Channel cannot be overwritten\n"); dev_err(rvu->dev, "Channel cannot be overwritten\n");
return -EINVAL; return -EINVAL;
} }
/* DMAC should be present in key for unicast filter to work */
if (!npc_is_field_present(rvu, NPC_DMAC, NIX_INTF_RX)) {
dev_err(rvu->dev, "DMAC not present in Key\n");
return -EINVAL;
}
/* check that none of the fields overwrite DMAC */
if (npc_check_overlap(rvu, blkaddr, NPC_DMAC, 0, NIX_INTF_RX)) {
dev_err(rvu->dev, "DMAC cannot be overwritten\n");
return -EINVAL;
}
npc_set_features(rvu, blkaddr, NIX_INTF_TX); npc_set_features(rvu, blkaddr, NIX_INTF_TX);
npc_set_features(rvu, blkaddr, NIX_INTF_RX); npc_set_features(rvu, blkaddr, NIX_INTF_RX);
...@@ -851,6 +862,11 @@ static void npc_update_flow(struct rvu *rvu, struct mcam_entry *entry, ...@@ -851,6 +862,11 @@ static void npc_update_flow(struct rvu *rvu, struct mcam_entry *entry,
npc_update_entry(rvu, NPC_LE, entry, NPC_LT_LE_ESP, npc_update_entry(rvu, NPC_LE, entry, NPC_LT_LE_ESP,
0, ~0ULL, 0, intf); 0, ~0ULL, 0, intf);
if (features & BIT_ULL(NPC_LXMB)) {
output->lxmb = is_broadcast_ether_addr(pkt->dmac) ? 2 : 1;
npc_update_entry(rvu, NPC_LXMB, entry, output->lxmb, 0,
output->lxmb, 0, intf);
}
#define NPC_WRITE_FLOW(field, member, val_lo, val_hi, mask_lo, mask_hi) \ #define NPC_WRITE_FLOW(field, member, val_lo, val_hi, mask_lo, mask_hi) \
do { \ do { \
if (features & BIT_ULL((field))) { \ if (features & BIT_ULL((field))) { \
...@@ -1153,6 +1169,7 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target, ...@@ -1153,6 +1169,7 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
rule->chan_mask = write_req.entry_data.kw_mask[0] & NPC_KEX_CHAN_MASK; rule->chan_mask = write_req.entry_data.kw_mask[0] & NPC_KEX_CHAN_MASK;
rule->chan = write_req.entry_data.kw[0] & NPC_KEX_CHAN_MASK; rule->chan = write_req.entry_data.kw[0] & NPC_KEX_CHAN_MASK;
rule->chan &= rule->chan_mask; rule->chan &= rule->chan_mask;
rule->lxmb = dummy.lxmb;
if (is_npc_intf_tx(req->intf)) if (is_npc_intf_tx(req->intf))
rule->intf = pfvf->nix_tx_intf; rule->intf = pfvf->nix_tx_intf;
else else
...@@ -1215,6 +1232,34 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu, ...@@ -1215,6 +1232,34 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
if (!is_npc_interface_valid(rvu, req->intf)) if (!is_npc_interface_valid(rvu, req->intf))
return NPC_FLOW_INTF_INVALID; return NPC_FLOW_INTF_INVALID;
/* If DMAC is not extracted in MKEX, rules installed by AF
* can rely on L2MB bit set by hardware protocol checker for
* broadcast and multicast addresses.
*/
if (npc_check_field(rvu, blkaddr, NPC_DMAC, req->intf))
goto process_flow;
if (is_pffunc_af(req->hdr.pcifunc)) {
if (is_unicast_ether_addr(req->packet.dmac)) {
dev_err(rvu->dev,
"%s: mkex profile does not support ucast flow\n",
__func__);
return NPC_FLOW_NOT_SUPPORTED;
}
if (!npc_is_field_present(rvu, NPC_LXMB, req->intf)) {
dev_err(rvu->dev,
"%s: mkex profile does not support bcast/mcast flow",
__func__);
return NPC_FLOW_NOT_SUPPORTED;
}
/* Modify feature to use LXMB instead of DMAC */
req->features &= ~BIT_ULL(NPC_DMAC);
req->features |= BIT_ULL(NPC_LXMB);
}
process_flow:
if (from_vf && req->default_rule) if (from_vf && req->default_rule)
return NPC_FLOW_VF_PERM_DENIED; return NPC_FLOW_VF_PERM_DENIED;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment