alpm_ts.c (87282B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * File: alpm_ts.c 7 * Purpose: ALPM trouble-shooting & sanity-check 8 */ 9 10 #include <shared/bsl.h> 11 12 #include <soc/mem.h> 13 #include <soc/drv.h> 14 #include <soc/debug.h> 15 #include <soc/error.h> 16 #include <soc/format.h> 17 #include <soc/lpm.h> 18 #include <soc/trident2.h> 19 #include <soc/tomahawk.h> 20 #include <shared/bsl.h> 21 22 #include <shared/util.h> 23 #include <shared/l3.h> 24 25 #if defined(ALPM_ENABLE) 26 27 #include <bcm/l3.h> 28 #include <bcm_int/esw/l3.h> 29 #include <bcm_int/esw/firebolt.h> 30 #include <bcm_int/esw/alpm.h> 31 #include <bcm_int/esw/alpm_util.h> 32 33 #define ALPM_CB0 0x01 34 #define ALPM_CB1 0x02 35 #define ALPM_CB_ALL_BMP (ALPM_CB0 | ALPM_CB1) 36 37 typedef struct _alpm_dbgcnt_s { 38 uint32 pvt_used[ALPM_PKM_CNT]; 39 uint32 pvt_max[ALPM_PKM_CNT]; 40 41 uint32 bucket_used; 42 uint32 bucket_max; 43 uint32 bank_used; 44 uint32 bank_max; 45 uint32 ent_used[ALPM_PKM_CNT]; /* bkt entries */ 46 uint32 ent_max; 47 uint32 bs[ALPM_BPB_MAX]; /* bucket share = #pvt share same bucket */ 48 } _alpm_dbgcnt_t; 49 50 typedef struct _alpm_dbg_data_s { 51 uint32 route_cnt; 52 uint32 hit_cnt; 53 _alpm_dbgcnt_t dc[ALPM_CB_CNT]; 54 int *bktref[ALPM_CB_CNT]; 55 } _alpm_dbg_data_t; 56 57 typedef struct _alpm_sanity_s { 58 int error; 59 int *bktptr[ALPM_CB_CNT]; 60 } _alpm_sanity_t; 61 62 typedef struct _alpm_pvt_bkt_cnt_s { 63 uint32 pvt_cnt; 64 uint32 bkt_cnt; 65 uint32 add_cnt; 66 uint32 del_cnt; 67 uint32 route_cnt; 68 uint8 db_type; 69 } _alpm_pvt_bkt_cnt_t; 70 71 typedef struct _alpm_trv_data_s { 72 int unit; 73 int vrf_id; 74 int ipt; 75 int err; 76 _alpm_cb_t *acb; 77 } _alpm_trv_data_t; 78 79 typedef enum _alpm_lkup_res_e { 80 ALPM_HIT = 1, /* Hit */ 81 ALPM_MISS = 2, /* Miss (Default Miss = 1) */ 82 ALPM_MISS_USE_AD = 3 /* Miss (Default Miss = 0) and use Assoc Data */ 83 } _alpm_lkup_res_t; 84 85 #define VRF_NAME(u, vrf_id) ((vrf_id) == ALPM_VRF_ID_GHI(u) ? "GHi" : \ 86 (vrf_id) == ALPM_VRF_ID_GLO(u) ? "GLo" : "") 87 88 #define ALPM_PVT_BKT_CNT_ADD(dst_dc, src_dc) \ 89 do { \ 90 (dst_dc)->pvt_cnt += (src_dc)->pvt_cnt; \ 91 (dst_dc)->bkt_cnt += (src_dc)->bkt_cnt; \ 92 (dst_dc)->add_cnt += (src_dc)->add_cnt; \ 93 (dst_dc)->del_cnt += (src_dc)->del_cnt; \ 94 (dst_dc)->route_cnt += (src_dc)->route_cnt; \ 95 } while (0) 96 97 #define PRINT_SPLIT_LINE(u) \ 98 LOG_CLI((BSL_META_U(u, "--------------------------------------------------------\n"))) 99 100 #define PRINT_VRF_NOT_FOUND(u) \ 101 LOG_CLI((BSL_META_U(u, "%9s\n"), "Specific VRF not found")) 102 103 #define PRINT_ACB_HEADER(u, i) \ 104 LOG_CLI((BSL_META_U(u, "\n%s\n"), alpm_util_acb_str[(i)])) 105 106 #define PRINT_PVT_BKT_HEADER(u) \ 107 do { \ 108 LOG_CLI((BSL_META_U(u, \ 109 "\nVRF PKM Pivot Bucket Add Delete | Comment\n"))); \ 110 } while (0) 111 112 #define PRINT_PVT_BKT_ITEM(u, vrf, ipt, dc) \ 113 do { \ 114 LOG_CLI((BSL_META_U(u, \ 115 "%-4d %-7s %-7d %-7d %-7d %-7d | %-7s\n"), (vrf), \ 116 alpm_util_ipt_str[(ipt)], (dc)->pvt_cnt, (dc)->bkt_cnt, \ 117 (dc)->add_cnt, (dc)->del_cnt, VRF_NAME((u), (vrf)) )); \ 118 } while (0) 119 120 #define PRINT_PVT_BKT_TOT(u, ipt, all) \ 121 do { \ 122 LOG_CLI((BSL_META_U(u, \ 123 "Tot %-7s %-7d %-7d %-7d %-7d |\n"), alpm_util_ipt_str[(ipt)], \ 124 (all)->pvt_cnt, (all)->bkt_cnt, (all)->add_cnt, (all)->del_cnt)); \ 125 } while (0) 126 127 /* according to ALPMC(u)->_alpm_dbg_info_bmp defines */ 128 char *alpm_dbg_info_str[_ALPM_DBG_INFO_MAX_NUM] = { 129 "pvt", 130 "rte", 131 "cnt", 132 "hit", 133 }; 134 135 int 136 alpm_dbg_info_bmp_show(int u) 137 { 138 int i; 139 if (ALPMC(u) == NULL) { 140 return BCM_E_INIT; 141 } 142 143 if (ALPMC(u)->_alpm_dbg_info_bmp != 0) { 144 cli_out("alpm_info_bmp is on:"); 145 146 if (ALPMC(u)->_alpm_dbg_info_bmp == _ALPM_DBG_INFO_ALL) { 147 cli_out(" all -"); 148 } 149 for (i = 0; i < _ALPM_DBG_INFO_MAX_NUM; i++) { 150 if (ALPMC(u)->_alpm_dbg_info_bmp & (1 << i)) { 151 cli_out(" %s", alpm_dbg_info_str[i]); 152 } 153 } 154 cli_out(".\n"); 155 } else { 156 cli_out("alpm_info_bmp is off.\n"); 157 } 158 159 return BCM_E_NONE; 160 161 } 162 163 int 164 alpm_dbg_info_bmp_set(int u, uint32 flags) 165 { 166 if (ALPMC(u) == NULL) { 167 return BCM_E_INIT; 168 } 169 170 ALPMC(u)->_alpm_dbg_info_bmp = flags; 171 (void)alpm_dbg_info_bmp_show(u); 172 173 return BCM_E_NONE; 174 } 175 176 int 177 alpm_find_best_match(int u, int vrf_id, int pkm, uint32 *sw_key, 178 int sw_len, _bcm_defip_cfg_t *lpm_cfg); 179 180 STATIC int 181 alpm_pvt_bkt_cnt_cb(int u, _alpm_cb_t *acb, 182 _alpm_pvt_node_t *pvt_node, void *user_data) 183 { 184 _alpm_pvt_bkt_cnt_t *data = (_alpm_pvt_bkt_cnt_t *)user_data; 185 if (pvt_node->bkt_trie && pvt_node->bkt_trie->trie) { 186 data->bkt_cnt += pvt_node->bkt_trie->trie->count; /* add bkt cnt */ 187 } 188 return BCM_E_NONE; 189 } 190 191 STATIC void 192 alpm_debug_count_dump(int u, int cb_bmp, int vrf_id, uint32 flags) 193 { 194 int found = FALSE; 195 _alpm_pvt_bkt_cnt_t alpm_dc[ALPM_IPT_CNT]; 196 _alpm_pvt_bkt_cnt_t all_dc[ALPM_IPT_CNT]; 197 int i, vrf, ipt; 198 _alpm_cb_t *acb; 199 alpm_lib_trie_t *pvt_trie; 200 201 for (i = 0; i < ACB_CNT(u); i++) { 202 if (!(cb_bmp & (1 << i))) { 203 continue; 204 } 205 PRINT_ACB_HEADER(u, i); 206 PRINT_PVT_BKT_HEADER(u); 207 PRINT_SPLIT_LINE(u); 208 209 found = FALSE; 210 acb = ACB(u, i); 211 sal_memset(&all_dc, 0, sizeof(all_dc)); 212 213 for (vrf = 0; vrf <= ALPM_VRF_ID_MAX(u); vrf++) { 214 if (vrf_id != -1 && vrf_id != vrf) { 215 continue; 216 } 217 sal_memset(&alpm_dc, 0, sizeof(alpm_dc)); 218 219 for (ipt = 0; ipt < ALPM_IPT_CNT; ipt++) { 220 if (!ACB_VRF_INITED(u, acb, vrf, ipt)) { 221 continue; 222 } 223 pvt_trie = ACB_PVT_TRIE(acb, vrf, ipt); 224 225 if ((pvt_trie == NULL) || (pvt_trie->trie == NULL)) { 226 continue; 227 } 228 alpm_dc[ipt].pvt_cnt = pvt_trie->trie->count; 229 alpm_dc[ipt].add_cnt = ACB_PVT_CTRL(acb, vrf, ipt).cnt_add; 230 alpm_dc[ipt].del_cnt = ACB_PVT_CTRL(acb, vrf, ipt).cnt_del; 231 alpm_dc[ipt].route_cnt = ACB_PVT_CTRL(acb, vrf, ipt).route_cnt; 232 alpm_dc[ipt].db_type = ACB_PVT_CTRL(acb, vrf, ipt).db_type; 233 234 (void)bcm_esw_alpm_pvt_traverse(u, i, vrf, ipt, 235 alpm_pvt_bkt_cnt_cb, (void *)&alpm_dc[ipt]); 236 found = TRUE; 237 238 if (flags & BCM_ALPM_DEBUG_SHOW_FLAG_BKT) { 239 PRINT_PVT_BKT_ITEM(u, vrf, ipt, &alpm_dc[ipt]); 240 } 241 ALPM_PVT_BKT_CNT_ADD(&all_dc[ipt], &alpm_dc[ipt]); 242 } 243 } 244 245 if (found == FALSE) { 246 PRINT_VRF_NOT_FOUND(u); 247 } else { 248 PRINT_SPLIT_LINE(u); 249 for (ipt = 0; ipt < ALPM_IPT_CNT; ipt++) { 250 PRINT_PVT_BKT_TOT(u, ipt, &all_dc[ipt]); 251 } 252 } 253 } 254 } 255 256 STATIC int 257 alpm_pfx_debug_cb(_alpm_pfx_node_t *pfx_node, void *user_data) 258 { 259 _alpm_trv_data_t *trv_data = (_alpm_trv_data_t *)user_data; 260 char ip_buf[IP6ADDR_STR_LEN]; 261 int u = trv_data->unit; 262 int ipt = trv_data->ipt; 263 /*int vrf_id = trv_data->vrf_id;*/ 264 _alpm_bkt_node_t *bkt_node = pfx_node->bkt_ptr; 265 int idx, ent; 266 _bcm_defip_cfg_t lpm_cfg; 267 268 if (bkt_node == NULL) { 269 /* VRF global low "virtual def rte" without true bucket */ 270 /* ALPM_INFO((" **PFX %p w/o BKT: Sublen:%d\n", 271 pfx_node, pfx_node->key_len)); */ 272 return BCM_E_NONE; 273 } 274 275 idx = ALPM_TAB_IDX_GET(bkt_node->ent_idx); 276 ent = ALPM_IDX_TO_ENT(bkt_node->ent_idx); 277 sal_memset(&lpm_cfg, 0, sizeof(lpm_cfg)); 278 279 /* defip_flags */ 280 if (ALPM_IS_IPV6(ipt)) { 281 lpm_cfg.defip_flags |= BCM_L3_IP6; 282 } 283 284 /* Key & Length (lpm_cfg.user_data will be used in _alpm_find()) */ 285 alpm_trie_pfx_to_cfg(u, bkt_node->key, bkt_node->key_len, &lpm_cfg); 286 287 if (ALPM_IS_IPV4(ipt)) { 288 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg.defip_ip_addr); 289 } else { 290 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg.defip_ip6_addr); 291 } 292 293 if (bkt_node->key_len != pfx_node->key_len) { 294 ALPM_INFO((" **PFX %p->BKT %p: idx:%d.%d Sublen:%d Dest:%d IP:%s" 295 " Error=(bkt_keylen:%d)\n", 296 pfx_node, bkt_node, idx, ent, pfx_node->key_len, 297 bkt_node->adata.defip_ecmp_index, ip_buf, 298 bkt_node->key_len)); 299 } else { 300 ALPM_INFO((" **PFX %p->BKT %p: idx:%d.%d Sublen:%d Dest:%d IP:%s\n", 301 pfx_node, bkt_node, idx, ent, pfx_node->key_len, 302 bkt_node->adata.defip_ecmp_index, ip_buf)); 303 } 304 305 return BCM_E_NONE; 306 } 307 308 STATIC int 309 alpm_bkt_debug_cb(_alpm_bkt_node_t *bkt_node, void *user_data) 310 { 311 _alpm_trv_data_t *trv_data = (_alpm_trv_data_t *)user_data; 312 char ip_buf[IP6ADDR_STR_LEN]; 313 int u = trv_data->unit; 314 int ipt = trv_data->ipt; 315 /*int vrf_id = trv_data->vrf_id;*/ 316 int idx = ALPM_TAB_IDX_GET(bkt_node->ent_idx); 317 int ent = ALPM_IDX_TO_ENT(bkt_node->ent_idx); 318 _bcm_defip_cfg_t lpm_cfg; 319 320 sal_memset(&lpm_cfg, 0, sizeof(lpm_cfg)); 321 322 /* defip_flags */ 323 if (ALPM_IS_IPV6(ipt)) { 324 lpm_cfg.defip_flags |= BCM_L3_IP6; 325 } 326 327 /* Key & Length (lpm_cfg.user_data will be used in _alpm_find()) */ 328 alpm_trie_pfx_to_cfg(u, bkt_node->key, bkt_node->key_len, &lpm_cfg); 329 330 if (ALPM_IS_IPV4(ipt)) { 331 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg.defip_ip_addr); 332 } else { 333 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg.defip_ip6_addr); 334 } 335 336 ALPM_INFO((" >BKT %p: idx:%d.%d Sublen:%d Dest:%d IP:%s\n", 337 bkt_node, idx, ent, bkt_node->key_len, 338 bkt_node->adata.defip_ecmp_index, ip_buf)); 339 340 return BCM_E_NONE; 341 } 342 343 STATIC int 344 alpm_pvt_node_dbg(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node, 345 _alpm_trv_data_t *trv_data) 346 { 347 char ip_buf[IP6ADDR_STR_LEN]; 348 int ipt = PVT_BKT_IPT(pvt_node); 349 int vrf_id = PVT_BKT_VRF(pvt_node); 350 int idx, sub_idx; 351 int rv = BCM_E_NONE; 352 _bcm_defip_cfg_t lpm_cfg; 353 354 sal_memset(&lpm_cfg, 0, sizeof(lpm_cfg)); 355 356 /* defip_flags */ 357 if (ALPM_IS_IPV6(ipt)) { 358 lpm_cfg.defip_flags |= BCM_L3_IP6; 359 } 360 361 if ((ipt != trv_data->ipt) || 362 (vrf_id != trv_data->vrf_id)) { 363 rv = BCM_E_INTERNAL; 364 } 365 366 /* Key & Length (lpm_cfg.user_data will be used in _alpm_find()) */ 367 alpm_trie_pfx_to_cfg(u, pvt_node->key, pvt_node->key_len, &lpm_cfg); 368 369 if (ALPM_IS_IPV4(ipt)) { 370 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg.defip_ip_addr); 371 } else { 372 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg.defip_ip6_addr); 373 } 374 375 ALPM_IER(alpm_util_pvt_idx_get(u, acb, pvt_node, &idx, &sub_idx)); 376 377 if (PVT_BKT_TRIE(pvt_node) == NULL) { 378 if (BCM_SUCCESS(rv)) { 379 ALPM_INFO(("L%d PVT %p->BKT %p: idx:%d.%d Sublen:%d IP:%s w/o bkt\n", 380 ACB_IDX(acb)+1, pvt_node, PVT_BKT_DEF(pvt_node), 381 idx, sub_idx, pvt_node->key_len, ip_buf)); 382 } else { 383 ALPM_ERR(("L%d PVT %p->BKT %p: idx:%d.%d Sublen:%d IP:%s w/o bkt" 384 " Error=(VRF:%d IPT:%d)\n", 385 ACB_IDX(acb)+1, pvt_node, PVT_BKT_DEF(pvt_node), 386 idx, sub_idx, pvt_node->key_len, ip_buf, 387 vrf_id, ipt)); 388 } 389 } else if (PVT_BKT_DEF(pvt_node) == NULL) { 390 if (BCM_SUCCESS(rv)) { 391 ALPM_INFO(("\nL%d PVT %p->BKT %p: idx:%d.%d Sublen:%d IP:%s w/o def_rte\n", 392 ACB_IDX(acb)+1, pvt_node, PVT_BKT_DEF(pvt_node), 393 idx, sub_idx, pvt_node->key_len, ip_buf)); 394 } else { 395 ALPM_ERR(("\nL%d PVT %p->BKT %p: idx:%d.%d Sublen:%d IP:%s w/o def_rte" 396 " Error=(VRF:%d IPT:%d)\n", 397 ACB_IDX(acb)+1, pvt_node, PVT_BKT_DEF(pvt_node), 398 idx, sub_idx, pvt_node->key_len, ip_buf, 399 vrf_id, ipt)); 400 } 401 } else { 402 if (BCM_SUCCESS(rv)) { 403 ALPM_INFO(("\nL%d PVT %p->BKT %p: idx:%d.%d Sublen:%d bpmDest:%d IP:%s\n", 404 ACB_IDX(acb)+1, pvt_node, PVT_BKT_DEF(pvt_node), 405 idx, sub_idx, pvt_node->key_len, 406 PVT_BKT_DEF(pvt_node)->adata.defip_ecmp_index, ip_buf)); 407 } else { 408 ALPM_ERR(("\nL%d PVT %p->BKT %p: idx:%d.%d Sublen:%d bpmDest:%d IP:%s" 409 " Error=(VRF:%d IPT:%d)\n", 410 ACB_IDX(acb)+1, pvt_node, PVT_BKT_DEF(pvt_node), 411 idx, sub_idx, pvt_node->key_len, 412 PVT_BKT_DEF(pvt_node)->adata.defip_ecmp_index, ip_buf, 413 vrf_id, ipt)); 414 } 415 } 416 417 return rv; 418 } 419 420 STATIC int 421 alpm_pvt_debug_cb(int u, _alpm_cb_t *acb, 422 _alpm_pvt_node_t *pvt_node, void *user_data) 423 { 424 _alpm_trv_data_t *trv_data = (_alpm_trv_data_t *)user_data; 425 426 alpm_pvt_node_dbg(u, acb, pvt_node, trv_data); 427 428 if (PVT_BKT_TRIE(pvt_node)) { 429 bcm_esw_alpm_bkt_traverse(pvt_node->bkt_trie, 430 alpm_bkt_debug_cb, trv_data); 431 } 432 return BCM_E_NONE; 433 } 434 435 STATIC void 436 alpm_trie_debug_dump(int u, int cb_bmp, int vrf_id) 437 { 438 int i, vrf, ipt; 439 _alpm_cb_t *acb; 440 _alpm_trv_data_t trv_data; 441 442 trv_data.unit = u; 443 for (i = 0; i < ACB_CNT(u); i++) { 444 if (!(cb_bmp & (1 << i))) { 445 continue; 446 } 447 acb = ACB(u, i); 448 trv_data.acb = acb; 449 450 for (vrf = 0; vrf <= ALPM_VRF_ID_MAX(u); vrf++) { 451 if (vrf_id != -1 && vrf_id != vrf) { 452 continue; 453 } 454 trv_data.vrf_id = vrf; 455 456 for (ipt = 0; ipt < ALPM_IPT_CNT; ipt++) { 457 if (!ACB_VRF_INITED(u, acb, vrf, ipt)) { 458 continue; 459 } 460 trv_data.ipt = ipt; 461 ALPM_INFO(("\n%s VRF:%d IPT:%s\n", 462 alpm_util_acb_str[i], vrf, alpm_util_ipt_str[ipt])); 463 (void)bcm_esw_alpm_pvt_traverse(u, i, vrf, ipt, 464 alpm_pvt_debug_cb, &trv_data); 465 466 if (ACB_HAS_RTE(acb, vrf)) { 467 ALPM_INFO(("\n")); 468 (void)bcm_esw_alpm_pfx_traverse(u, vrf, ipt, 469 alpm_pfx_debug_cb, &trv_data); 470 } 471 } 472 } 473 } 474 } 475 476 /* 477 * Function: 478 * bcm_esw_alpm_debug_show 479 * Purpose: 480 * Show ALPM Sw counters for all levels per VRF. 481 * Detail debug info will be dumped if "debug bcm alpm". 482 * Parameters: 483 * u - (In)Device unit 484 * vrf_id - (In)Show for a specific VRF ID, -1 for all VRFs. 485 * flags - (In)Show flags or all. 486 * Returns: 487 * BCM_E_XXX 488 */ 489 int 490 bcm_esw_alpm_debug_show(int u, int vrf_id, uint32 flags) 491 { 492 int rv = BCM_E_NONE; 493 494 if (ALPMC(u) == NULL) { 495 return BCM_E_INIT; 496 } 497 498 if ((vrf_id > ALPM_VRF_ID_MAX(u)) || !flags) { 499 return BCM_E_PARAM; 500 } 501 502 if (flags & (BCM_ALPM_DEBUG_SHOW_FLAG_CNT | BCM_ALPM_DEBUG_SHOW_FLAG_BKT)) { 503 alpm_debug_count_dump(u, ALPM_CB_ALL_BMP, vrf_id, flags); 504 } 505 506 if (flags & (BCM_ALPM_DEBUG_SHOW_FLAG_INTDBG)) { 507 alpm_trie_debug_dump(u, ALPM_CB_ALL_BMP, vrf_id); 508 } 509 510 return rv; 511 } 512 /* 513 * Function: 514 * alpm_cb_dbg_process 515 * Purpose: 516 * ALPM control block (level) debug process. 517 * It's recursive from top to bottom. 518 * Get ALPM data and info from Hw mem at this level. 519 * Parameters: 520 * u - (In)Device unit 521 * vrf_id - (In)VRF ID 522 * pkm - (In)PKM 523 * acb - (In)ALPM control block 524 * fent - (In)ALPM_DATA entry 525 * pvtfmt - (In)Pivot bank format (ignored for TCAM) 526 * key - (In)Key prefix 527 * key_len - (In)Key prefix length 528 * idx - (In)Memory Index 529 * sub_idx - (In)Memory sub_idx (for half-entry) or ent index 530 * adata - (In)Assoc Data structure pointer 531 * dp - (In/Out)Carrying debug counters 532 * Returns: 533 * BCM_E_XXX 534 */ 535 STATIC int 536 alpm_cb_dbg_process(int u, int vrf_id, int pkm, _alpm_cb_t *acb, void *fent, 537 int pvtfmt, uint32 *key, int key_len, int idx, int sub_idx, 538 _alpm_bkt_adata_t *adata, _alpm_dbg_data_t *dp) 539 { 540 uint32 bkt_entry[ALPM_MEM_ENT_MAX]; 541 uint32 fent1[ALPM_MEM_ENT_MAX]; 542 uint32 ftmp[ALPM_MEM_ENT_MAX]; 543 uint32 new_key[4]; 544 uint32 fmt, valid; 545 int sublen, new_len, def_miss; 546 int idx1, eid, bnk; 547 _alpm_bkt_adata_t adata1; 548 _alpm_bkt_info_t bkt_info; 549 char ip_buf[IP6ADDR_STR_LEN]; 550 _bcm_defip_cfg_t lpm_cfg; 551 _alpm_tbl_t bkt_tbl; 552 _alpm_tbl_t pvt_tbl; 553 int ipt; 554 555 if (ACB_IDX(acb) >= ACB_CNT(u)) { 556 return BCM_E_INTERNAL; /* wrong ALPM control level called */ 557 } 558 559 ipt = ALPM_PKM2IPT(pkm); 560 bkt_tbl = ACB_BKT_TBL(acb, vrf_id); 561 pvt_tbl = (ACB_HAS_TCAM(acb) ? acb->pvt_tbl[pkm] : 562 ACB_BKT_TBL(ACB_UPR(u, acb), vrf_id)); 563 564 /**** Pivot level ****/ 565 alpm_util_bkt_info_get(u, vrf_id, ipt, pkm, acb, fent, sub_idx, 566 &bkt_info, &sublen, &def_miss); 567 568 /* kshift must be same as previous key_len */ 569 if (!ACB_BKT_FIXED_FMT(acb, 1) && sublen != key_len) { 570 ALPM_ERR(("%s: ALPM_DATA invalid kshift:%d vs pivot len:%d" 571 " idx:%d.%d (%d)\n", ALPM_TBL_NAME(pvt_tbl), sublen, 572 key_len, idx, sub_idx, BI_BKT_IDX(&bkt_info))); 573 return BCM_E_NONE; /* just skip the pivot */ 574 } 575 if (BI_BKT_IDX(&bkt_info) >= ACB_BKT_CNT(acb)) { 576 ALPM_ERR(("%s: ALPM_DATA invalid bkt_ptr idx:%d.%d (%d)\n", 577 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, BI_BKT_IDX(&bkt_info))); 578 return BCM_E_NONE; /* just skip the pivot */ 579 } 580 dp->dc[ACB_IDX(acb)].pvt_used[pkm]++; 581 dp->bktref[ACB_IDX(acb)][BI_BKT_IDX(&bkt_info)]++; 582 if (ALPMC(u)->_alpm_dbg_info_bmp & _ALPM_DBG_INFO_PVT) { 583 alpm_util_cfg_construct(u, vrf_id, ipt, key, key_len, adata, &lpm_cfg); 584 if (ALPM_IS_IPV4(ipt)) { 585 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg.defip_ip_addr); 586 } else { 587 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg.defip_ip6_addr); 588 } 589 if (ACB_HAS_TCAM(acb)) { 590 ALPM_INFO(("VRF:%d PKM:%s %s: idx:%d.%d Sublen:%d bpmDest:%d IP:%s\n", 591 vrf_id, alpm_util_pkm_str[pkm], ALPM_TBL_NAME(pvt_tbl), 592 idx, sub_idx, key_len, 593 adata->defip_ecmp_index, ip_buf)); 594 } else { 595 ALPM_INFO(("VRF:%d PKM:%s %s: idx:%d.%d Sublen:%d fmt:%d bpmDest:%d IP:%s\n", 596 vrf_id, alpm_util_pkm_str[pkm], ALPM_TBL_NAME(pvt_tbl), 597 idx, sub_idx, key_len, pvtfmt, 598 adata->defip_ecmp_index, ip_buf)); 599 } 600 } 601 602 for (bnk = 0; bnk < ACB_BNK_PER_BKT(acb, vrf_id); bnk++) { 603 fmt = bkt_info.bnk_fmt[bnk]; 604 if ((fmt == 0) || (fmt > ACB_FMT_CNT(acb, vrf_id))) { 605 if (fmt > ACB_FMT_CNT(acb, vrf_id)) { 606 ALPM_ERR(("%s: ALPM_DATA format wrong idx:%d.%d (bank=%d fmt=%d).\n", 607 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, bnk, fmt)); 608 } 609 continue; 610 } 611 dp->dc[ACB_IDX(acb)].bank_used++; 612 613 /**** Bucket Level ****/ 614 idx1 = ALPM_TAB_IDX_GET_BKT_BNK(acb, BI_ROFS(&bkt_info), BI_BKT_IDX(&bkt_info), bnk); 615 ALPM_IER(alpm_bkt_entry_read(u, ACB_BKT_TBL(acb, vrf_id), 616 acb, bkt_entry, idx1)); 617 618 for (eid = 0; eid < ACB_FMT_ENT_MAX(acb, vrf_id, fmt); eid++) { 619 uint32 key2[4] = {0}; 620 int len2 = 0; 621 int sub_bkt_ptr = 0; 622 623 /* process bucket entry Prefix */ 624 alpm_util_ent_ent_get(u, vrf_id, acb, bkt_entry, fmt, eid, ftmp); 625 alpm_util_bkt_pfx_get(u, vrf_id, acb, ftmp, fmt, key2, &len2, &valid); 626 alpm_util_bkt_adata_get(u, vrf_id, ipt, acb, ftmp, fmt, &adata1, &sub_bkt_ptr); 627 628 if (!valid || BI_SUB_BKT_IDX(&bkt_info) != sub_bkt_ptr) { 629 continue; 630 } else { 631 if (ACB_BKT_FIXED_FMT(acb, 1)) { 632 new_len = len2; 633 sal_memcpy(new_key, key2, sizeof(new_key)); 634 } else { 635 alpm_util_pfx_cat(u, ipt, key, sublen, key2, len2, new_key, &new_len); 636 } 637 } 638 639 /* process bucket entry ASSOC_DATA */ 640 dp->dc[ACB_IDX(acb)].ent_used[pkm]++; 641 642 /* end recursion here if reach to route level (last level) */ 643 if (ACB_HAS_RTE(acb, vrf_id)) { 644 dp->route_cnt++; 645 if (ALPMC(u)->_alpm_dbg_info_bmp & _ALPM_DBG_INFO_RTE) { 646 alpm_util_cfg_construct(u, vrf_id, ipt, new_key, new_len, 647 &adata1, &lpm_cfg); 648 if (ALPM_IS_IPV4(ipt)) { 649 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg.defip_ip_addr); 650 } else { 651 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg.defip_ip6_addr); 652 } 653 654 if (!ALPM_HIT_SKIP(u)) { 655 int hit_val; 656 ALPM_HIT_LOCK(u); 657 hit_val = alpm_rte_hit_get(u, vrf_id, bkt_tbl, idx1, eid); 658 ALPM_HIT_UNLOCK(u); 659 660 if (hit_val > 0) { 661 dp->hit_cnt++; 662 ALPM_INFO(("! ")); 663 } 664 } 665 ALPM_INFO(("VRF:%d PKM:%s %s: Route idx:%d.%d Sublen:%d" 666 " fmt:%d Dest:%d IP:%s\n", 667 vrf_id, alpm_util_pkm_str[pkm], 668 ALPM_TBL_NAME(bkt_tbl), 669 idx1, eid, 670 new_len, fmt, adata1.defip_ecmp_index, ip_buf)); 671 } 672 continue; 673 } 674 675 /* prevent going further down if somehow last level is not 676 Route level due to internal failure */ 677 if ((ACB_IDX(acb) + 1) >= ACB_CNT(u)) { 678 return BCM_E_INTERNAL; 679 } 680 681 /* get ALPM Data entry ready for next level */ 682 alpm_util_ent_data_get(u, vrf_id, ipt, acb, ftmp, fmt, fent1); 683 ALPM_IER(alpm_cb_dbg_process(u, vrf_id, ipt, ACB_DWN(u, acb), 684 fent1, fmt, new_key, new_len, idx1, eid, &adata1, dp)); 685 } /* for ent */ 686 } /* for bnk */ 687 688 return BCM_E_NONE; 689 } 690 691 /* 692 * Function: 693 * bcm_esw_alpm_debug_brief_show 694 * Purpose: 695 * Show ALPM Hw mem debug information and counters. 696 * Process all ALPM levels from top to bottom. 697 * Detail debug info will be dumped if "debug bcm alpm". 698 * Parameters: 699 * u - (In)Device unit 700 * phy_bkt - (In)Physical bucket (not in used) 701 * index - (In)Memory index (not in used) 702 * Returns: 703 * BCM_E_XXX 704 */ 705 int 706 bcm_esw_alpm_debug_brief_show(int u, int phy_bkt, int index) 707 { 708 int ipv6, key_mode; 709 int idx, sub_idx; 710 int vrf_id; 711 int idx_end; 712 int step_size; 713 int rv = BCM_E_NONE; 714 int rv_tcam; 715 uint32 lpm_entry[ALPM_MEM_ENT_MAX]; 716 uint32 fent[ALPM_MEM_ENT_MAX]; 717 _bcm_defip_cfg_t lpm_cfg; 718 _alpm_cb_t *acb; 719 _alpm_bkt_adata_t adata0; 720 int pk, pkm, use_alpm; 721 uint32 key[4]; 722 int ipt, key_pfx_len; 723 int i, j, bit128, pid, alloc_sz, k, ent_used_tot; 724 uint32 glb_hi_cnt = 0, glb_lo_cnt = 0; /* TCAM direct routes */ 725 _alpm_dbg_data_t dbg[ALPM_BKT_PID_CNT]; /* per Private and Global */ 726 _alpm_dbg_data_t *dp; 727 _alpm_bkt_pool_conf_t *bp_conf; 728 char ip_buf[IP6ADDR_STR_LEN]; 729 char *lvl_str[] = { 730 "2-Level", 731 "3-Level" 732 }; 733 char *mode_str[] = { 734 "ALPM-Combined", 735 "ALPM-Parallel", 736 "ALPM-TCAM_ALPM" 737 }; 738 #if defined(BCM_TRIDENT3_SUPPORT) 739 uint32 urpf, alpm, fv, rval; 740 uint32 mode = 0; 741 uint32 bnkbits = 0; 742 char *dw_str = "Double Wide"; 743 char *sw_str = "Single Wide"; 744 char *ipver_str[] = { 745 "IPv4", 746 "IPv6-64", 747 "IPv6-128", 748 "IPv4-1", 749 "IPv6-64-1" 750 }; 751 uint32 fmt_ent_max[] = { 752 6, 753 3, 754 2, 755 4, 756 3 757 }; 758 #endif 759 760 if (ALPMC(u) == NULL) { 761 return BCM_E_INIT; 762 } 763 764 for (i = 0; i < ACB_CNT(u); i++) { 765 acb = ACB(u, i); 766 767 for (pid = 0; pid < ALPM_BKT_PID_CNT; pid++) { 768 bp_conf = ACB_BKT_POOL(acb, pid); 769 if (pid > 0 && bp_conf == ACB_BKT_POOL(acb, pid - 1)) { 770 continue; /* Combined Mode uses PID=0 only for dbg counters */ 771 } 772 773 dp = &dbg[pid]; 774 dp->route_cnt = 0; 775 dp->hit_cnt = 0; 776 sal_memset(&dp->dc[i], 0, sizeof(_alpm_dbgcnt_t)); 777 dp->dc[i].bucket_max = ACB_BKT_CNT(acb); 778 dp->dc[i].bank_max = BPC_BNK_CNT(bp_conf); 779 dp->dc[i].ent_max = dp->dc[i].bank_max * BPC_FMT_ENT_MAX(bp_conf, 1); 780 alloc_sz = dp->dc[i].bucket_max * sizeof(int); 781 ALPM_ALLOC_EG(dp->bktref[i], alloc_sz, "bktref"); 782 783 /* Calculate maximum pivot supported (only useful for TCAM level) */ 784 if (ACB_HAS_TCAM(acb)) { 785 for (pkm = 0; pkm < ALPM_PKM_CNT; pkm++) { 786 dp->dc[i].pvt_max[pkm] = 787 (pkm == ALPM_PKM_32B ? 2 : 1) * tcam_table_size(u, pkm); 788 } 789 } 790 } 791 } 792 793 acb = ACB_TOP(u); /* from top to bottom */ 794 795 for (pk = 0; pk < ALPM_PKM_CNT; pk++) { 796 if (ALPM_TCAM_TBL_SKIP(u, pk)) { 797 continue; /* skip duplicated or invalid TCAM table */ 798 } 799 800 idx_end = tcam_table_size(u, pk); 801 /* Walk all TCAM entries */ 802 for (idx = 0; idx < idx_end; idx++) { 803 ALPM_IEG(tcam_entry_read(u, pk, lpm_entry, idx, idx)); 804 805 for (sub_idx = 0; sub_idx < ALPM_TCAM_SUBCNT; sub_idx += step_size) { 806 rv_tcam = tcam_valid_entry_mode_get(u, pk, lpm_entry, 807 &step_size, &pkm, &ipv6, &key_mode, sub_idx); 808 if (BCM_FAILURE(rv_tcam)) { 809 if (rv_tcam == BCM_E_INTERNAL) { 810 ALPM_ERR(("%s: Invalid Key Mode:%d or Key Type (IPv6):%d" 811 " in idx:%d.%d\n", 812 TCAM_TBL_NAME(acb, pk), key_mode, ipv6, idx, sub_idx)); 813 } 814 continue; 815 } 816 ipt = ALPM_PKM2IPT(pkm); 817 tcam_entry_vrf_id_get(u, pkm, lpm_entry, sub_idx, &vrf_id); 818 819 /* Combined Mode uses PID=0 only for dbg counters */ 820 pid = ACB_BKT_VRF_PID(acb, vrf_id); 821 dp = &dbg[pid]; 822 if (vrf_id == ALPM_VRF_ID_GHI(u)) { 823 glb_hi_cnt++; 824 } else if (vrf_id == ALPM_VRF_ID_GLO(u)) { 825 glb_lo_cnt++; 826 } 827 828 /* Get Pre-pivot key IP_ADDR and prefix length (mask) */ 829 sal_memset(key, 0, sizeof(key)); 830 key_pfx_len = 0; 831 tcam_entry_to_key(u, pkm, lpm_entry, sub_idx, key); 832 tcam_entry_pfx_len_get(u, pkm, lpm_entry, sub_idx, &key_pfx_len); 833 834 /* process pre-pivor ASSOC_DATA */ 835 tcam_entry_adata_get(u, pkm, lpm_entry, sub_idx, &adata0); 836 use_alpm = !(adata0.defip_flags & BCM_L3_IPMC) && 837 ALPM_VRF_ID_HAS_BKT(u, vrf_id); 838 839 /* VRF_OVERRIDE (Global High) entries, and IP multicast prefix 840 * resides in TCAM */ 841 if (!use_alpm) { 842 dp->route_cnt++; 843 if (ALPMC(u)->_alpm_dbg_info_bmp & 844 (_ALPM_DBG_INFO_PVT | _ALPM_DBG_INFO_RTE)) { 845 alpm_util_cfg_construct(u, vrf_id, ipt, key, key_pfx_len, 846 &adata0, &lpm_cfg); 847 if (ALPM_IS_IPV4(ipt)) { 848 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg.defip_ip_addr); 849 } else { 850 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg.defip_ip6_addr); 851 } 852 853 if (!ALPM_HIT_SKIP(u) && 854 tcam_entry_hit_get(u, pkm, lpm_entry, sub_idx)) { 855 dp->hit_cnt++; 856 ALPM_INFO(("! ")); 857 } 858 859 ALPM_INFO(("VRF:%d PKM:%s TCAM: Direct Route" 860 " idx:%d.%d Sublen:%d Dest:%d IP:%s\n", 861 vrf_id, alpm_util_pkm_str[pkm], idx, sub_idx, key_pfx_len, 862 adata0.defip_ecmp_index, ip_buf)); 863 } 864 continue; 865 } 866 867 if (ALPMC(u)->_alpm_dbg_info_bmp & 868 (_ALPM_DBG_INFO_PVT | _ALPM_DBG_INFO_RTE)) { 869 ALPM_INFO(("\n")); 870 } 871 872 /* process ALPM_DATA level recursively from top to bottom */ 873 tcam_entry_bdata_get(u, pkm, lpm_entry, sub_idx, fent); 874 875 ALPM_IEG(alpm_cb_dbg_process(u, vrf_id, pkm, acb, fent, 0, 876 key, key_pfx_len, idx, sub_idx, &adata0, dp)); 877 878 } /* for sub_idx */ 879 } /* for idx */ 880 } /* for pk */ 881 882 if (ALPMC(u)->_alpm_dbg_info_bmp & _ALPM_DBG_INFO_CNT) { 883 bit128 = !!tcam_table_size(u, ALPM_PKM_128); 884 /* count bkt sharing */ 885 for (i = 0; i < ACB_CNT(u); i++) { 886 acb = ACB(u, i); 887 for (pid = 0; pid < ALPM_BKT_PID_CNT; pid++) { 888 bp_conf = ACB_BKT_POOL(acb, pid); 889 if (pid > 0 && bp_conf == ACB_BKT_POOL(acb, pid - 1)) { 890 continue; /* Combined Mode uses PID=0 only */ 891 } 892 dp = &dbg[pid]; 893 for (j = 0; j < dp->dc[i].bucket_max; j++) { 894 if (dp->bktref[i][j] != 0) { 895 dp->dc[i].bucket_used++; 896 } 897 898 for (k = 0; k < ALPM_BPB_MAX; k++) { 899 if (dp->bktref[i][j] == (k+1)) { 900 dp->dc[i].bs[k]++; 901 } 902 } 903 } 904 } 905 } 906 907 LOG_CLI(("\n")); 908 LOG_CLI(("%-24s%s %s\n", "Mode:", 909 lvl_str[ACB_CNT(u) - 1], mode_str[ALPM_MODE(u)])); 910 LOG_CLI(("%-24s%d\n", "IPv6 Bits:", bit128 ? 128 : 64)); 911 912 #if defined(BCM_TRIDENT3_SUPPORT) 913 if (SOC_IS_TRIDENT3X(u)) { /* for TD3X specific only */ 914 urpf = SOC_URPF_STATUS_GET(u); 915 LOG_CLI(("%-24s%s\n", "uRPF:", urpf ? "Enable" : "Disable")); 916 for (i = 0; i < 5; i++) { 917 LOG_CLI(("%-24s%s | %2d EPBkt | %2d EPBnk\n", 918 ipver_str[i], 919 ACB_BKT_DW(acb) ? dw_str : sw_str, 920 (fmt_ent_max[i] * ACB_PHY_BNK_PER_BKT(acb)) << ACB_BKT_DW(acb), 921 fmt_ent_max[i])); 922 } 923 LOG_CLI(("\n")); 924 LOG_CLI(("HW Status:\n")); 925 SOC_IF_ERROR_RETURN(READ_L3_DEFIP_RPF_CONTROLr(u, &rval)); 926 alpm = soc_reg_field_get(u, L3_DEFIP_RPF_CONTROLr, rval, LPM_MODEf); 927 if (alpm != 0) { 928 mode = soc_reg_field_get(u, L3_DEFIP_RPF_CONTROLr, rval, LOOKUP_MODEf); 929 } 930 urpf = soc_reg_field_get(u, L3_DEFIP_RPF_CONTROLr, rval, DEFIP_RPF_ENABLEf); 931 LOG_CLI(("\n")); 932 LOG_CLI(("%-24s%s\n", "Mode:", mode_str[mode])); 933 bit128 = !!soc_mem_index_count(u, L3_DEFIP_PAIR_128m); 934 LOG_CLI(("%-24s%d\n", "IPv6 Bits:", bit128 ? 128 : 64)); 935 LOG_CLI(("%-24s%s\n", "uRPF:", urpf ? "Enable" : "Disable")); 936 if (alpm == 0) { 937 return SOC_E_NONE; 938 } 939 if (mode == 0 && !urpf) { /* Combined mode && uRPF */ 940 fv = 1; 941 } else if (mode == 2) { /* TCAM/ALPM mode */ 942 fv = 1; 943 } else { /* Parallel mode */ 944 fv = 0; 945 } 946 LOG_CLI(("%-24s%s\n", "IPv4:", fv ? dw_str : sw_str)); 947 if (mode == 0 && !urpf) { /* Combined mode && uRPF */ 948 fv = 1; 949 } else if (mode == 2) { /* TCAM/ALPM mode */ 950 fv = 1; 951 } else { /* Parallel mode */ 952 fv = 0; 953 } 954 LOG_CLI(("%-24s%s\n", "IPv6-64:", fv ? dw_str : sw_str)); 955 LOG_CLI(("%-24s%s\n", "IPv6-128:", fv ? dw_str : sw_str)); 956 if (SOC_REG_IS_VALID(u, ISS_LOG_TO_PHY_BANK_MAP_2r)) { 957 SOC_IF_ERROR_RETURN(READ_ISS_LOG_TO_PHY_BANK_MAP_2r(u, &rval)); 958 bnkbits = soc_reg_field_get(u, ISS_LOG_TO_PHY_BANK_MAP_2r, rval, 959 ALPM_BANK_MODEf); 960 } 961 LOG_CLI(("%-24s%d\n", "Num Banks:", bnkbits == 0 ? 8 : 4)); 962 } 963 #endif 964 LOG_CLI(("%-24s%s\n", "Bucket sharing:", "Enable")); 965 LOG_CLI(("%-24s%s\n", "Global/Private Zoned:", 966 ALPM_TCAM_ZONED(u) ? "Yes" : "No")); 967 LOG_CLI(("%-24s%s\n", "SW Prefix Lookup:", "Yes")); 968 LOG_CLI(("%-24s%d\n", "Direct Route Glb High:", glb_hi_cnt)); 969 LOG_CLI(("%-24s%d\n", "Direct Route Glb Low:", glb_lo_cnt)); 970 LOG_CLI(("---------------------------------------\n")); 971 LOG_CLI(("\n")); 972 for (i = 0; i < ACB_CNT(u); i++) { 973 acb = ACB(u, i); 974 LOG_CLI(("== %s\n", alpm_util_acb_str[i])); 975 LOG_CLI(("%-24s%d\n", "Num Banks:", ACB_PHY_BNK_PER_BKT(acb))); 976 LOG_CLI(("%-24s%d\n", "Bank bits:", ACB_BNK_BITS(acb))); 977 LOG_CLI(("%-24s%d\n", "Num Buckets:", ACB_BKT_CNT(acb))); 978 LOG_CLI(("%-24s%d\n", "Bucket bits:", ACB_BKT_BITS(acb))); 979 LOG_CLI(("%-24s0x%x\n", "Bucket Mask:", ACB_BKT_CNT(acb) - 1)); 980 LOG_CLI(("\n")); 981 for (pid = 0; pid < ALPM_BKT_PID_CNT; pid++) { 982 bp_conf = ACB_BKT_POOL(acb, pid); 983 if (pid > 0 && bp_conf == ACB_BKT_POOL(acb, pid - 1)) { 984 continue; /* Combined Mode uses PID=0 only */ 985 } 986 dp = &dbg[pid]; 987 988 if (ALPM_TCAM_ZONED(u)) { 989 LOG_CLI(("%s\n", (pid == 0 ? "-- Private:" : "-- Global:"))); 990 } else { 991 LOG_CLI(("-- Private & Global:\n")); 992 } 993 994 LOG_CLI(("%-24s\n", "Pivots:")); 995 for (pkm = 0; pkm < ALPM_PKM_CNT; pkm++) { 996 if (ACB_HAS_TCAM(acb)) { 997 LOG_CLI((" %-22s%d/%-4d\n", alpm_util_pkm_str[pkm], 998 dp->dc[i].pvt_used[pkm], 999 dp->dc[i].pvt_max[pkm])); 1000 } else { 1001 LOG_CLI((" %-22s%d/%-4d\n", alpm_util_pkm_str[pkm], 1002 dp->dc[i].pvt_used[pkm], 1003 dp->dc[i-1].ent_max)); 1004 } 1005 } 1006 1007 LOG_CLI(("%-24s%d/%-4d\n", "Buckets:", 1008 dp->dc[i].bucket_used, dp->dc[i].bucket_max)); 1009 LOG_CLI(("%-24s%d/%-4d\n", "Banks:", 1010 dp->dc[i].bank_used, dp->dc[i].bank_max)); 1011 ent_used_tot = dp->dc[i].ent_used[ALPM_PKM_32B] + 1012 dp->dc[i].ent_used[ALPM_PKM_64B] + 1013 dp->dc[i].ent_used[ALPM_PKM_128]; 1014 LOG_CLI(("%-24s%d/%-4d\n", "Bucket Entries:", 1015 ent_used_tot, dp->dc[i].ent_max)); 1016 for (pkm = 0; pkm < ALPM_PKM_CNT; pkm++) { 1017 LOG_CLI((" %-22s%d\n", alpm_util_pkm_str[pkm], 1018 dp->dc[i].ent_used[pkm])); 1019 } 1020 1021 LOG_CLI(("%s\n", "Bucket Sharing Count:")); 1022 for (k = 0; k < BPC_BNK_PER_BKT(bp_conf); k++) { 1023 LOG_CLI((" %1d%-21s%d\n", (k+1), "->1:", dp->dc[i].bs[k])); 1024 } 1025 1026 if (ACB_HAS_RTE(acb, ALPM_BPC_PID_TO_VRF_ID(u, pid))) { 1027 LOG_CLI(("%-24s%d\n", "Total Routes:", dp->route_cnt)); 1028 LOG_CLI(("%-24s%d\n", "Total Hit Routes:", dp->hit_cnt)); 1029 } 1030 LOG_CLI(("\n")); 1031 } 1032 } 1033 } 1034 1035 bad: 1036 for (i = 0; i < ACB_CNT(u); i++) { 1037 acb = ACB(u, i); 1038 for (pid = 0; pid < ALPM_BKT_PID_CNT; pid++) { 1039 bp_conf = ACB_BKT_POOL(acb, pid); 1040 if (pid > 0 && bp_conf == ACB_BKT_POOL(acb, pid - 1)) { 1041 continue; /* Combined Mode uses PID=0 only */ 1042 } 1043 dp = &dbg[pid]; 1044 if (dp->bktref[i]) { 1045 alpm_util_free(dp->bktref[i]); 1046 dp->bktref[i] = NULL; 1047 } 1048 } 1049 } 1050 return rv; 1051 } 1052 1053 /* Compare a prefix Hw lookup result (ip, sublen, intf) */ 1054 STATIC int 1055 alpm_pfx_hw_route_cb(_alpm_pfx_node_t *pfx_node, void *user_data) 1056 { 1057 _alpm_trv_data_t *trv_data = (_alpm_trv_data_t *)user_data; 1058 int u = trv_data->unit; 1059 int ipt = trv_data->ipt; 1060 int vrf_id = trv_data->vrf_id; 1061 int found_vrf_id; 1062 int ipv6 = ALPM_IS_IPV6(ipt); 1063 _alpm_bkt_node_t *bkt_node = pfx_node->bkt_ptr; 1064 _bcm_defip_cfg_t lpm_cfg; 1065 int nh_ecmp_idx, dest, err = 0; 1066 bcm_ip_t defip_ip_addr = 0; 1067 bcm_ip6_t defip_ip6_addr = {0}; 1068 int defip_sub_len; 1069 char ip_buf[IP6ADDR_STR_LEN]; 1070 int rv = BCM_E_NONE; 1071 1072 if (bkt_node == NULL) { 1073 return rv; 1074 } 1075 1076 sal_memset(&lpm_cfg, 0, sizeof(lpm_cfg)); 1077 lpm_cfg.defip_vrf = ALPM_VRF_ID_TO_VRF(u, vrf_id); 1078 lpm_cfg.defip_flags |= (ipv6 ? BCM_L3_IP6 : 0); 1079 1080 alpm_trie_pfx_to_cfg(u, pfx_node->key, pfx_node->key_len, &lpm_cfg); 1081 1082 dest = bkt_node->adata.defip_ecmp_index; 1083 defip_sub_len = lpm_cfg.defip_sub_len; 1084 if (ipv6) { 1085 sal_memcpy(&defip_ip6_addr, &lpm_cfg.defip_ip6_addr, sizeof(defip_ip6_addr)); 1086 } else { 1087 defip_ip_addr = lpm_cfg.defip_ip_addr; 1088 } 1089 1090 rv = bcm_esw_alpm_find(u, &lpm_cfg, &nh_ecmp_idx); 1091 1092 if (BCM_FAILURE(rv)) { 1093 err = 1; 1094 } else { 1095 found_vrf_id = ALPM_LPM_VRF_ID(u, &lpm_cfg); 1096 /* VRF override match is OK */ 1097 if (found_vrf_id != ALPM_VRF_ID_GHI(u)) { 1098 if ((defip_sub_len != lpm_cfg.defip_sub_len) || (dest != nh_ecmp_idx)) { 1099 err = 2; 1100 } else { 1101 if (ipv6) { 1102 if (sal_memcmp(&defip_ip6_addr, &lpm_cfg.defip_ip6_addr, sizeof(defip_ip6_addr))) { 1103 err = 3; 1104 } 1105 } else { 1106 if (defip_ip_addr != lpm_cfg.defip_ip_addr) { 1107 err = 3; 1108 } 1109 } 1110 } 1111 } 1112 } 1113 1114 if (err) { 1115 if (ipv6) { 1116 alpm_util_fmt_ip6addr(ip_buf, defip_ip6_addr); 1117 } else { 1118 alpm_util_fmt_ipaddr(ip_buf, defip_ip_addr); 1119 } 1120 1121 ALPM_ERR(("PFX %p->BKT %p: IP:%s Sublen:%d Dest:%d => ", 1122 pfx_node, bkt_node, ip_buf, defip_sub_len, dest)); 1123 1124 if (err == 1) { 1125 ALPM_ERR(("couldn't find in Hw (%d)!\n", rv)); 1126 } else { 1127 if (ipv6) { 1128 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg.defip_ip6_addr); 1129 } else { 1130 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg.defip_ip_addr); 1131 } 1132 ALPM_ERR(("wrong Hw route!\n")); 1133 ALPM_ERR((" Current best match Hw route: IP:%s Sublen:%d Dest:%d\n", 1134 ip_buf, lpm_cfg.defip_sub_len, nh_ecmp_idx)); 1135 } 1136 1137 trv_data->err++; 1138 } 1139 1140 return BCM_E_NONE; 1141 } 1142 1143 1144 /* 1145 * Function: 1146 * alpm_pfx_hw_route_sanity 1147 * Purpose: 1148 * Hw route lookup for all prefix trie routes. 1149 * Parameters: 1150 * u - (In)Device unit 1151 * tot_err - (In/Out)Total errors during lookup 1152 * Returns: 1153 * BCM_E_XXX 1154 */ 1155 int 1156 alpm_pfx_hw_route_sanity(int u, int *tot_err) 1157 { 1158 int vrf_id, ipt; 1159 _alpm_trv_data_t trv_data; 1160 1161 trv_data.err = 0; 1162 trv_data.unit = u; 1163 for (ipt = 0; ipt < ALPM_IPT_CNT; ipt++) { 1164 trv_data.ipt = ipt; 1165 for (vrf_id = 0; vrf_id <= ALPM_VRF_ID_MAX(u); vrf_id++) { 1166 if (!ACB_VRF_INITED(u, ACB_VRF_BTM(u, vrf_id), vrf_id, ipt)) { 1167 continue; 1168 } 1169 trv_data.vrf_id = vrf_id; 1170 (void)bcm_esw_alpm_pfx_traverse(u, vrf_id, ipt, 1171 alpm_pfx_hw_route_cb, &trv_data); 1172 } 1173 } 1174 1175 if (trv_data.err) { 1176 ALPM_ERR(("\nNumber of routes with HW routing issue: %d\n", trv_data.err)); 1177 *tot_err += trv_data.err; 1178 } 1179 1180 return BCM_E_NONE; 1181 } 1182 1183 /* 1184 * Function: 1185 * alpm_cb_sanity_process 1186 * Purpose: 1187 * ALPM control block (level) sanity process. 1188 * It's recursive from top to bottom. 1189 * Detection of HW/Sw mismatch or conflict, entry data anormality etc. 1190 * Parameters: 1191 * u - (In)Device unit 1192 * vrf_id - (In)VRF ID 1193 * pkm - (In)PKM 1194 * acb - (In)ALPM control block 1195 * pvtfmt - (In)Pivot bank format (ignored for TCAM) 1196 * fent - (In)ALPM_DATA entry 1197 * key - (In)Key prefix 1198 * key_len - (In)Key prefix length 1199 * idx - (In)Memory Index 1200 * sub_idx - (In)Memory sub_idx (for half-entry) or ent index 1201 * adata - (In)Assoc Data structure pointer 1202 * sanity - (Out)Carrying sanity check info 1203 * Returns: 1204 * BCM_E_XXX 1205 */ 1206 STATIC int 1207 alpm_cb_sanity_process(int u, int vrf_id, int pkm, _alpm_cb_t *acb, 1208 int pvtfmt, void *fent, uint32 *key, int key_len, 1209 int idx, int sub_idx, 1210 _alpm_bkt_adata_t *adata, _alpm_sanity_t *sanity) 1211 { 1212 uint32 bkt_entry[ALPM_MEM_ENT_MAX]; 1213 uint32 fent1[ALPM_MEM_ENT_MAX]; 1214 uint32 ftmp[ALPM_MEM_ENT_MAX]; 1215 uint32 new_key[4]; 1216 uint32 pfx[5], pvt_idx, bkt_idx; 1217 alpm_lib_trie_t *pvt_trie, *pfx_trie, *bkt_trie; 1218 _alpm_pvt_node_t *pvt_node = NULL; 1219 _alpm_pfx_node_t *bkt_node; 1220 _alpm_pfx_node_t *pfx_node; 1221 char ip_buf[IP6ADDR_STR_LEN]; 1222 char err_msg[160]; 1223 uint32 fmt, valid; 1224 int sublen, new_len, def_miss; 1225 int idx1, eid, bnk, trie_idx, trie_ent; 1226 _alpm_bkt_adata_t adata1, bm_adata, adata_local; 1227 int rv = BCM_E_NONE; 1228 int bkt_empty; 1229 _bcm_defip_cfg_t lpm_cfg; 1230 _alpm_bkt_info_t bkt_info; 1231 int pvt_node_pfx_cnt = 0; 1232 int hw_bkt_pfx_cnt = 0; 1233 _alpm_tbl_t bkt_tbl; 1234 _alpm_tbl_t pvt_tbl; 1235 int ipt; 1236 1237 if (ACB_IDX(acb) >= ACB_CNT(u)) { 1238 return BCM_E_INTERNAL; /* wrong ALPM control level called */ 1239 } 1240 1241 ipt = ALPM_PKM2IPT(pkm); 1242 pfx_trie = ALPM_VRF_TRIE(u, vrf_id, ipt); 1243 bkt_tbl = ACB_BKT_TBL(acb, vrf_id); 1244 pvt_tbl = (ACB_HAS_TCAM(acb) ? acb->pvt_tbl[pkm] : 1245 ACB_BKT_TBL(ACB_UPR(u, acb), vrf_id)); 1246 1247 /**** Pivot level ****/ 1248 alpm_util_bkt_info_get(u, vrf_id, ipt, pkm, acb, fent, sub_idx, 1249 &bkt_info, &sublen, &def_miss); 1250 1251 /* kshift must be same as previous key_len */ 1252 if (!ACB_BKT_FIXED_FMT(acb, 1) && sublen != key_len) { 1253 sanity->error++; 1254 ALPM_ERR(("%s: ALPM_DATA invalid kshift:%d vs pivot len:%d" 1255 " idx:%d.%d (%d)\n", ALPM_TBL_NAME(pvt_tbl), sublen, 1256 key_len, idx, sub_idx, BI_BKT_IDX(&bkt_info))); 1257 return BCM_E_NONE; /* just skip the pivot */ 1258 } 1259 if (BI_BKT_IDX(&bkt_info) >= ACB_BKT_CNT(acb)) { 1260 sanity->error++; 1261 ALPM_ERR(("%s: ALPM_DATA invalid bkt_ptr idx:%d.%d (%d)\n", 1262 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, BI_BKT_IDX(&bkt_info))); 1263 return BCM_E_NONE; /* just skip the pivot */ 1264 } 1265 1266 /* HW pivot key vs SW pvt trie */ 1267 rv = BCM_E_NONE; 1268 alpm_trie_key_to_pfx(u, ipt, key, key_len, pfx); 1269 pvt_trie = ACB_PVT_TRIE(acb, vrf_id, ipt); 1270 if (pvt_trie != NULL) { 1271 rv = alpm_lib_trie_search(pvt_trie, pfx, key_len, (alpm_lib_trie_node_t **)&pvt_node); 1272 if (BCM_SUCCESS(rv)) { 1273 if (ACB_HAS_TCAM(acb)) { /* compare tcam_idx */ 1274 if (pkm == ALPM_PKM_32B) { 1275 pvt_idx = idx << 1 | sub_idx; 1276 trie_idx = PVT_IDX(pvt_node) >> 1; 1277 trie_ent = PVT_IDX(pvt_node) & 1; 1278 } else { 1279 pvt_idx = idx; 1280 trie_idx = PVT_IDX(pvt_node); 1281 trie_ent = 0; 1282 } 1283 if (pvt_idx != PVT_IDX(pvt_node)) { 1284 rv = BCM_E_INTERNAL; 1285 sanity->error++; 1286 sal_sprintf(err_msg, "Error: duplicated key as pvt tcam_idx:%d.%d", 1287 trie_idx, trie_ent); 1288 } 1289 } 1290 } else { /* rv = BCM_E_NOT_FOUND */ 1291 sanity->error++; 1292 sal_sprintf(err_msg, "Error: not found in pvt trie"); 1293 pvt_node = NULL; 1294 } 1295 } else { 1296 rv = BCM_E_INTERNAL; 1297 sanity->error++; 1298 sal_sprintf(err_msg, "Error: pvt trie doesn't exist"); 1299 } 1300 1301 if (BCM_FAILURE(rv)) { 1302 alpm_util_cfg_construct(u, vrf_id, ipt, key, key_len, adata, &lpm_cfg); 1303 if (ALPM_IS_IPV4(ipt)) { 1304 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg.defip_ip_addr); 1305 } else { 1306 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg.defip_ip6_addr); 1307 } 1308 if (ACB_HAS_TCAM(acb)) { 1309 ALPM_ERR(("VRF:%d IPT:%s %s: TCAM idx:%d.%d Sublen:%d bpmDest:%d IP:%s\n ==> %s\n", 1310 vrf_id, alpm_util_ipt_str[ipt], ALPM_TBL_NAME(pvt_tbl), 1311 idx, sub_idx, key_len, adata->defip_ecmp_index, 1312 ip_buf, err_msg)); 1313 } else { 1314 ALPM_ERR(("VRF:%d IPT:%s %s: PVT idx:%d.%d Sublen:%d fmt:%d bpmDest:%d IP:%s\n ==> %s\n", 1315 vrf_id, alpm_util_ipt_str[ipt], ALPM_TBL_NAME(pvt_tbl), 1316 idx, sub_idx, key_len, pvtfmt, 1317 adata->defip_ecmp_index, ip_buf, err_msg)); 1318 } 1319 } else { 1320 if (pvt_node && pvt_node->bkt_trie && pvt_node->bkt_trie->trie) { 1321 pvt_node_pfx_cnt = pvt_node->bkt_trie->trie->count; 1322 } 1323 } 1324 1325 #if 0 1326 /* Pivot Assoc_Data Hw validation (only if Default_Miss==0) */ 1327 if (def_miss == FALSE) { 1328 /* through Hw best match lookup */ 1329 ALPM_VERB(("%s: check Pivot idx:%d.%d def_rte => ", 1330 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx)); 1331 sal_memset(&lpm_cfg, 0, sizeof(lpm_cfg)); 1332 /* ALPMTBD: find best match from ALPM only (exclude Direct Routes) */ 1333 rv = alpm_find_best_match(u, vrf_id, pkm, key, key_len, &lpm_cfg); 1334 1335 if (BCM_FAILURE(rv)) { 1336 sanity->error++; 1337 ALPM_ERR(("%s: Pivot idx:%d.%d BPM missing (rv=%d)\n", 1338 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, rv)); 1339 } else { 1340 alpm_util_adata_cfg_to_trie(u, &lpm_cfg, &bm_adata); 1341 /* filter flags BCM_L3_HIT & BCM_L3_IP6 from 1342 bm_adata.defip_flags before memcmp */ 1343 ALPM_FLAGS_FILTER(bm_adata.defip_flags); 1344 if (sal_memcmp((void *)adata, (void *)&bm_adata, 1345 sizeof(_alpm_bkt_adata_t)) != 0) { 1346 sanity->error++; 1347 ALPM_ERR(("%s: Pivot idx:%d.%d Assoc Data mismatch" 1348 " (current vs best match):\n", 1349 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx)); 1350 ALPM_ERR((" defip_flags: %x vs %x, dest: %d vs %d\n", 1351 adata->defip_flags, bm_adata.defip_flags, 1352 adata->defip_ecmp_index, bm_adata.defip_ecmp_index)); 1353 } 1354 } 1355 } 1356 #endif 1357 1358 /* Pvt default route verification & Assoc_Data Sw validation */ 1359 if (pfx_trie != NULL) { 1360 rv = alpm_lib_trie_find_lpm(pfx_trie, pfx, key_len, 1361 (alpm_lib_trie_node_t **)&pfx_node); 1362 if (BCM_FAILURE(rv)) { 1363 if (def_miss == 0) { 1364 sanity->error++; 1365 ALPM_ERR(("%s: Pivot idx:%d.%d BPM missing (rv=%d)\n", 1366 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, rv)); 1367 } 1368 } else { 1369 if (pvt_node != NULL) { 1370 if (PVT_BKT_DEF(pvt_node) != pfx_node->bkt_ptr) { 1371 sanity->error++; 1372 ALPM_ERR(("%s: Pivot idx:%d.%d key_len:%d bpm_len:%d DEF_PFX %p" 1373 " diff than BPM BKT %p\n", 1374 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, 1375 PVT_KEY_LEN(pvt_node), PVT_BPM_LEN(pvt_node), 1376 PVT_BKT_DEF(pvt_node), pfx_node->bkt_ptr)); 1377 } else { 1378 if (def_miss == 1 && PVT_BKT_DEF(pvt_node)) { 1379 sanity->error++; 1380 ALPM_ERR(("%s: Pivot idx:%d.%d Default_Miss=1 but BPM route exits\n", 1381 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx)); 1382 } 1383 } 1384 } 1385 1386 adata_local = *adata; 1387 if (pfx_node->bkt_ptr) { 1388 bm_adata = pfx_node->bkt_ptr->adata; 1389 /* 1390 * filter flags BCM_L3_HIT & BCM_L3_IP6 from 1391 * bm_adata.defip_flags and adata.defip_flags 1392 * before memcmp. 1393 */ 1394 ALPM_FLAGS_FILTER(bm_adata.defip_flags); 1395 ALPM_FLAGS_FILTER(adata_local.defip_flags); 1396 if (sal_memcmp((void *)&adata_local, (void *)&bm_adata, 1397 sizeof(_alpm_bkt_adata_t)) != 0) { 1398 sanity->error++; 1399 ALPM_ERR(("%s: Pivot idx:%d.%d Assoc Data mismatch" 1400 "(current vs bm) flags:%x vs %x dest:%d vs %d\n", 1401 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, 1402 adata_local.defip_flags, bm_adata.defip_flags, 1403 adata_local.defip_ecmp_index, 1404 bm_adata.defip_ecmp_index)); 1405 } 1406 } else { 1407 /* Parallel & TCAM mix mode, pivot sanity check: 1408 no best match def_rte but default_miss = 0 */ 1409 if ((def_miss == 0) && ALPM_TCAM_ZONED(u)) { 1410 sanity->error++; 1411 ALPM_ERR(("%s: Pivot idx:%d.%d w/o bm_rte => " 1412 "wrong def_miss:0 dest:%d\n", 1413 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, 1414 adata_local.defip_ecmp_index)); 1415 } 1416 } 1417 } 1418 } 1419 1420 bkt_empty = TRUE; /* each pivot must have at least one valid bucket entry */ 1421 for (bnk = 0; bnk < ACB_BNK_PER_BKT(acb, vrf_id); bnk++) { 1422 fmt = bkt_info.bnk_fmt[bnk]; 1423 if ((fmt == 0) || (fmt > ACB_FMT_CNT(acb, vrf_id))) { 1424 if (fmt > ACB_FMT_CNT(acb, vrf_id)) { 1425 sanity->error++; 1426 ALPM_ERR(("%s: ALPM_DATA format wrong idx:%d.%d (bank=%d fmt=%d).\n", 1427 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, bnk, fmt)); 1428 } 1429 continue; 1430 } 1431 1432 /**** Bucket Level ****/ 1433 idx1 = ALPM_TAB_IDX_GET_BKT_BNK(acb, BI_ROFS(&bkt_info), BI_BKT_IDX(&bkt_info), bnk); 1434 if (!ACB_BKT_FIXED_FMT(acb, 1)) { /* for TH3 only */ 1435 if (ACB_VRF_PVT_PTR(acb, vrf_id, idx1) == NULL) { 1436 sanity->error++; 1437 ALPM_ERR(("%s: bucket info -> pvt_ptr == NULL at bank %d\n", 1438 ALPM_TBL_NAME(bkt_tbl), idx1)); 1439 } else { 1440 _alpm_pvt_node_t *pvt_node2; 1441 1442 pvt_node2 = (_alpm_pvt_node_t *)ACB_VRF_PVT_PTR(acb, vrf_id, idx1); 1443 if (bkt_info.rofs != pvt_node2->bkt_info.rofs || 1444 bkt_info.bkt_idx != pvt_node2->bkt_info.bkt_idx || 1445 sal_memcmp(bkt_info.bnk_fmt, pvt_node2->bkt_info.bnk_fmt, sizeof(bkt_info.bnk_fmt)) != 0) { 1446 sanity->error++; 1447 ALPM_ERR(("\t%s: sw & hw bkt_info mismatch\n", 1448 ALPM_TBL_NAME(bkt_tbl))); 1449 ALPM_ERR(("\thw rofs %d bkt_idx %d fmt %d %d %d %d %d %d %d %d\n", 1450 bkt_info.rofs, bkt_info.bkt_idx, 1451 bkt_info.bnk_fmt[0], 1452 bkt_info.bnk_fmt[1], 1453 bkt_info.bnk_fmt[2], 1454 bkt_info.bnk_fmt[3], 1455 bkt_info.bnk_fmt[4], 1456 bkt_info.bnk_fmt[5], 1457 bkt_info.bnk_fmt[6], 1458 bkt_info.bnk_fmt[7])); 1459 ALPM_ERR(("\tsw rofs %d bkt_idx %d fmt %d %d %d %d %d %d %d %d\n", 1460 pvt_node2->bkt_info.rofs, pvt_node2->bkt_info.bkt_idx, 1461 pvt_node2->bkt_info.bnk_fmt[0], 1462 pvt_node2->bkt_info.bnk_fmt[1], 1463 pvt_node2->bkt_info.bnk_fmt[2], 1464 pvt_node2->bkt_info.bnk_fmt[3], 1465 pvt_node2->bkt_info.bnk_fmt[4], 1466 pvt_node2->bkt_info.bnk_fmt[5], 1467 pvt_node2->bkt_info.bnk_fmt[6], 1468 pvt_node2->bkt_info.bnk_fmt[7])); 1469 } 1470 } 1471 } 1472 ALPM_IER(alpm_bkt_entry_read_no_cache(u, ACB_BKT_TBL(acb, vrf_id), 1473 acb, bkt_entry, idx1)); 1474 1475 /* verify bucket bank ptr duplication */ 1476 if (sanity->bktptr[ACB_IDX(acb)][idx1] == -1) { 1477 sanity->bktptr[ACB_IDX(acb)][idx1] = idx; 1478 } else { 1479 /* No need to check conflict bucket for bucket sharing */ 1480 if (!ACB_BKT_FIXED_FMT(acb, vrf_id) && 1481 idx != sanity->bktptr[ACB_IDX(acb)][idx1]) { 1482 sanity->error++; 1483 ALPM_ERR(("%s: conflict bucket bank at %d (upr_idx %d vs %d)\n", 1484 ALPM_TBL_NAME(bkt_tbl), idx1, idx, 1485 sanity->bktptr[ACB_IDX(acb)][idx1])); 1486 } /* else: conflict from higher CB, but this level is "OK" */ 1487 } 1488 1489 for (eid = 0; eid < ACB_FMT_ENT_MAX(acb, vrf_id, fmt); eid++) { 1490 uint32 key2[4] = {0}; 1491 int len2 = 0; 1492 int sub_bkt_ptr = 0; 1493 1494 /* process bucket entry Prefix */ 1495 alpm_util_ent_ent_get(u, vrf_id, acb, bkt_entry, fmt, eid, ftmp); 1496 alpm_util_bkt_pfx_get(u, vrf_id, acb, ftmp, fmt, key2, &len2, &valid); 1497 alpm_util_bkt_adata_get(u, vrf_id, ipt, acb, ftmp, fmt, &adata1, &sub_bkt_ptr); 1498 1499 if (!valid || BI_SUB_BKT_IDX(&bkt_info) != sub_bkt_ptr) { 1500 continue; 1501 } else { 1502 if (ACB_BKT_FIXED_FMT(acb, 1)) { 1503 new_len = len2; 1504 sal_memcpy(new_key, key2, sizeof(new_key)); 1505 } else { 1506 alpm_util_pfx_cat(u, ipt, key, sublen, key2, len2, new_key, &new_len); 1507 } 1508 } 1509 bkt_empty = FALSE; /* at least one bucket entry */ 1510 hw_bkt_pfx_cnt ++; 1511 1512 rv = BCM_E_NONE; 1513 if (new_len == 0 && 1514 (new_key[0] != 0 || new_key[1] != 0 || 1515 new_key[2] != 0 || new_key[3] != 0)) { 1516 rv = BCM_E_INTERNAL; 1517 sanity->error++; 1518 sal_sprintf(err_msg, 1519 "Error: length is 0 but key is not, in bkt%d bnk%d ent%d", 1520 BI_BKT_IDX(&bkt_info), bnk, eid); 1521 } 1522 1523 if (BCM_SUCCESS(rv)) { 1524 /* process bucket entry ASSOC_DATA */ 1525 alpm_trie_key_to_pfx(u, ipt, new_key, new_len, pfx); 1526 1527 /* HW bucket key vs SW bkt trie */ 1528 if (pvt_node != NULL) { 1529 bkt_trie = PVT_BKT_TRIE(pvt_node); 1530 if (bkt_trie != NULL) { 1531 rv = alpm_lib_trie_search(bkt_trie, pfx, new_len, 1532 (alpm_lib_trie_node_t **)&bkt_node); 1533 if (BCM_SUCCESS(rv)) { 1534 bkt_idx = idx1 | ((eid & ALPM_IDX_ENT_MASK) 1535 << ALPM_IDX_ENT_SHIFT); 1536 if (bkt_idx != bkt_node->ent_idx) { 1537 rv = BCM_E_INTERNAL; 1538 sanity->error++; 1539 trie_idx = ALPM_TAB_IDX_GET(bkt_node->ent_idx); 1540 trie_ent = ALPM_IDX_TO_ENT(bkt_node->ent_idx); 1541 sal_sprintf(err_msg, 1542 "Error: duplicated key as bkt ent_idx:%d(bkt%d bnk%d).%d", 1543 trie_idx, ALPM_IDX_TO_BKT(acb, bkt_node->ent_idx), 1544 ALPM_IDX_TO_BNK(acb, bkt_node->ent_idx), 1545 trie_ent); 1546 } 1547 } else { 1548 sanity->error++; 1549 sal_sprintf(err_msg, "Error: not found in bkt trie"); 1550 } 1551 } else { 1552 rv = BCM_E_INTERNAL; 1553 sanity->error++; 1554 sal_sprintf(err_msg, "Error: bkt trie doesn't exist"); 1555 } 1556 } 1557 } 1558 1559 if (BCM_FAILURE(rv)) { 1560 alpm_util_cfg_construct(u, vrf_id, ipt, new_key, new_len, 1561 &adata1, &lpm_cfg); 1562 if (ALPM_IS_IPV4(ipt)) { 1563 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg.defip_ip_addr); 1564 } else { 1565 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg.defip_ip6_addr); 1566 } 1567 ALPM_ERR(("VRF:%d IPT:%s %s: BKT idx:%d(bkt%d bnk%d).%d Sublen:%d" 1568 " fmt:%d Dest:%d IP:%s\n ==> %s\n", 1569 vrf_id, alpm_util_ipt_str[ipt], 1570 ALPM_TBL_NAME(bkt_tbl), 1571 idx1, BI_BKT_IDX(&bkt_info), bnk, eid, new_len, fmt, 1572 adata1.defip_ecmp_index, ip_buf, err_msg)); 1573 } 1574 1575 /* end recursion here if reach to route level (last level) */ 1576 if (ACB_HAS_RTE(acb, vrf_id)) { 1577 /* HW route vs SW prefix trie */ 1578 if (BCM_SUCCESS(rv)) { /* if failed on bkt, bypass pfx check */ 1579 if (pfx_trie != NULL) { 1580 rv = alpm_lib_trie_search(pfx_trie, pfx, new_len, 1581 (alpm_lib_trie_node_t **)&pfx_node); 1582 if (BCM_SUCCESS(rv)) { 1583 bkt_idx = idx1 | ((eid & ALPM_IDX_ENT_MASK) 1584 << ALPM_IDX_ENT_SHIFT); 1585 if (bkt_idx != pfx_node->bkt_ptr->ent_idx) { 1586 rv = BCM_E_INTERNAL; 1587 sanity->error++; 1588 trie_idx = ALPM_TAB_IDX_GET(bkt_node->ent_idx); 1589 trie_ent = ALPM_IDX_TO_ENT(bkt_node->ent_idx); 1590 sal_sprintf(err_msg, 1591 "Error: duplicated key as bkt ent_idx:%d.%d", 1592 trie_idx, trie_ent); 1593 } 1594 } else { 1595 sanity->error++; 1596 sal_sprintf(err_msg, "Error: not found in prefix trie"); 1597 } 1598 } else { 1599 rv = BCM_E_INTERNAL; 1600 sanity->error++; 1601 sal_sprintf(err_msg, "Error: pfx trie doesn't exist"); 1602 } 1603 1604 if (BCM_FAILURE(rv)) { 1605 alpm_util_cfg_construct(u, vrf_id, ipt, new_key, new_len, 1606 &adata1, &lpm_cfg); 1607 if (ALPM_IS_IPV4(ipt)) { 1608 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg.defip_ip_addr); 1609 } else { 1610 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg.defip_ip6_addr); 1611 } 1612 ALPM_ERR(("VRF:%d IPT:%s %s: RTE idx:%d.%d Sublen:%d" 1613 " fmt:%d Dest:%d IP:%s\n ==> %s\n", 1614 vrf_id, alpm_util_ipt_str[ipt], 1615 ALPM_TBL_NAME(bkt_tbl), 1616 idx1, eid, new_len, fmt, 1617 adata1.defip_ecmp_index, ip_buf, err_msg)); 1618 } 1619 } 1620 continue; 1621 } 1622 1623 /* prevent going further down if somehow last level 1624 is not Route level due to internal failure */ 1625 if ((ACB_IDX(acb) + 1) >= ACB_CNT(u)) { 1626 return BCM_E_INTERNAL; 1627 } 1628 1629 /* get ALPM Data entry ready for next level */ 1630 alpm_util_ent_data_get(u, vrf_id, ipt, acb, ftmp, fmt, fent1); 1631 ALPM_IER(alpm_cb_sanity_process(u, vrf_id, ipt, ACB_DWN(u, acb), 1632 fmt, fent1, new_key, new_len, 1633 idx1, eid, &adata1, sanity)); 1634 } /* for eid */ 1635 } /* for bnk */ 1636 1637 if (hw_bkt_pfx_cnt != pvt_node_pfx_cnt) { 1638 sanity->error++; 1639 ALPM_ERR(("%s: Pivot idx:%d.%d pfx count(%d) does not match to hw bkt(bkt=%d,dw=%d) pfx count(%d)\n", 1640 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, pvt_node_pfx_cnt, 1641 PVT_BKT_IDX(pvt_node), ACB_BKT_DW(acb), hw_bkt_pfx_cnt)); 1642 } 1643 1644 /* each pivot must have at least one valid bucket entry except 1645 * default pivot */ 1646 if (bkt_empty && key_len != 0) { 1647 sanity->error++; 1648 ALPM_ERR(("%s: Pivot idx:%d.%d with empty bucket (or route).\n", 1649 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx)); 1650 } 1651 return BCM_E_NONE; 1652 } 1653 1654 /* 1655 * Function: 1656 * bcm_esw_alpm_sanity_check 1657 * Purpose: 1658 * Sanity check for ALPM 1659 * Parameters: 1660 * u - (In)Device unit 1661 * mem - (In)TCAM memory (not in used) 1662 * index - (In)Memory index (not in used) 1663 * check_sw - (In)check_sw = 0 for prefix Hw routing check 1664 * Returns: 1665 * BCM_E_XXX 1666 */ 1667 int 1668 bcm_esw_alpm_sanity_check(int u, soc_mem_t mem, int index, int check_sw) 1669 { 1670 int ipv6, key_mode; 1671 int idx, sub_idx; 1672 int vrf_id; 1673 int idx_end; 1674 int step_size; 1675 uint32 lpm_entry[ALPM_MEM_ENT_MAX]; 1676 uint32 fent[ALPM_MEM_ENT_MAX]; 1677 _alpm_cb_t *acb; 1678 _alpm_bkt_adata_t adata0; 1679 int pk, pkm, use_alpm; 1680 uint32 key[4]; 1681 int key_pfx_len; 1682 int i, alloc_sz, pid, tot_error = 0; 1683 _alpm_sanity_t sanity[ALPM_BKT_PID_CNT]; 1684 _alpm_sanity_t *psanity; 1685 int rv = BCM_E_NONE; 1686 int rv_tcam; 1687 _alpm_bkt_pool_conf_t *bp_conf; 1688 1689 if (ALPMC(u) == NULL) { 1690 return BCM_E_INIT; 1691 } 1692 1693 for (i = 0; i < ACB_CNT(u); i++) { 1694 acb = ACB(u, i); 1695 1696 for (pid = 0; pid < ALPM_BKT_PID_CNT; pid++) { 1697 bp_conf = ACB_BKT_POOL(acb, pid); 1698 if (pid > 0 && bp_conf == ACB_BKT_POOL(acb, pid - 1)) { 1699 continue; /* Combined Mode uses only PID=0 for sanity counters */ 1700 } 1701 1702 psanity = &sanity[pid]; 1703 alloc_sz = BPC_BNK_CNT(bp_conf) * sizeof(int); 1704 ALPM_ALLOC_EG(psanity->bktptr[i], alloc_sz, "bktptr"); 1705 /* initialized to -1 to distinguish index 0 */ 1706 sal_memset(psanity->bktptr[i], 0xff, alloc_sz); 1707 psanity->error = 0; 1708 } 1709 } 1710 1711 acb = ACB_TOP(u); /* from top to bottom */ 1712 1713 L3_LOCK(u); 1714 for (pk = 0; pk < ALPM_PKM_CNT; pk++) { 1715 if (ALPM_TCAM_TBL_SKIP(u, pk)) { 1716 continue; /* skip duplicated or invalid TCAM table */ 1717 } 1718 1719 /* LOG_CLI(("\n- Processing %s ...\n", TCAM_TBL_NAME(acb, pk))); */ 1720 idx_end = tcam_table_size(u, pk); 1721 /* Walk all TCAM entries */ 1722 for (idx = 0; idx < idx_end; idx++) { 1723 ALPM_IEG(tcam_entry_read_no_cache(u, pk, lpm_entry, idx, idx)); 1724 1725 for (sub_idx = 0; sub_idx < ALPM_TCAM_SUBCNT; sub_idx += step_size) { 1726 rv_tcam = tcam_valid_entry_mode_get(u, pk, lpm_entry, 1727 &step_size, &pkm, &ipv6, &key_mode, sub_idx); 1728 if (BCM_FAILURE(rv_tcam)) { 1729 if (rv_tcam == BCM_E_INTERNAL) { 1730 ALPM_ERR(("%s: Invalid Key Mode:%d or Key Type" 1731 " (IPv6):%d in idx:%d.%d\n", 1732 TCAM_TBL_NAME(acb, pk), key_mode, 1733 ipv6, idx, sub_idx)); 1734 } 1735 continue; 1736 } 1737 tcam_entry_vrf_id_get(u, pkm, lpm_entry, sub_idx, &vrf_id); 1738 1739 /* process pre-pivor ASSOC_DATA */ 1740 tcam_entry_adata_get(u, pkm, lpm_entry, sub_idx, &adata0); 1741 use_alpm = !(adata0.defip_flags & BCM_L3_IPMC) && 1742 ALPM_VRF_ID_HAS_BKT(u, vrf_id); 1743 if (!use_alpm) { 1744 continue; 1745 } 1746 1747 /* Get Pre-pivot key IP_ADDR and prefix length (mask) */ 1748 sal_memset(key, 0, sizeof(key)); 1749 key_pfx_len = 0; 1750 tcam_entry_to_key(u, pkm, lpm_entry, sub_idx, key); 1751 tcam_entry_pfx_len_get(u, pkm, lpm_entry, sub_idx, &key_pfx_len); 1752 1753 /* process ALPM_DATA level recursively from top to bottom */ 1754 tcam_entry_bdata_get(u, pkm, lpm_entry, sub_idx, fent); 1755 1756 /* Combined Mode uses only PID=0 for sanity counters */ 1757 pid = ACB_BKT_VRF_PID(acb, vrf_id); 1758 psanity = &sanity[pid]; 1759 ALPM_IEG(alpm_cb_sanity_process(u, vrf_id, pkm, acb, 0, fent, 1760 key, key_pfx_len, idx, sub_idx, 1761 &adata0, psanity)); 1762 } /* for sub_idx */ 1763 } /* for idx */ 1764 } /* for pk */ 1765 1766 if (check_sw == 0) { 1767 rv = alpm_pfx_hw_route_sanity(u, &tot_error); 1768 } 1769 1770 bad: 1771 L3_UNLOCK(u); 1772 for (i = 0; i < ACB_CNT(u); i++) { 1773 acb = ACB(u, i); 1774 for (pid = 0; pid < ALPM_BKT_PID_CNT; pid++) { 1775 bp_conf = ACB_BKT_POOL(acb, pid); 1776 if (pid > 0 && bp_conf == ACB_BKT_POOL(acb, pid - 1)) { 1777 continue; /* Combined Mode uses only PID=0 for sanity counters */ 1778 } 1779 1780 psanity = &sanity[pid]; 1781 if (psanity->bktptr[i]) { 1782 alpm_util_free(psanity->bktptr[i]); 1783 psanity->bktptr[i] = NULL; 1784 } 1785 tot_error += psanity->error; 1786 } 1787 } 1788 1789 if (rv == BCM_E_NONE) { 1790 rv = (tot_error ? BCM_E_FAIL : BCM_E_NONE); 1791 if (ALPMTR_TRACE_EN(u)) { 1792 LOG_CLI(("RTE#%d ", ALPMTR_CNT(u))); 1793 } 1794 if (BCM_SUCCESS(rv)) { 1795 LOG_CLI(("L3 ALPM sanity check: passed!\n")); 1796 } 1797 } 1798 1799 return rv; 1800 } 1801 1802 /* 1803 * Function: 1804 * alpm_cb_bm_lookup 1805 * Purpose: 1806 * ALPM bucket best match lookup per CB by Hw (recursive from top to bottom). 1807 * Parameters: 1808 * u - (In)Device unit 1809 * vrf_id - (In)VRF ID 1810 * pkm - (In)PKM 1811 * acb - (In)ALPM control block pointer 1812 * fent - (In)ALPM_DATA entry 1813 * pvtfmt - (In)Pivot bank format (ignored for TCAM) 1814 * key - (In)Key prefix 1815 * key_len - (In)Key prefix length 1816 * idx - (In)Memory Index 1817 * sub_idx - (In)Memory sub_idx (for half-entry) or ent index 1818 * adata - (In)Assoc Data structure pointer 1819 * lpm_cfg - (Out)BPM defip cfg info found 1820 * hit_res - (Out)Lookup result in the bucket 1821 * sw_key - (In)Key to lookup 1822 * sw_len - (In)Key length to lookup 1823 * Returns: 1824 * BCM_E_XXX 1825 */ 1826 STATIC int 1827 alpm_cb_bm_lookup(int u, int vrf_id, int pkm, _alpm_cb_t *acb, void *fent, 1828 int pvtfmt, uint32 *key, int key_len, int idx, int sub_idx, 1829 _alpm_bkt_adata_t *adata, _bcm_defip_cfg_t *lpm_cfg, 1830 _alpm_lkup_res_t *hit_res, uint32 *sw_key, int sw_len) 1831 { 1832 uint32 bkt_entry[ALPM_MEM_ENT_MAX]; 1833 uint32 ftmp[ALPM_MEM_ENT_MAX]; 1834 uint32 hw_mask[4]; 1835 uint32 hw_key[4]; 1836 uint32 fmt, valid; 1837 int i, sublen, hw_len, key_ent_cnt; 1838 int idx1, eid, bnk; 1839 char ip_buf[IP6ADDR_STR_LEN]; 1840 _bcm_defip_cfg_t lpm_cfg_tmp; 1841 _alpm_bkt_adata_t adata_tmp; 1842 _alpm_bkt_adata_t adata1; 1843 int def_miss = TRUE; 1844 _alpm_lkup_res_t hit_res1 = ALPM_MISS; /* lookup result from next CB */ 1845 int hit_val; 1846 /* Used for keeping Longest Matched entry in Bucket */ 1847 int bm_len = -1; 1848 int bm_idx = 0; 1849 int bm_ent = 0; 1850 uint32 bm_fmt = 0; 1851 uint32 bm_key[4]; 1852 uint32 bm_fent[ALPM_MEM_ENT_MAX]; 1853 _alpm_bkt_info_t bkt_info; 1854 _alpm_tbl_t bkt_tbl; 1855 _alpm_tbl_t pvt_tbl; 1856 int ipt = ALPM_PKM2IPT(pkm); 1857 1858 if (ACB_IDX(acb) >= ACB_CNT(u)) { 1859 return BCM_E_INTERNAL; /* wrong ALPM control level called */ 1860 } 1861 1862 bkt_tbl = ACB_BKT_TBL(acb, vrf_id); 1863 pvt_tbl = (ACB_HAS_TCAM(acb) ? acb->pvt_tbl[pkm] : 1864 ACB_BKT_TBL(ACB_UPR(u, acb), vrf_id)); 1865 1866 /**** Pivot level ****/ 1867 alpm_util_bkt_info_get(u, vrf_id, ipt, pkm, acb, fent, sub_idx, 1868 &bkt_info, &sublen, &def_miss); 1869 1870 /* show pivot hit info */ 1871 alpm_util_cfg_construct(u, vrf_id, ipt, key, key_len, adata, &lpm_cfg_tmp); 1872 if (ALPM_IS_IPV4(ipt)) { 1873 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg_tmp.defip_ip_addr); 1874 } else { 1875 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg_tmp.defip_ip6_addr); 1876 } 1877 1878 /*if (ACB_HAS_TCAM(acb)) { 1879 ALPM_VERB(("Hit pivot in %s: idx:%d.%d VRF:%d%s IP:%s Sublen:%d\n", 1880 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, 1881 vrf_id, (vrf_id == ALPM_VRF_ID_GLO(u)? "(Global low)" : ""), 1882 ip_buf, key_len)); 1883 } else { 1884 ALPM_VERB(("Hit pivot in %s: idx:%d.%d fmt:%d IP:%s Sublen:%d\n", 1885 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, pvtfmt, ip_buf, key_len)); 1886 }*/ 1887 1888 /* kshift must be same as previous key_len */ 1889 if (!ACB_BKT_FIXED_FMT(acb, 1) && sublen != key_len) { 1890 ALPM_ERR(("%s: ALPM_DATA invalid kshift:%d vs pivot len:%d" 1891 " idx:%d.%d (%d)\n", ALPM_TBL_NAME(pvt_tbl), sublen, 1892 key_len, idx, sub_idx, BI_BKT_IDX(&bkt_info))); 1893 return BCM_E_NONE; /* just skip the pivot */ 1894 } 1895 if (BI_BKT_IDX(&bkt_info) >= ACB_BKT_CNT(acb)) { 1896 ALPM_ERR(("%s: ALPM_DATA invalid bkt_ptr idx:%d.%d (%d)\n", 1897 ALPM_TBL_NAME(pvt_tbl), idx, sub_idx, BI_BKT_IDX(&bkt_info))); 1898 return BCM_E_NONE; /* just skip the pivot */ 1899 } 1900 1901 for (bnk = 0; bnk < ACB_BNK_PER_BKT(acb, vrf_id); bnk++) { 1902 fmt = bkt_info.bnk_fmt[bnk]; 1903 if ((fmt == 0) || (fmt > ACB_FMT_CNT(acb, vrf_id))) { 1904 if (fmt > ACB_FMT_CNT(acb, vrf_id)) { 1905 ALPM_ERR(("%s: ALPM_DATA format wrong idx:%d.%d" 1906 " (bank=%d fmt=%d).\n", ALPM_TBL_NAME(pvt_tbl), 1907 idx, sub_idx, bnk, fmt)); 1908 } 1909 continue; 1910 } 1911 1912 /**** Bucket Level ****/ 1913 idx1 = ALPM_TAB_IDX_GET_BKT_BNK(acb, BI_ROFS(&bkt_info), BI_BKT_IDX(&bkt_info), bnk); 1914 ALPM_IER(alpm_bkt_entry_read(u, ACB_BKT_TBL(acb, vrf_id), 1915 acb, bkt_entry, idx1)); 1916 1917 for (eid = 0; eid < ACB_FMT_ENT_MAX(acb, vrf_id, fmt); eid++) { 1918 uint32 key2[4] = {0}; 1919 int len2 = 0; 1920 int sub_bkt_ptr = 0; 1921 1922 /* process bucket entry Prefix */ 1923 alpm_util_ent_ent_get(u, vrf_id, acb, bkt_entry, fmt, eid, ftmp); 1924 alpm_util_bkt_pfx_get(u, vrf_id, acb, ftmp, fmt, key2, &len2, &valid); 1925 alpm_util_bkt_adata_get(u, vrf_id, ipt, acb, ftmp, fmt, &adata_tmp, &sub_bkt_ptr); 1926 1927 if (!valid || BI_SUB_BKT_IDX(&bkt_info) != sub_bkt_ptr) { 1928 continue; 1929 } 1930 1931 if (ACB_BKT_FIXED_FMT(acb, 1)) { 1932 hw_len = len2; 1933 sal_memcpy(hw_key, key2, sizeof(hw_key)); 1934 } else { 1935 alpm_util_pfx_cat(u, ipt, key, sublen, key2, len2, hw_key, &hw_len); 1936 } 1937 1938 if (hw_len > sw_len) { /* invalid or not match */ 1939 continue; 1940 } 1941 alpm_util_len_to_mask(ipt, hw_len, hw_mask); 1942 1943 /* new_len <= sw_len: compare all hw_masked key */ 1944 key_ent_cnt = ALPM_KEY_ENT_CNT(ipt); 1945 for (i = 0; i < key_ent_cnt; i++) { 1946 if ((sw_key[i] & hw_mask[i]) != (hw_key[i] & hw_mask[i])) { 1947 break; 1948 } 1949 } 1950 /* Not match */ 1951 if (i < key_ent_cnt) { 1952 continue; 1953 } 1954 1955 /* Found a match, keep longest matched route */ 1956 if (hw_len > bm_len) { 1957 bm_len = hw_len; 1958 bm_fmt = fmt; 1959 bm_idx = idx1; /* ALPM bucket mem index */ 1960 bm_ent = eid; 1961 sal_memcpy(bm_key, hw_key, sizeof(hw_key)); 1962 sal_memcpy(bm_fent, ftmp, sizeof(ftmp)); 1963 sal_memcpy(&adata1, &adata_tmp, sizeof(adata_tmp)); 1964 } 1965 } /* for ent */ 1966 } /* for bnk */ 1967 1968 /* Hit in bucket */ 1969 if (bm_len != -1) { 1970 /* end recursion down if reach route level (last level) */ 1971 if (ACB_HAS_RTE(acb, vrf_id)) { 1972 *hit_res = ALPM_HIT; 1973 alpm_util_cfg_construct(u, vrf_id, ipt, bm_key, bm_len, 1974 &adata1, &lpm_cfg_tmp); 1975 if (ALPM_IS_IPV4(ipt)) { 1976 alpm_util_fmt_ipaddr(ip_buf, lpm_cfg_tmp.defip_ip_addr); 1977 } else { 1978 alpm_util_fmt_ip6addr(ip_buf, lpm_cfg_tmp.defip_ip6_addr); 1979 } 1980 1981 /*ALPM_VERB(("Hit route in %s idx:%d.%d fmt:%d IP:%s Sublen:%d\n", 1982 ALPM_TBL_NAME(bkt_tbl), bm_idx, bm_ent, 1983 bm_fmt, ip_buf, bm_len));*/ 1984 } else { /* go down CB */ 1985 /* prevent going further down if somehow last level 1986 is not Route level due to internal failure */ 1987 if ((ACB_IDX(acb) + 1) >= ACB_CNT(u)) { 1988 return BCM_E_INTERNAL; 1989 } 1990 1991 /* get ALPM Data entry ftmp for next level using best match saved */ 1992 alpm_util_ent_data_get(u, vrf_id, ipt, acb, bm_fent, bm_fmt, ftmp); 1993 ALPM_IER(alpm_cb_bm_lookup(u, vrf_id, ipt, ACB_DWN(u, acb), 1994 ftmp, bm_fmt, bm_key, bm_len, bm_idx, bm_ent, 1995 &adata1, lpm_cfg, &hit_res1, sw_key, sw_len)); 1996 1997 if (hit_res1 == ALPM_HIT) { /* Hit from next CB */ 1998 *hit_res = ALPM_HIT; 1999 return BCM_E_NONE; 2000 } else if ((hit_res1 == ALPM_MISS) && (def_miss == TRUE)) { 2001 *hit_res = ALPM_MISS; 2002 ALPM_VERB(("Miss in %s idx:%d.%d\n", 2003 ALPM_TBL_NAME(bkt_tbl), bm_idx, bm_ent)); 2004 return BCM_E_NONE; 2005 } 2006 /* hit_res1 == ALPM_MISS_USE_AD or def_miss == FALSE */ 2007 *hit_res = ALPM_MISS_USE_AD; 2008 ALPM_VERB(("Miss but use Associated data in %s idx:%d.%d\n", 2009 ALPM_TBL_NAME(bkt_tbl), bm_idx, bm_ent)); 2010 } 2011 2012 /* Reached route level or hit_res1 == ALPM_MISS_USE_AD from next CB */ 2013 /* Get best match Assoc_Data and prepare returned lpm_cfg info*/ 2014 alpm_util_cfg_construct(u, vrf_id, ipt, bm_key, bm_len, &adata1, lpm_cfg); 2015 lpm_cfg->defip_index = 2016 alpm_util_ent_phy_idx_get(u, acb, vrf_id, bm_idx); /* ALPM mem index */ 2017 2018 /* Get HIT bit from best matched entry */ 2019 if (!ALPM_HIT_SKIP(u)) { 2020 ALPM_HIT_LOCK(u); 2021 hit_val = alpm_rte_hit_get(u, vrf_id, bkt_tbl, bm_idx, bm_ent); 2022 lpm_cfg->defip_flags |= (hit_val > 0 ? BCM_L3_HIT : 0); 2023 ALPM_HIT_UNLOCK(u); 2024 } 2025 2026 return BCM_E_NONE; 2027 } 2028 2029 /* Missed in this CB */ 2030 if (def_miss == TRUE) { 2031 *hit_res = ALPM_MISS; /* Miss at all */ 2032 } else { /* Default Miss = 0 */ 2033 *hit_res = ALPM_MISS_USE_AD; /* Miss but upper CB should use Assoc Data */ 2034 } 2035 return BCM_E_NONE; 2036 } 2037 2038 /* 2039 * Function: 2040 * alpm_find_best_match 2041 * Purpose: 2042 * Get best prefix match entry from DEFIP table (both IPv4 or IPv6). 2043 * It's an indenpendent routine, to simalute HW process for incoming 2044 * packets. Considering possible mismatch between SW and HW, we need 2045 * to go through hardware for lookup regardless of software state. 2046 * Parameters: 2047 * u - (IN)Device unit number 2048 * vrf_id - (IN)VRF ID to lookup 2049 * pkm - (IN)Packing mode to lookup 2050 * sw_key - (IN)Key to lookup 2051 * sw_len - (IN)Key length to lookup 2052 * lpm_cfg - (OUT)BPM defip cfg info found 2053 * Returns: 2054 * BCM_E_XXX 2055 */ 2056 int 2057 alpm_find_best_match(int u, int vrf_id, int pkm, uint32 *sw_key, 2058 int sw_len, _bcm_defip_cfg_t *lpm_cfg) 2059 { 2060 int i, ipv6, hw_pkm, step_size, key_ent_cnt; 2061 int idx, sub_idx, idx_min, idx_cnt; 2062 int idx_end; 2063 int hw_len, hw_vrf_id; 2064 int use_alpm, key_mode; 2065 _alpm_lkup_res_t hit_res = ALPM_MISS; 2066 uint32 hw_mask[4]; 2067 uint32 hw_key[4]; 2068 uint32 fent[ALPM_MEM_ENT_MAX]; 2069 _alpm_cb_t *acb; 2070 uint32 lpm_entry[ALPM_MEM_ENT_MAX]; 2071 int do_urpf = 0; /* Find uRPF region */ 2072 int rv_tcam; 2073 int ipt = ALPM_PKM2IPT(pkm); 2074 2075 if (ALPMC(u) == NULL || !ALPMC(u)->_alpm_inited) { 2076 return BCM_E_INIT; 2077 } 2078 if (!SOC_URPF_STATUS_GET(u) && do_urpf) { 2079 return BCM_E_PARAM; 2080 } 2081 2082 acb = ACB_TOP(u); /* from top to bottom */ 2083 2084 idx_min = 0; 2085 idx_cnt = tcam_table_size(u, pkm); 2086 /* in Parallel or TCAM/ALPM mixed mode search Global High from second half */ 2087 if (ALPM_TCAM_ZONED(u)) { 2088 idx_cnt >>= 1; 2089 idx_min += idx_cnt; 2090 } 2091 if (do_urpf) { 2092 idx_min += tcam_table_size(u, pkm); 2093 } 2094 idx_end = idx_min + idx_cnt; 2095 2096 /* 1) Scanning for Global High routes first */ 2097 for (idx = idx_min; idx < idx_end; idx++) { 2098 ALPM_IER(tcam_entry_read(u, pkm, lpm_entry, idx, idx)); 2099 2100 for (sub_idx = 0; sub_idx < ALPM_TCAM_SUBCNT; sub_idx += step_size) { 2101 rv_tcam = tcam_valid_entry_mode_get(u, pkm, lpm_entry, 2102 &step_size, &hw_pkm, &ipv6, &key_mode, sub_idx); 2103 if (BCM_FAILURE(rv_tcam)) { 2104 if (rv_tcam == BCM_E_INTERNAL) { 2105 ALPM_ERR(("%s: Invalid Key Mode:%d or Key Type" 2106 " (IPv6):%d in idx:%d.%d\n", 2107 TCAM_TBL_NAME(acb, pkm), key_mode, 2108 ipv6, idx, sub_idx)); 2109 } 2110 continue; 2111 } 2112 2113 if (pkm != hw_pkm) { 2114 continue; 2115 } 2116 2117 tcam_entry_vrf_id_get(u, pkm, lpm_entry, sub_idx, &hw_vrf_id); 2118 if (hw_vrf_id != ALPM_VRF_ID_GHI(u)) { /* only Global Hi */ 2119 continue; 2120 } 2121 2122 sal_memset(hw_key, 0, sizeof(hw_key)); 2123 hw_len = 0; 2124 tcam_entry_to_key(u, pkm, lpm_entry, sub_idx, hw_key); 2125 tcam_entry_pfx_len_get(u, pkm, lpm_entry, sub_idx, &hw_len); 2126 if (hw_len > sw_len) { /* not match */ 2127 continue; 2128 } 2129 alpm_util_len_to_mask(ipt, hw_len, hw_mask); 2130 2131 /* hw_len <= sw_len: compare all hw_masked key */ 2132 key_ent_cnt = ALPM_KEY_ENT_CNT(ipt); 2133 for (i = 0; i < key_ent_cnt; i++) { 2134 if ((sw_key[i] & hw_mask[i]) != (hw_key[i] & hw_mask[i])) { 2135 break; 2136 } 2137 } 2138 /* Not match */ 2139 if (i < key_ent_cnt) { 2140 continue; 2141 } 2142 2143 /* Found all key matched (must be longest prefix due to order in TCAM) */ 2144 /* prepare returned lpm_cfg info */ 2145 tcam_entry_to_cfg(u, pkm, lpm_entry, sub_idx, lpm_cfg); 2146 alpm_util_key_to_cfg(u, ipt, hw_key, lpm_cfg); 2147 lpm_cfg->defip_sub_len = hw_len; 2148 lpm_cfg->defip_vrf = ALPM_VRF_ID_TO_VRF(u, hw_vrf_id); 2149 lpm_cfg->defip_flags |= (ipv6 ? BCM_L3_IP6 : 0); 2150 lpm_cfg->defip_index = idx; /* TCAM table index */ 2151 2152 ALPM_VERB(("Hit Global High route in %s idx:%d.%d\n", 2153 TCAM_TBL_NAME(acb, pkm), idx, sub_idx)); 2154 return BCM_E_NONE; 2155 } 2156 } 2157 2158 /* 2) Scanning for entire TCAM table sequentially 2159 (Private VRF route has precedence over Global Low) */ 2160 idx_min = 0; 2161 idx_cnt = tcam_table_size(u, pkm); 2162 if (do_urpf) { 2163 idx_min += tcam_table_size(u, pkm); 2164 } 2165 idx_end = idx_min + idx_cnt; 2166 2167 for (idx = idx_min; idx < idx_end; idx++) { 2168 _alpm_bkt_adata_t adata0; 2169 ALPM_IER(tcam_entry_read(u, pkm, lpm_entry, idx, idx)); 2170 2171 for (sub_idx = 0; sub_idx < ALPM_TCAM_SUBCNT; sub_idx += step_size) { 2172 rv_tcam = tcam_valid_entry_mode_get(u, pkm, lpm_entry, 2173 &step_size, &hw_pkm, &ipv6, &key_mode, sub_idx); 2174 if (BCM_FAILURE(rv_tcam)) { 2175 if (rv_tcam == BCM_E_INTERNAL) { 2176 ALPM_ERR(("%s: Invalid Key Mode:%d or Key Type" 2177 " (IPv6):%d in idx:%d.%d\n", 2178 TCAM_TBL_NAME(acb, pkm), key_mode, 2179 ipv6, idx, sub_idx)); 2180 } 2181 continue; 2182 } 2183 2184 if (pkm != hw_pkm) { 2185 continue; 2186 } 2187 2188 tcam_entry_vrf_id_get(u, pkm, lpm_entry, sub_idx, &hw_vrf_id); 2189 if ((vrf_id != hw_vrf_id) && (hw_vrf_id < ALPM_VRF_ID_GLO(u))) { 2190 continue; 2191 } 2192 /* valid only when ((vrf_id == hw_vrf_id) || 2193 (hw_vrf_id >= ALPM_VRF_ID_GLO(u))) */ 2194 sal_memset(hw_key, 0, sizeof(hw_key)); 2195 hw_len = 0; 2196 tcam_entry_to_key(u, pkm, lpm_entry, sub_idx, hw_key); 2197 tcam_entry_pfx_len_get(u, pkm, lpm_entry, sub_idx, &hw_len); 2198 if (hw_len > sw_len) { /* not match */ 2199 continue; 2200 } 2201 alpm_util_len_to_mask(ipt, hw_len, hw_mask); 2202 2203 /* hw_len <= sw_len: compare all hw_masked key */ 2204 key_ent_cnt = ALPM_KEY_ENT_CNT(ipt); 2205 for (i = 0; i < key_ent_cnt; i++) { 2206 if ((sw_key[i] & hw_mask[i]) != (hw_key[i] & hw_mask[i])) { 2207 break; 2208 } 2209 } 2210 /* Not match */ 2211 if (i < key_ent_cnt) { 2212 continue; 2213 } 2214 2215 /* Hit in TCAM pivot (must be longest prefix due to order in TCAM) */ 2216 tcam_entry_adata_get(u, pkm, lpm_entry, sub_idx, &adata0); 2217 use_alpm = !(adata0.defip_flags & BCM_L3_IPMC) && 2218 ALPM_VRF_ID_HAS_BKT(u, vrf_id); 2219 if (!use_alpm) { 2220 /* Global Low Direct route */ 2221 ALPM_VERB(("Hit Global Low route in %s idx:%d.%d\n", 2222 TCAM_TBL_NAME(acb, pkm), idx, sub_idx)); 2223 } else { 2224 /* ALPM bucket lookup from top to bottom */ 2225 tcam_entry_bdata_get(u, pkm, lpm_entry, sub_idx, fent); 2226 2227 alpm_util_cfg_to_key(u, ipt, lpm_cfg, sw_key); 2228 ALPM_IER(alpm_cb_bm_lookup(u, hw_vrf_id, pkm, acb, fent, 0, 2229 hw_key, hw_len, idx, sub_idx, &adata0, 2230 lpm_cfg, &hit_res, sw_key, sw_len)); 2231 if (hit_res == ALPM_HIT) { /* Hit in bucket */ 2232 return BCM_E_NONE; 2233 } else if (hit_res == ALPM_MISS) { /* Miss */ 2234 ALPM_VERB(("Miss in %s idx:%d.%d\n", 2235 TCAM_TBL_NAME(acb, pkm), idx, sub_idx)); 2236 return(BCM_E_NOT_FOUND); 2237 } else { /* hit_res == ALPM_MISS_USE_AD */ 2238 ALPM_VERB(("Miss but use Associated data in %s idx:%d.%d\n", 2239 TCAM_TBL_NAME(acb, pkm), idx, sub_idx)); 2240 } 2241 } 2242 2243 /* prepare returned lpm_cfg info */ 2244 tcam_entry_to_cfg(u, pkm, lpm_entry, sub_idx, lpm_cfg); 2245 alpm_util_key_to_cfg(u, ipt, hw_key, lpm_cfg); 2246 lpm_cfg->defip_sub_len = hw_len; 2247 lpm_cfg->defip_vrf = ALPM_VRF_ID_TO_VRF(u, hw_vrf_id); 2248 lpm_cfg->defip_flags |= (ipv6 ? BCM_L3_IP6 : 0); 2249 lpm_cfg->defip_index = idx; /* TCAM Hw index */ 2250 2251 return BCM_E_NONE; 2252 } 2253 } 2254 2255 /* Private VRF and Global Low Miss */ 2256 ALPM_VERB(("Search miss for given address\n")); 2257 2258 return(BCM_E_NOT_FOUND); 2259 } 2260 2261 /* 2262 * Function: 2263 * bcm_esw_alpm_find 2264 * Purpose: 2265 * Get an entry from DEFIP table. 2266 * Parameters: 2267 * u - (IN)Device unit number. 2268 * lpm_cfg - (IN/OUT)Key to lookup and found defip information. 2269 * nh_ecmp_idx - (OUT)Next hop or ecmp group index of bpm_route 2270 * Returns: 2271 * BCM_E_XXX 2272 */ 2273 int 2274 bcm_esw_alpm_find(int u, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 2275 { 2276 int vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 2277 int pkm = ALPM_LPM_PKM(u, lpm_cfg); 2278 int ipt = ALPM_PKM2IPT(pkm); 2279 uint32 sw_key[4] = {0}; 2280 int sw_len; 2281 2282 /* Input parameters check */ 2283 if (NULL == lpm_cfg) { 2284 return (BCM_E_PARAM); 2285 } 2286 alpm_util_ipmask_apply(u, lpm_cfg); 2287 2288 sw_len = lpm_cfg->defip_sub_len; 2289 2290 /* Perform hw lookup */ 2291 alpm_util_cfg_to_key(u, ipt, lpm_cfg, sw_key); /* get sw_key[4] */ 2292 ALPM_IER_PRT_EXCEPT(alpm_find_best_match(u, vrf_id, pkm, sw_key, sw_len, lpm_cfg), BCM_E_NOT_FOUND); 2293 *nh_ecmp_idx = lpm_cfg->defip_ecmp_index; 2294 2295 return (BCM_E_NONE); 2296 } 2297 2298 /* 2299 * Function: 2300 * bcm_esw_alpm_sw_dump 2301 * Purpose: 2302 * dump sw l3 (ALPM). 2303 * Parameters: 2304 * u - (IN)Device unit number. 2305 */ 2306 void 2307 bcm_esw_alpm_sw_dump(int u) 2308 { 2309 LOG_CLI((BSL_META_U(u, "\n ALPM Info -\n"))); 2310 bcm_esw_alpm_debug_brief_show(u, 0, 0); 2311 alpm_cb_stat_dump(u, 3); 2312 } 2313 2314 #endif /* ALPM_ENABLE */