/* SPDX-License-Identifier: BSD-3-Clause * Copyright(C) 2019 Marvell International Ltd. */ #include "otx2_ethdev.h" #include "otx2_ethdev_sec.h" #include "otx2_flow.h" #define NPC_MAX_FIELD_NAME_SIZE 80 #define NPC_RX_ACTIONOP_MASK GENMASK(3, 0) #define NPC_RX_ACTION_PFFUNC_MASK GENMASK(19, 4) #define NPC_RX_ACTION_INDEX_MASK GENMASK(39, 20) #define NPC_RX_ACTION_MATCH_MASK GENMASK(55, 40) #define NPC_RX_ACTION_FLOWKEY_MASK GENMASK(60, 56) #define NPC_TX_ACTION_INDEX_MASK GENMASK(31, 12) #define NPC_TX_ACTION_MATCH_MASK GENMASK(47, 32) #define NIX_RX_VTAGACT_VTAG0_RELPTR_MASK GENMASK(7, 0) #define NIX_RX_VTAGACT_VTAG0_LID_MASK GENMASK(10, 8) #define NIX_RX_VTAGACT_VTAG0_TYPE_MASK GENMASK(14, 12) #define NIX_RX_VTAGACT_VTAG0_VALID_MASK BIT_ULL(15) #define NIX_RX_VTAGACT_VTAG1_RELPTR_MASK GENMASK(39, 32) #define NIX_RX_VTAGACT_VTAG1_LID_MASK GENMASK(42, 40) #define NIX_RX_VTAGACT_VTAG1_TYPE_MASK GENMASK(46, 44) #define NIX_RX_VTAGACT_VTAG1_VALID_MASK BIT_ULL(47) #define NIX_TX_VTAGACT_VTAG0_RELPTR_MASK GENMASK(7, 0) #define NIX_TX_VTAGACT_VTAG0_LID_MASK GENMASK(10, 8) #define NIX_TX_VTAGACT_VTAG0_OP_MASK GENMASK(13, 12) #define NIX_TX_VTAGACT_VTAG0_DEF_MASK GENMASK(25, 16) #define NIX_TX_VTAGACT_VTAG1_RELPTR_MASK GENMASK(39, 32) #define NIX_TX_VTAGACT_VTAG1_LID_MASK GENMASK(42, 40) #define NIX_TX_VTAGACT_VTAG1_OP_MASK GENMASK(45, 44) #define NIX_TX_VTAGACT_VTAG1_DEF_MASK GENMASK(57, 48) struct npc_rx_parse_nibble_s { uint16_t chan : 3; uint16_t errlev : 1; uint16_t errcode : 2; uint16_t l2l3bm : 1; uint16_t laflags : 2; uint16_t latype : 1; uint16_t lbflags : 2; uint16_t lbtype : 1; uint16_t lcflags : 2; uint16_t lctype : 1; uint16_t ldflags : 2; uint16_t ldtype : 1; uint16_t leflags : 2; uint16_t letype : 1; uint16_t lfflags : 2; uint16_t lftype : 1; uint16_t lgflags : 2; uint16_t lgtype : 1; uint16_t lhflags : 2; uint16_t lhtype : 1; } __rte_packed; const char *intf_str[] = { "NIX-RX", "NIX-TX", }; const char *ltype_str[NPC_MAX_LID][NPC_MAX_LT] = { [NPC_LID_LA][0] = "NONE", [NPC_LID_LA][NPC_LT_LA_ETHER] = "LA_ETHER", [NPC_LID_LA][NPC_LT_LA_IH_NIX_ETHER] = "LA_IH_NIX_ETHER", [NPC_LID_LA][NPC_LT_LA_HIGIG2_ETHER] = "LA_HIGIG2_ETHER", [NPC_LID_LA][NPC_LT_LA_IH_NIX_HIGIG2_ETHER] = "LA_IH_NIX_HIGIG2_ETHER", [NPC_LID_LB][0] = "NONE", [NPC_LID_LB][NPC_LT_LB_CTAG] = "LB_CTAG", [NPC_LID_LB][NPC_LT_LB_STAG_QINQ] = "LB_STAG_QINQ", [NPC_LID_LB][NPC_LT_LB_ETAG] = "LB_ETAG", [NPC_LID_LB][NPC_LT_LB_EXDSA] = "LB_EXDSA", [NPC_LID_LB][NPC_LT_LB_VLAN_EXDSA] = "LB_VLAN_EXDSA", [NPC_LID_LC][0] = "NONE", [NPC_LID_LC][NPC_LT_LC_IP] = "LC_IP", [NPC_LID_LC][NPC_LT_LC_IP6] = "LC_IP6", [NPC_LID_LC][NPC_LT_LC_ARP] = "LC_ARP", [NPC_LID_LC][NPC_LT_LC_IP6_EXT] = "LC_IP6_EXT", [NPC_LID_LC][NPC_LT_LC_NGIO] = "LC_NGIO", [NPC_LID_LD][0] = "NONE", [NPC_LID_LD][NPC_LT_LD_ICMP] = "LD_ICMP", [NPC_LID_LD][NPC_LT_LD_ICMP6] = "LD_ICMP6", [NPC_LID_LD][NPC_LT_LD_UDP] = "LD_UDP", [NPC_LID_LD][NPC_LT_LD_TCP] = "LD_TCP", [NPC_LID_LD][NPC_LT_LD_SCTP] = "LD_SCTP", [NPC_LID_LD][NPC_LT_LD_GRE] = "LD_GRE", [NPC_LID_LD][NPC_LT_LD_NVGRE] = "LD_NVGRE", [NPC_LID_LE][0] = "NONE", [NPC_LID_LE][NPC_LT_LE_VXLAN] = "LE_VXLAN", [NPC_LID_LE][NPC_LT_LE_ESP] = "LE_ESP", [NPC_LID_LE][NPC_LT_LE_GTPC] = "LE_GTPC", [NPC_LID_LE][NPC_LT_LE_GTPU] = "LE_GTPU", [NPC_LID_LE][NPC_LT_LE_GENEVE] = "LE_GENEVE", [NPC_LID_LE][NPC_LT_LE_VXLANGPE] = "LE_VXLANGPE", [NPC_LID_LF][0] = "NONE", [NPC_LID_LF][NPC_LT_LF_TU_ETHER] = "LF_TU_ETHER", [NPC_LID_LG][0] = "NONE", [NPC_LID_LG][NPC_LT_LG_TU_IP] = "LG_TU_IP", [NPC_LID_LG][NPC_LT_LG_TU_IP6] = "LG_TU_IP6", [NPC_LID_LH][0] = "NONE", [NPC_LID_LH][NPC_LT_LH_TU_UDP] = "LH_TU_UDP", [NPC_LID_LH][NPC_LT_LH_TU_TCP] = "LH_TU_TCP", [NPC_LID_LH][NPC_LT_LH_TU_SCTP] = "LH_TU_SCTP", [NPC_LID_LH][NPC_LT_LH_TU_ESP] = "LH_TU_ESP", }; static uint16_t otx2_get_nibbles(struct rte_flow *flow, uint16_t size, uint32_t bit_offset) { uint32_t byte_index, noffset; uint16_t data, mask; uint8_t *bytes; bytes = (uint8_t *)flow->mcam_data; mask = (1ULL << (size * 4)) - 1; byte_index = bit_offset / 8; noffset = bit_offset % 8; data = *(uint16_t *)&bytes[byte_index]; data >>= noffset; data &= mask; return data; } static void otx2_flow_print_parse_nibbles(FILE *file, struct rte_flow *flow, uint64_t parse_nibbles) { struct npc_rx_parse_nibble_s *rx_parse; uint32_t data, offset = 0; rx_parse = (struct npc_rx_parse_nibble_s *)&parse_nibbles; if (rx_parse->chan) { data = otx2_get_nibbles(flow, 3, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_CHAN:%#03X\n", data); offset += 12; } if (rx_parse->errlev) { data = otx2_get_nibbles(flow, 1, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_ERRLEV:%#X\n", data); offset += 4; } if (rx_parse->errcode) { data = otx2_get_nibbles(flow, 2, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_ERRCODE:%#02X\n", data); offset += 8; } if (rx_parse->l2l3bm) { data = otx2_get_nibbles(flow, 1, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_L2L3_BCAST:%#X\n", data); offset += 4; } if (rx_parse->latype) { data = otx2_get_nibbles(flow, 1, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LA_LTYPE:%s\n", ltype_str[NPC_LID_LA][data]); offset += 4; } if (rx_parse->laflags) { data = otx2_get_nibbles(flow, 2, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LA_FLAGS:%#02X\n", data); offset += 8; } if (rx_parse->lbtype) { data = otx2_get_nibbles(flow, 1, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LB_LTYPE:%s\n", ltype_str[NPC_LID_LB][data]); offset += 4; } if (rx_parse->lbflags) { data = otx2_get_nibbles(flow, 2, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LB_FLAGS:%#02X\n", data); offset += 8; } if (rx_parse->lctype) { data = otx2_get_nibbles(flow, 1, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LC_LTYPE:%s\n", ltype_str[NPC_LID_LC][data]); offset += 4; } if (rx_parse->lcflags) { data = otx2_get_nibbles(flow, 2, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LC_FLAGS:%#02X\n", data); offset += 8; } if (rx_parse->ldtype) { data = otx2_get_nibbles(flow, 1, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LD_LTYPE:%s\n", ltype_str[NPC_LID_LD][data]); offset += 4; } if (rx_parse->ldflags) { data = otx2_get_nibbles(flow, 2, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LD_FLAGS:%#02X\n", data); offset += 8; } if (rx_parse->letype) { data = otx2_get_nibbles(flow, 1, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LE_LTYPE:%s\n", ltype_str[NPC_LID_LE][data]); offset += 4; } if (rx_parse->leflags) { data = otx2_get_nibbles(flow, 2, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LE_FLAGS:%#02X\n", data); offset += 8; } if (rx_parse->lftype) { data = otx2_get_nibbles(flow, 1, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LF_LTYPE:%s\n", ltype_str[NPC_LID_LF][data]); offset += 4; } if (rx_parse->lfflags) { data = otx2_get_nibbles(flow, 2, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LF_FLAGS:%#02X\n", data); offset += 8; } if (rx_parse->lgtype) { data = otx2_get_nibbles(flow, 1, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LG_LTYPE:%s\n", ltype_str[NPC_LID_LG][data]); offset += 4; } if (rx_parse->lgflags) { data = otx2_get_nibbles(flow, 2, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LG_FLAGS:%#02X\n", data); offset += 8; } if (rx_parse->lhtype) { data = otx2_get_nibbles(flow, 1, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LH_LTYPE:%s\n", ltype_str[NPC_LID_LH][data]); offset += 4; } if (rx_parse->lhflags) { data = otx2_get_nibbles(flow, 2, offset); fprintf(file, "\tNPC_PARSE_NIBBLE_LH_FLAGS:%#02X\n", data); } } static void otx2_flow_print_xtractinfo(FILE *file, struct npc_xtract_info *lfinfo, struct rte_flow *flow, int lid, int lt) { uint8_t *datastart, *maskstart; int i; datastart = (uint8_t *)&flow->mcam_data + lfinfo->key_off; maskstart = (uint8_t *)&flow->mcam_mask + lfinfo->key_off; fprintf(file, "\t%s, hdr offset:%#X, len:%#X, key offset:%#X, ", ltype_str[lid][lt], lfinfo->hdr_off, lfinfo->len, lfinfo->key_off); fprintf(file, "Data:0X"); for (i = lfinfo->len - 1; i >= 0; i--) fprintf(file, "%02X", datastart[i]); fprintf(file, ", "); fprintf(file, "Mask:0X"); for (i = lfinfo->len - 1; i >= 0; i--) fprintf(file, "%02X", maskstart[i]); fprintf(file, "\n"); } static void otx2_flow_print_item(FILE *file, struct otx2_eth_dev *hw, struct npc_xtract_info *xinfo, struct rte_flow *flow, int intf, int lid, int lt, int ld) { struct otx2_npc_flow_info *npc_flow = &hw->npc_flow; struct npc_xtract_info *lflags_info; int i, lf_cfg; otx2_flow_print_xtractinfo(file, xinfo, flow, lid, lt); if (xinfo->flags_enable) { lf_cfg = npc_flow->prx_lfcfg[ld].i; if (lf_cfg == lid) { for (i = 0; i < NPC_MAX_LFL; i++) { lflags_info = npc_flow->prx_fxcfg[intf] [ld][i].xtract; otx2_flow_print_xtractinfo(file, lflags_info, flow, lid, lt); } } } } static void otx2_flow_dump_patterns(FILE *file, struct otx2_eth_dev *hw, struct rte_flow *flow) { struct otx2_npc_flow_info *npc_flow = &hw->npc_flow; struct npc_lid_lt_xtract_info *lt_xinfo; struct npc_xtract_info *xinfo; uint32_t intf, lid, ld, i; uint64_t parse_nibbles; uint16_t ltype; intf = flow->nix_intf; parse_nibbles = npc_flow->keyx_supp_nmask[intf]; otx2_flow_print_parse_nibbles(file, flow, parse_nibbles); for (i = 0; i < flow->num_patterns; i++) { lid = flow->dump_data[i].lid; ltype = flow->dump_data[i].ltype; lt_xinfo = &npc_flow->prx_dxcfg[intf][lid][ltype]; for (ld = 0; ld < NPC_MAX_LD; ld++) { xinfo = <_xinfo->xtract[ld]; if (!xinfo->enable) continue; otx2_flow_print_item(file, hw, xinfo, flow, intf, lid, ltype, ld); } } } static void otx2_flow_dump_tx_action(FILE *file, uint64_t npc_action) { char index_name[NPC_MAX_FIELD_NAME_SIZE] = "Index:"; uint32_t tx_op, index, match_id; tx_op = npc_action & NPC_RX_ACTIONOP_MASK; fprintf(file, "\tActionOp:"); switch (tx_op) { case NIX_TX_ACTIONOP_DROP: fprintf(file, "NIX_TX_ACTIONOP_DROP (%lu)\n", (uint64_t)NIX_RX_ACTIONOP_DROP); break; case NIX_TX_ACTIONOP_UCAST_DEFAULT: fprintf(file, "NIX_TX_ACTIONOP_UCAST_DEFAULT (%lu)\n", (uint64_t)NIX_TX_ACTIONOP_UCAST_DEFAULT); break; case NIX_TX_ACTIONOP_UCAST_CHAN: fprintf(file, "NIX_TX_ACTIONOP_UCAST_DEFAULT (%lu)\n", (uint64_t)NIX_TX_ACTIONOP_UCAST_CHAN); strncpy(index_name, "Transmit Channel:", NPC_MAX_FIELD_NAME_SIZE); break; case NIX_TX_ACTIONOP_MCAST: fprintf(file, "NIX_TX_ACTIONOP_MCAST (%lu)\n", (uint64_t)NIX_TX_ACTIONOP_MCAST); strncpy(index_name, "Multicast Table Index:", NPC_MAX_FIELD_NAME_SIZE); break; case NIX_TX_ACTIONOP_DROP_VIOL: fprintf(file, "NIX_TX_ACTIONOP_DROP_VIOL (%lu)\n", (uint64_t)NIX_TX_ACTIONOP_DROP_VIOL); break; } index = ((npc_action & NPC_TX_ACTION_INDEX_MASK) >> 12) & 0xFFFFF; fprintf(file, "\t%s:%#05X\n", index_name, index); match_id = ((npc_action & NPC_TX_ACTION_MATCH_MASK) >> 32) & 0xFFFF; fprintf(file, "\tMatch Id:%#04X\n", match_id); } static void otx2_flow_dump_rx_action(FILE *file, uint64_t npc_action) { uint32_t rx_op, pf_func, index, match_id, flowkey_alg; char index_name[NPC_MAX_FIELD_NAME_SIZE] = "Index:"; rx_op = npc_action & NPC_RX_ACTIONOP_MASK; fprintf(file, "\tActionOp:"); switch (rx_op) { case NIX_RX_ACTIONOP_DROP: fprintf(file, "NIX_RX_ACTIONOP_DROP (%lu)\n", (uint64_t)NIX_RX_ACTIONOP_DROP); break; case NIX_RX_ACTIONOP_UCAST: fprintf(file, "NIX_RX_ACTIONOP_UCAST (%lu)\n", (uint64_t)NIX_RX_ACTIONOP_UCAST); strncpy(index_name, "RQ Index", NPC_MAX_FIELD_NAME_SIZE); break; case NIX_RX_ACTIONOP_UCAST_IPSEC: fprintf(file, "NIX_RX_ACTIONOP_UCAST_IPSEC (%lu)\n", (uint64_t)NIX_RX_ACTIONOP_UCAST_IPSEC); strncpy(index_name, "RQ Index:", NPC_MAX_FIELD_NAME_SIZE); break; case NIX_RX_ACTIONOP_MCAST: fprintf(file, "NIX_RX_ACTIONOP_MCAST (%lu)\n", (uint64_t)NIX_RX_ACTIONOP_MCAST); strncpy(index_name, "Multicast/mirror table index", NPC_MAX_FIELD_NAME_SIZE); break; case NIX_RX_ACTIONOP_RSS: fprintf(file, "NIX_RX_ACTIONOP_RSS (%lu)\n", (uint64_t)NIX_RX_ACTIONOP_RSS); strncpy(index_name, "RSS Group Index", NPC_MAX_FIELD_NAME_SIZE); break; case NIX_RX_ACTIONOP_PF_FUNC_DROP: fprintf(file, "NIX_RX_ACTIONOP_PF_FUNC_DROP (%lu)\n", (uint64_t)NIX_RX_ACTIONOP_PF_FUNC_DROP); break; case NIX_RX_ACTIONOP_MIRROR: fprintf(file, "NIX_RX_ACTIONOP_MIRROR (%lu)\n", (uint64_t)NIX_RX_ACTIONOP_MIRROR); strncpy(index_name, "Multicast/mirror table index", NPC_MAX_FIELD_NAME_SIZE); break; } pf_func = ((npc_action & NPC_RX_ACTION_PFFUNC_MASK) >> 4) & 0xFFFF; fprintf(file, "\tPF_FUNC: %#04X\n", pf_func); index = ((npc_action & NPC_RX_ACTION_INDEX_MASK) >> 20) & 0xFFFFF; fprintf(file, "\t%s:%#05X\n", index_name, index); match_id = ((npc_action & NPC_RX_ACTION_MATCH_MASK) >> 40) & 0xFFFF; fprintf(file, "\tMatch Id:%#04X\n", match_id); flowkey_alg = ((npc_action & NPC_RX_ACTION_FLOWKEY_MASK) >> 56) & 0x1F; fprintf(file, "\tFlow Key Alg:%#X\n", flowkey_alg); } static void otx2_flow_dump_parsed_action(FILE *file, uint64_t npc_action, bool is_rx) { if (is_rx) { fprintf(file, "NPC RX Action:%#016lX\n", npc_action); otx2_flow_dump_rx_action(file, npc_action); } else { fprintf(file, "NPC TX Action:%#016lX\n", npc_action); otx2_flow_dump_tx_action(file, npc_action); } } static void otx2_flow_dump_rx_vtag_action(FILE *file, uint64_t vtag_action) { uint32_t type, lid, relptr; if (vtag_action & NIX_RX_VTAGACT_VTAG0_VALID_MASK) { relptr = vtag_action & NIX_RX_VTAGACT_VTAG0_RELPTR_MASK; lid = ((vtag_action & NIX_RX_VTAGACT_VTAG0_LID_MASK) >> 8) & 0x7; type = ((vtag_action & NIX_RX_VTAGACT_VTAG0_TYPE_MASK) >> 12) & 0x7; fprintf(file, "\tVTAG0:relptr:%#X\n", relptr); fprintf(file, "\tlid:%#X\n", lid); fprintf(file, "\ttype:%#X\n", type); } if (vtag_action & NIX_RX_VTAGACT_VTAG1_VALID_MASK) { relptr = ((vtag_action & NIX_RX_VTAGACT_VTAG1_RELPTR_MASK) >> 32) & 0xFF; lid = ((vtag_action & NIX_RX_VTAGACT_VTAG1_LID_MASK) >> 40) & 0x7; type = ((vtag_action & NIX_RX_VTAGACT_VTAG1_TYPE_MASK) >> 44) & 0x7; fprintf(file, "\tVTAG1:relptr:%#X\n", relptr); fprintf(file, "\tlid:%#X\n", lid); fprintf(file, "\ttype:%#X\n", type); } } static void otx2_get_vtag_opname(uint32_t op, char *opname, int len) { switch (op) { case 0x0: strncpy(opname, "NOP", len - 1); break; case 0x1: strncpy(opname, "INSERT", len - 1); break; case 0x2: strncpy(opname, "REPLACE", len - 1); break; } } static void otx2_flow_dump_tx_vtag_action(FILE *file, uint64_t vtag_action) { uint32_t relptr, lid, op, vtag_def; char opname[10]; relptr = vtag_action & NIX_TX_VTAGACT_VTAG0_RELPTR_MASK; lid = ((vtag_action & NIX_TX_VTAGACT_VTAG0_LID_MASK) >> 8) & 0x7; op = ((vtag_action & NIX_TX_VTAGACT_VTAG0_OP_MASK) >> 12) & 0x3; vtag_def = ((vtag_action & NIX_TX_VTAGACT_VTAG0_DEF_MASK) >> 16) & 0x3FF; otx2_get_vtag_opname(op, opname, sizeof(opname)); fprintf(file, "\tVTAG0 relptr:%#X\n", relptr); fprintf(file, "\tlid:%#X\n", lid); fprintf(file, "\top:%s\n", opname); fprintf(file, "\tvtag_def:%#X\n", vtag_def); relptr = ((vtag_action & NIX_TX_VTAGACT_VTAG1_RELPTR_MASK) >> 32) & 0xFF; lid = ((vtag_action & NIX_TX_VTAGACT_VTAG1_LID_MASK) >> 40) & 0x7; op = ((vtag_action & NIX_TX_VTAGACT_VTAG1_OP_MASK) >> 44) & 0x3; vtag_def = ((vtag_action & NIX_TX_VTAGACT_VTAG1_DEF_MASK) >> 48) & 0x3FF; otx2_get_vtag_opname(op, opname, sizeof(opname)); fprintf(file, "\tVTAG1:relptr:%#X\n", relptr); fprintf(file, "\tlid:%#X\n", lid); fprintf(file, "\top:%s\n", opname); fprintf(file, "\tvtag_def:%#X\n", vtag_def); } static void otx2_flow_dump_vtag_action(FILE *file, uint64_t vtag_action, bool is_rx) { if (is_rx) { fprintf(file, "NPC RX VTAG Action:%#016lX\n", vtag_action); otx2_flow_dump_rx_vtag_action(file, vtag_action); } else { fprintf(file, "NPC TX VTAG Action:%#016lX\n", vtag_action); otx2_flow_dump_tx_vtag_action(file, vtag_action); } } void otx2_flow_dump(FILE *file, struct otx2_eth_dev *hw, struct rte_flow *flow) { bool is_rx = 0; int i; fprintf(file, "MCAM Index:%d\n", flow->mcam_id); fprintf(file, "Interface :%s (%d)\n", intf_str[flow->nix_intf], flow->nix_intf); fprintf(file, "Priority :%d\n", flow->priority); if (flow->nix_intf == NIX_INTF_RX) is_rx = 1; otx2_flow_dump_parsed_action(file, flow->npc_action, is_rx); otx2_flow_dump_vtag_action(file, flow->vtag_action, is_rx); fprintf(file, "Patterns:\n"); otx2_flow_dump_patterns(file, hw, flow); fprintf(file, "MCAM Raw Data :\n"); for (i = 0; i < OTX2_MAX_MCAM_WIDTH_DWORDS; i++) { fprintf(file, "\tDW%d :%016lX\n", i, flow->mcam_data[i]); fprintf(file, "\tDW%d_Mask:%016lX\n", i, flow->mcam_mask[i]); } fprintf(file, "\n"); }