Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Suman Ghosh <sumang@marvell.com>
Link: https://lore.kernel.org/r/20221031090856.1404303-1-sumang@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Suman Ghosh and committed by
Jakub Kicinski
2cee6401 b54a0d40

+70 -18
+1
drivers/net/ethernet/marvell/octeontx2/af/npc.h
··· 620 620 bool vfvlan_cfg; 621 621 u16 chan; 622 622 u16 chan_mask; 623 + u8 lxmb; 623 624 }; 624 625 625 626 #endif /* NPC_H */
+6
drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
··· 2756 2756 for_each_set_bit(bit, (unsigned long *)&rule->features, 64) { 2757 2757 seq_printf(s, "\t%s ", npc_get_field_name(bit)); 2758 2758 switch (bit) { 2759 + case NPC_LXMB: 2760 + if (rule->lxmb == 1) 2761 + seq_puts(s, "\tL2M nibble is set\n"); 2762 + else 2763 + seq_puts(s, "\tL2B nibble is set\n"); 2764 + break; 2759 2765 case NPC_DMAC: 2760 2766 seq_printf(s, "%pM ", rule->packet.dmac); 2761 2767 seq_printf(s, "mask %pM\n", rule->mask.dmac);
+63 -18
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
··· 43 43 [NPC_DPORT_UDP] = "udp destination port", 44 44 [NPC_SPORT_SCTP] = "sctp source port", 45 45 [NPC_DPORT_SCTP] = "sctp destination port", 46 + [NPC_LXMB] = "Mcast/Bcast header ", 46 47 [NPC_UNKNOWN] = "unknown", 47 48 }; 48 49 ··· 341 340 vlan_tag2 = &key_fields[NPC_VLAN_TAG2]; 342 341 343 342 /* if key profile programmed does not extract Ethertype at all */ 344 - if (!etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws) 343 + if (!etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws) { 344 + dev_err(rvu->dev, "mkex: Ethertype is not extracted.\n"); 345 345 goto vlan_tci; 346 + } 346 347 347 348 /* if key profile programmed extracts Ethertype from one layer */ 348 349 if (etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws) ··· 357 354 /* if key profile programmed extracts Ethertype from multiple layers */ 358 355 if (etype_ether->nr_kws && etype_tag1->nr_kws) { 359 356 for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) { 360 - if (etype_ether->kw_mask[i] != etype_tag1->kw_mask[i]) 357 + if (etype_ether->kw_mask[i] != etype_tag1->kw_mask[i]) { 358 + dev_err(rvu->dev, "mkex: Etype pos is different for untagged and tagged pkts.\n"); 361 359 goto vlan_tci; 360 + } 362 361 } 363 362 key_fields[NPC_ETYPE] = *etype_tag1; 364 363 } 365 364 if (etype_ether->nr_kws && etype_tag2->nr_kws) { 366 365 for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) { 367 - if (etype_ether->kw_mask[i] != etype_tag2->kw_mask[i]) 366 + if (etype_ether->kw_mask[i] != etype_tag2->kw_mask[i]) { 367 + dev_err(rvu->dev, "mkex: Etype pos is different for untagged and double tagged pkts.\n"); 368 368 goto vlan_tci; 369 + } 369 370 } 370 371 key_fields[NPC_ETYPE] = *etype_tag2; 371 372 } 372 373 if (etype_tag1->nr_kws && etype_tag2->nr_kws) { 373 374 for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) { 374 - if (etype_tag1->kw_mask[i] != etype_tag2->kw_mask[i]) 375 + if (etype_tag1->kw_mask[i] != etype_tag2->kw_mask[i]) { 376 + dev_err(rvu->dev, "mkex: Etype pos is different for tagged and double tagged pkts.\n"); 375 377 goto vlan_tci; 378 + } 376 379 } 377 380 key_fields[NPC_ETYPE] = *etype_tag2; 378 381 } 379 382 380 383 /* check none of higher layers overwrite Ethertype */ 381 384 start_lid = key_fields[NPC_ETYPE].layer_mdata.lid + 1; 382 - if (npc_check_overlap(rvu, blkaddr, NPC_ETYPE, start_lid, intf)) 385 + if (npc_check_overlap(rvu, blkaddr, NPC_ETYPE, start_lid, intf)) { 386 + dev_err(rvu->dev, "mkex: Ethertype is overwritten by higher layers.\n"); 383 387 goto vlan_tci; 388 + } 384 389 *features |= BIT_ULL(NPC_ETYPE); 385 390 vlan_tci: 386 391 /* if key profile does not extract outer vlan tci at all */ 387 - if (!vlan_tag1->nr_kws && !vlan_tag2->nr_kws) 392 + if (!vlan_tag1->nr_kws && !vlan_tag2->nr_kws) { 393 + dev_err(rvu->dev, "mkex: Outer vlan tci is not extracted.\n"); 388 394 goto done; 395 + } 389 396 390 397 /* if key profile extracts outer vlan tci from one layer */ 391 398 if (vlan_tag1->nr_kws && !vlan_tag2->nr_kws) ··· 406 393 /* if key profile extracts outer vlan tci from multiple layers */ 407 394 if (vlan_tag1->nr_kws && vlan_tag2->nr_kws) { 408 395 for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) { 409 - if (vlan_tag1->kw_mask[i] != vlan_tag2->kw_mask[i]) 396 + if (vlan_tag1->kw_mask[i] != vlan_tag2->kw_mask[i]) { 397 + dev_err(rvu->dev, "mkex: Out vlan tci pos is different for tagged and double tagged pkts.\n"); 410 398 goto done; 399 + } 411 400 } 412 401 key_fields[NPC_OUTER_VID] = *vlan_tag2; 413 402 } 414 403 /* check none of higher layers overwrite outer vlan tci */ 415 404 start_lid = key_fields[NPC_OUTER_VID].layer_mdata.lid + 1; 416 - if (npc_check_overlap(rvu, blkaddr, NPC_OUTER_VID, start_lid, intf)) 405 + if (npc_check_overlap(rvu, blkaddr, NPC_OUTER_VID, start_lid, intf)) { 406 + dev_err(rvu->dev, "mkex: Outer vlan tci is overwritten by higher layers.\n"); 417 407 goto done; 408 + } 418 409 *features |= BIT_ULL(NPC_OUTER_VID); 419 410 done: 420 411 return; ··· 539 522 if (npc_check_field(rvu, blkaddr, NPC_LB, intf)) 540 523 *features |= BIT_ULL(NPC_VLAN_ETYPE_CTAG) | 541 524 BIT_ULL(NPC_VLAN_ETYPE_STAG); 525 + 526 + /* for L2M/L2B/L3M/L3B, check if the type is present in the key */ 527 + if (npc_check_field(rvu, blkaddr, NPC_LXMB, intf)) 528 + *features |= BIT_ULL(NPC_LXMB); 542 529 } 543 530 544 531 /* Scan key extraction profile and record how fields of our interest ··· 618 597 /* check that none of the fields overwrite channel */ 619 598 if (npc_check_overlap(rvu, blkaddr, NPC_CHAN, 0, NIX_INTF_RX)) { 620 599 dev_err(rvu->dev, "Channel cannot be overwritten\n"); 621 - return -EINVAL; 622 - } 623 - /* DMAC should be present in key for unicast filter to work */ 624 - if (!npc_is_field_present(rvu, NPC_DMAC, NIX_INTF_RX)) { 625 - dev_err(rvu->dev, "DMAC not present in Key\n"); 626 - return -EINVAL; 627 - } 628 - /* check that none of the fields overwrite DMAC */ 629 - if (npc_check_overlap(rvu, blkaddr, NPC_DMAC, 0, NIX_INTF_RX)) { 630 - dev_err(rvu->dev, "DMAC cannot be overwritten\n"); 631 600 return -EINVAL; 632 601 } 633 602 ··· 862 851 npc_update_entry(rvu, NPC_LE, entry, NPC_LT_LE_ESP, 863 852 0, ~0ULL, 0, intf); 864 853 854 + if (features & BIT_ULL(NPC_LXMB)) { 855 + output->lxmb = is_broadcast_ether_addr(pkt->dmac) ? 2 : 1; 856 + npc_update_entry(rvu, NPC_LXMB, entry, output->lxmb, 0, 857 + output->lxmb, 0, intf); 858 + } 865 859 #define NPC_WRITE_FLOW(field, member, val_lo, val_hi, mask_lo, mask_hi) \ 866 860 do { \ 867 861 if (features & BIT_ULL((field))) { \ ··· 1169 1153 rule->chan_mask = write_req.entry_data.kw_mask[0] & NPC_KEX_CHAN_MASK; 1170 1154 rule->chan = write_req.entry_data.kw[0] & NPC_KEX_CHAN_MASK; 1171 1155 rule->chan &= rule->chan_mask; 1156 + rule->lxmb = dummy.lxmb; 1172 1157 if (is_npc_intf_tx(req->intf)) 1173 1158 rule->intf = pfvf->nix_tx_intf; 1174 1159 else ··· 1232 1215 if (!is_npc_interface_valid(rvu, req->intf)) 1233 1216 return NPC_FLOW_INTF_INVALID; 1234 1217 1218 + /* If DMAC is not extracted in MKEX, rules installed by AF 1219 + * can rely on L2MB bit set by hardware protocol checker for 1220 + * broadcast and multicast addresses. 1221 + */ 1222 + if (npc_check_field(rvu, blkaddr, NPC_DMAC, req->intf)) 1223 + goto process_flow; 1224 + 1225 + if (is_pffunc_af(req->hdr.pcifunc)) { 1226 + if (is_unicast_ether_addr(req->packet.dmac)) { 1227 + dev_err(rvu->dev, 1228 + "%s: mkex profile does not support ucast flow\n", 1229 + __func__); 1230 + return NPC_FLOW_NOT_SUPPORTED; 1231 + } 1232 + 1233 + if (!npc_is_field_present(rvu, NPC_LXMB, req->intf)) { 1234 + dev_err(rvu->dev, 1235 + "%s: mkex profile does not support bcast/mcast flow", 1236 + __func__); 1237 + return NPC_FLOW_NOT_SUPPORTED; 1238 + } 1239 + 1240 + /* Modify feature to use LXMB instead of DMAC */ 1241 + req->features &= ~BIT_ULL(NPC_DMAC); 1242 + req->features |= BIT_ULL(NPC_LXMB); 1243 + } 1244 + 1245 + process_flow: 1235 1246 if (from_vf && req->default_rule) 1236 1247 return NPC_FLOW_VF_PERM_DENIED; 1237 1248