alpm.c (196254B)
1 /* 2 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 3 * 4 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 5 * 6 * File: alpm.c 7 * Purpose: ALPM device independent implementation. 8 * Requires: 9 */ 10 11 /* Implementation notes: 12 */ 13 #include <shared/bsl.h> 14 15 #include <soc/mem.h> 16 #include <soc/drv.h> 17 #include <soc/debug.h> 18 #include <soc/error.h> 19 #include <soc/lpm.h> 20 #include <soc/trident2.h> 21 #include <soc/tomahawk.h> 22 #include <shared/bsl.h> 23 24 #include <shared/util.h> 25 #include <shared/l3.h> 26 27 #if defined(ALPM_ENABLE) 28 29 #include <bcm/l3.h> 30 31 #include <bcm_int/esw/l3.h> 32 #include <bcm_int/esw/firebolt.h> 33 #include <bcm_int/esw/alpm.h> 34 #include <bcm_int/esw/alpm_util.h> 35 36 /* Internal use only */ 37 typedef struct alpm_pvt_trav_cb_data_s { 38 int unit; 39 _alpm_cb_t *acb; 40 int bkt_idx; 41 42 SHR_BITDCL bkt[256]; /* 1K|8K, Max: 13 bits */ 43 SHR_BITDCL bnk[ALPM_BPB_MAX * 256]; /* bnk|bkt 1K|5 or 8K|8 */ 44 SHR_BITDCL ent[ALPM_BPB_MAX * 8192]; /* 10b/13b(bkt) |3b(bnk)| 5b(ent) */ 45 uint8 bnkfmt[ALPM_BPB_MAX * 8192];/* Bank format type */ 46 } alpm_pvt_trav_cb_data_t; 47 48 char *alpm_tbl_str[] = { 49 "alpmTblInvalid", 50 "alpmTblPvtCmodeL1", 51 "alpmTblPvtPmodeL1", 52 "alpmTblPvtCmodeL1P128", 53 "alpmTblPvtPmodeL1P128", 54 "alpmTblBktCmodeL2", 55 "alpmTblBktPmodeL2", 56 "alpmTblBktPmodeGblL2", 57 "alpmTblBktPmodePrtL2", 58 "alpmTblBktCmodeL3", 59 "alpmTblBktPmodeGblL3", 60 "alpmTblBktPmodePrtL3", 61 "alpmTblCount" 62 }; 63 64 _alpm_ctrl_t *alpm_control[SOC_MAX_NUM_DEVICES]; 65 66 /* Internal functions */ 67 static int alpm_pvt_update_by_pvt_node(int, _alpm_cb_t *, _alpm_pvt_node_t *, uint32); 68 static int alpm_bkt_pfx_shrink(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node, void *user_data); 69 static int alpm_vrf_pfx_trie_add(int u, _alpm_cb_t *acb, _bcm_defip_cfg_t *lpm_cfg, void *udata); 70 static int alpm_cb_split(int u, _alpm_cb_t *acb, _bcm_defip_cfg_t *lpm_cfg, 71 _alpm_bkt_info_t *nbkt_info, int max_spl_cnt); 72 73 /* External functions */ 74 75 /* 76 * key[4] = {key[0], key[1], key[2], key[3]} 77 * ipv4: key[4] = {IP_ADDR0f, 0, 0, 0} 78 * ipv6-64: key[4] = {0, 0, IP_ADDR0f, IP_ADDR1f} 79 * ipv6-128: key[4] = {IP_ADDR0_LWRf, IP_ADDR1_LWRf, IP_ADDR0_UPRf, IP_ADDR1_UPRf} 80 */ 81 void 82 alpm_trie_key_to_pfx(int u, int ipt, uint32 *key, uint32 len, uint32 *pfx) 83 { 84 int i; 85 uint32 pfx_shift, tmp; 86 87 pfx[0] = pfx[1] = pfx[2] = pfx[3] = pfx[4] = 0; 88 /* Obtain prefix length */ 89 if (ALPM_IS_IPV4(ipt)) { 90 pfx[1] = _SHIFT_RIGHT(key[0], 32 - len); 91 pfx[0] = 0; 92 } else { 93 /* PAIR_128 style, for both mode==2 and mode==3 */ 94 int start; 95 uint32 tmp_pfx[5] = {0}; 96 tmp_pfx[0] = key[0]; 97 tmp_pfx[1] = key[1]; 98 tmp_pfx[2] = key[2]; 99 tmp_pfx[3] = key[3]; 100 101 /* shift entire prefix right to remove trailing 0s in prefix */ 102 /* to simplify, words which are all 0s are ignored to begin with, so 103 * a right shift of say 46 is a right shift of 46-32 = 14, but starting 104 * from word 1. Once all shifting is done, shift all words to right by 1 105 */ 106 pfx_shift = 128 - len; 107 start = pfx_shift / 32; 108 pfx_shift = pfx_shift % 32; 109 for (i = start; i < 4; i++) { 110 tmp_pfx[i] >>= pfx_shift; 111 tmp = tmp_pfx[i+1] & ((1 << pfx_shift) - 1); 112 tmp = _SHIFT_LEFT(tmp, 32 - pfx_shift); 113 tmp_pfx[i] |= tmp; 114 } 115 /* make shift right justified and also reverse order for trie. 116 * Also, note trie sees key only in words 1 to 4 117 */ 118 for (i = start; i < 4; i++) { 119 pfx[4 - (i - start)] = tmp_pfx[i]; 120 } 121 } 122 return ; 123 } 124 125 /* 126 * key[4] = {key[0], key[1], key[2], key[3]} 127 * ipv4: key[4] = {IP_ADDR0f, 0, 0, 0} 128 * ipv6: 129 * 64: key[4] = {0, 0, IP_ADDR0f, IP_ADDR1f} 130 * 128: key[4] = {IP_ADDR0_LWRf, IP_ADDR1_LWRf, IP_ADDR0_UPRf, IP_ADDR1_UPRf} 131 */ 132 void 133 alpm_trie_pfx_to_key(int u, int ipt, uint32 *pfx, uint32 len, uint32 *key) 134 { 135 int key_bytes = sizeof(uint32) * BITS2WORDS(_MAX_KEY_LEN_144_); 136 137 sal_memcpy(key, pfx, key_bytes); 138 if (ALPM_IS_IPV6(ipt)) { 139 uint32 pfx_shift, tmp, start, pfx_tmp[6]; 140 int i; 141 142 sal_memcpy(pfx_tmp, key, key_bytes); 143 sal_memset(key, 0, key_bytes); 144 145 /* shift entire prefix left to add trailing 0s in prefix */ 146 pfx_shift = 128 - len; 147 start = (pfx_shift + 31) / 32; 148 /* fix corner case: */ 149 if ((pfx_shift % 32) == 0) { 150 start++; 151 } 152 pfx_shift = pfx_shift % 32; 153 for (i = start; i <= 4; i++) { 154 pfx_tmp[i] <<= pfx_shift; 155 tmp = pfx_tmp[i+1] & ~(0xffffffff >> pfx_shift); 156 tmp = _SHIFT_RIGHT(tmp, 32 - pfx_shift); 157 if (i < 4) { 158 pfx_tmp[i] |= tmp; 159 } 160 } 161 /* make shift left justified and reversed, 162 * i.e, lsw goes to index 0 */ 163 for (i = start; i <= 4; i++) { 164 key[3 - (i - start)] = pfx_tmp[i]; 165 } 166 } else { 167 key[0] = _SHIFT_LEFT(key[1], 32 - len); 168 key[1] = 0; 169 } 170 } 171 172 /* ip_addr => lpm_cfg->user_data 173 * OUT: pfx in tire format 174 */ 175 void 176 alpm_trie_cfg_to_pfx(int u, _bcm_defip_cfg_t *lpm_cfg, uint32 *pfx) 177 { 178 /* Create Prefix */ 179 uint32 key[4] = {0}; 180 uint32 ipt; 181 182 ipt = ALPM_LPM_IPT(u, lpm_cfg); 183 alpm_util_cfg_to_key(u, ipt, lpm_cfg, key); 184 alpm_trie_key_to_pfx(u, ipt, key, lpm_cfg->defip_sub_len, pfx); 185 186 return ; 187 } 188 189 /* pfx in trie format => ip_addr 190 * OUT: lpm_cfg->defip_ip6_addr/defip_ip_addr from trie format 191 */ 192 void 193 alpm_trie_pfx_to_cfg(int u, uint32 *pfx, int pfx_len, _bcm_defip_cfg_t *lpm_cfg) 194 { 195 /* Create Prefix */ 196 uint32 key[5] = {0}; 197 uint32 ipt = ALPM_LPM_IPT(u, lpm_cfg); 198 199 alpm_trie_pfx_to_key(u, ipt, pfx, pfx_len, key); 200 alpm_util_key_to_cfg(u, ipt, key, lpm_cfg); 201 lpm_cfg->defip_sub_len = pfx_len; 202 return ; 203 } 204 205 /* Convert TCAM entry to trie pfx format */ 206 int 207 alpm_trie_ent_to_pfx(int u, int pkm, void *e, int sub_idx, int pfx_len, 208 uint32 *pfx) 209 { 210 int rv = BCM_E_UNAVAIL; 211 uint32 key[4] = {0}; 212 213 rv = tcam_entry_to_key(u, pkm, e, sub_idx, key); 214 215 if (BCM_SUCCESS(rv)) { 216 alpm_trie_key_to_pfx(u, ALPM_PKM2IPT(pkm), key, pfx_len, pfx); 217 } 218 219 return rv; 220 } 221 222 static int 223 alpm_trie_pfx_cb(alpm_lib_trie_node_t *node, void *user_data) 224 { 225 _alpm_bkt_pfx_arr_t *pfx_arr = (_alpm_bkt_pfx_arr_t *)user_data; 226 if (node->type == trieNodeTypePayload) { 227 pfx_arr->pfx[pfx_arr->pfx_cnt] = (_alpm_bkt_node_t *)node; 228 pfx_arr->pfx_cnt++; 229 } 230 return BCM_E_NONE; 231 } 232 233 static int 234 alpm_trie_max_split_len_cb(alpm_lib_trie_node_t *node, void *user_data) 235 { 236 int *pkm; 237 int *pfx_len; 238 239 if (node->type == trieNodeTypePayload) { 240 uint32 key_len = ((_alpm_bkt_node_t *)node)->key_len; 241 int max_pfx_len[] = {32, 64, 128}; 242 pkm = (int *)user_data; 243 pfx_len = (int *)user_data + 1; 244 245 if (key_len == max_pfx_len[*pkm]) { 246 *pfx_len = key_len; 247 return BCM_E_BUSY; 248 } 249 if (*pfx_len < key_len) { 250 *pfx_len = key_len; 251 } 252 } 253 return BCM_E_NONE; 254 } 255 256 static void 257 alpm_trie_max_split_attr(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node, 258 int *split_len, int *split_cnt) 259 { 260 int splen = 0; 261 int rv, pvt_len = 0; 262 int kl, key_len[2] = {0}; 263 alpm_lib_trie_t *bkt_trie = NULL; 264 int vrf_id = PVT_BKT_VRF(pvt_node); 265 int pkm, ipt = PVT_BKT_IPT(pvt_node); 266 267 if (ALPM_IS_IPV6(ipt) && ALPM_128B(u)) { 268 pkm = ALPM_PKM_128; 269 } else { 270 pkm = ipt; 271 } 272 273 if (ACB_BKT_FIXED_FMT(acb, vrf_id)) { 274 int max_split_len[] = {32, 64, 128}; 275 splen = max_split_len[pkm] - 1; 276 } else { 277 pvt_len = PVT_KEY_LEN(pvt_node); 278 bkt_trie = PVT_BKT_TRIE(pvt_node); 279 key_len[0] = pkm; 280 281 rv = alpm_lib_trie_traverse(bkt_trie, alpm_trie_max_split_len_cb, key_len, 282 trieTraverseOrderIn); 283 if (BCM_FAILURE(rv) && rv != BCM_E_BUSY) { 284 ALPM_ERR(("alpm_lib_trie_traverse(bkt_trie) failed (%d)", rv)); 285 } 286 287 kl = key_len[1]; 288 if (acb->acb_idx == 0) { 289 splen = (pvt_len + kl + 1) * 1 / 2; 290 } else { 291 int splen1, splen2; 292 splen1 = (int)ACB_VRF_SPLEN_DIFF1(u, acb, vrf_id, ipt); 293 splen2 = (int)ACB_VRF_SPLEN_DIFF2(u, acb, vrf_id, ipt); 294 295 if ((kl - pvt_len) <= splen1) { 296 splen = kl - splen2; 297 *split_cnt = 1 << splen2; 298 } else { 299 splen = kl - splen1; 300 } 301 if (splen <= pvt_len) { 302 splen = (pvt_len + kl + 1) * 1 / 2; 303 } 304 } 305 } 306 307 *split_len = splen; 308 309 return ; 310 } 311 312 static int 313 alpm_trie_node_delete_cb(alpm_lib_trie_node_t *node, void *info) 314 { 315 if (node != NULL) { 316 alpm_util_free(node); 317 } 318 return BCM_E_NONE; 319 } 320 321 static int 322 alpm_trie_tree_destroy(int u, alpm_lib_trie_t *trie) 323 { 324 int rv = BCM_E_NONE; 325 if (trie != NULL) { 326 /* traverse bucket trie and clear it */ 327 rv = alpm_lib_trie_traverse(trie, alpm_trie_node_delete_cb, 328 NULL, trieTraverseOrderIn); 329 if (BCM_SUCCESS(rv)) { 330 alpm_lib_trie_destroy(trie); 331 } 332 } 333 334 return rv; 335 } 336 337 static int 338 alpm_trie_pvt_bkt_clear_cb(int u, _alpm_cb_t *acb, 339 _alpm_pvt_node_t *pvt_node, void *datum) 340 { 341 int rv = BCM_E_NONE; 342 alpm_lib_trie_t *bkt_trie; 343 344 bkt_trie = PVT_BKT_TRIE(pvt_node); 345 ALPM_IER(alpm_trie_tree_destroy(u, bkt_trie)); 346 PVT_BKT_TRIE(pvt_node) = NULL; 347 348 return rv; 349 } 350 351 static int 352 alpm_trie_clear_all(int u) 353 { 354 int i, rv = BCM_E_NONE; 355 int ipt, vrf_id; 356 _alpm_cb_t *acb; 357 alpm_lib_trie_t *pvt_trie = NULL, *vrf_trie = NULL; 358 359 for (ipt = 0; ipt < ALPM_IPT_CNT; ipt ++) { 360 for (vrf_id = 0; vrf_id <= ALPM_VRF_ID_MAX(u); vrf_id++) { 361 for (i = 0; i < ACB_CNT(u); i++) { 362 acb = ACB(u, i); 363 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt)) { 364 continue; 365 } 366 /* Clear Bucket Trie-tree */ 367 rv = bcm_esw_alpm_pvt_traverse(u, i, vrf_id, ipt, 368 alpm_trie_pvt_bkt_clear_cb, NULL); 369 ALPM_IER(rv); 370 371 /* Clear PVT Trie-tree */ 372 pvt_trie = ACB_PVT_TRIE(acb, vrf_id, ipt); 373 ALPM_IER(alpm_trie_tree_destroy(u, pvt_trie)); 374 ACB_PVT_TRIE(acb, vrf_id, ipt) = NULL; 375 } 376 377 /* Clear Prefix Trie-tree */ 378 vrf_trie = ALPM_VRF_TRIE(u, vrf_id, ipt); 379 ALPM_IER(alpm_trie_tree_destroy(u, vrf_trie)); 380 ALPM_VRF_TRIE(u, vrf_id, ipt) = NULL; 381 } 382 } 383 384 return rv; 385 } 386 387 /* Fill Aux entry for operation */ 388 static void 389 alpm_ppg_prepare(int u, _bcm_defip_cfg_t *lpm_cfg, int replace_len, 390 void *def_bkt_node, _alpm_ppg_data_t *ppg_data) 391 { 392 sal_memset(ppg_data, 0, sizeof(_alpm_ppg_data_t)); 393 394 ppg_data->vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 395 ppg_data->ipt = ALPM_LPM_IPT(u, lpm_cfg); 396 ppg_data->key_len = lpm_cfg->defip_sub_len; 397 ppg_data->bpm_len = replace_len; 398 sal_memcpy(ppg_data->key, lpm_cfg->user_data, sizeof(ppg_data->key)); 399 /* Get assoc_data */ 400 ppg_data->bkt_def = def_bkt_node; 401 402 return ; 403 } 404 405 static int 406 alpm_ppg(int u, alpm_lib_trie_t *pivot, void *prefix, uint32 len, 407 int insert, void *cb, void *user_data) 408 { 409 int rv = BCM_E_NONE; 410 uint32 pvt_len = 0; 411 alpm_lib_trie_node_t *lpm_pvt = NULL; 412 alpm_lib_trie_bpm_cb_info_t cb_info; 413 414 cb_info.pfx = (void *)prefix; 415 cb_info.len = len; 416 cb_info.user_data = user_data; 417 418 /* Find longest prefix match(pivot) of route */ 419 ALPM_IER(alpm_lib_trie_find_lpm(pivot, prefix, len, &lpm_pvt)); 420 pvt_len = (TRIE_ELEMENT_GET(_alpm_pvt_node_t *, lpm_pvt, node))->key_len; 421 422 if (pivot->v6_key) { 423 rv = _alpm_lib_trie_v6_ppg_prefix(lpm_pvt, pvt_len, 424 (void *)prefix, len, cb, &cb_info); 425 } else { 426 rv = _alpm_lib_trie_ppg_prefix(lpm_pvt, pvt_len, 427 (void *)prefix, len, cb, &cb_info); 428 } 429 430 return rv; 431 } 432 433 static int 434 alpm_ppg_assoc_data_cb(alpm_lib_trie_node_t *trie, alpm_lib_trie_bpm_cb_info_t *info) 435 { 436 int rv = BCM_E_NONE, unit; 437 int update_pvt = 0; 438 uint32 pfx_len, rpl_bpm_len, pvt_bpm_len; 439 440 _alpm_cb_t *acb; 441 _alpm_ppg_cb_user_data_t *user_data; 442 _alpm_ppg_data_t *ppg_data; 443 _alpm_pvt_node_t *pvt_node; 444 _alpm_bkt_node_t *pvt_def, *ppg_def; 445 446 user_data = info->user_data; 447 unit = user_data->unit; 448 ppg_data = user_data->ppg_data; 449 acb = user_data->ppg_acb; 450 451 pvt_node = (_alpm_pvt_node_t *)trie; 452 pvt_bpm_len = PVT_BPM_LEN(pvt_node); 453 pfx_len = ppg_data->key_len; 454 rpl_bpm_len = ppg_data->bpm_len; 455 456 /* bypass MC (direct route) for ppg in case of mix UC & MC in same VRF */ 457 if (PVT_IS_IPMC(pvt_node)) { 458 return rv; 459 } 460 461 if (user_data->ppg_op == ALPM_PPG_INSERT) { 462 rpl_bpm_len = pfx_len; 463 } 464 465 /* Addr & Mask has been screened by propagate function, 466 * no need to do it again */ 467 if (user_data->ppg_op == ALPM_PPG_INSERT) { 468 if (pvt_bpm_len > pfx_len) { 469 /* Not qualified and stop from traversing its child nodes */ 470 return SOC_E_LIMIT; 471 } 472 } 473 474 if (user_data->ppg_op == ALPM_PPG_DELETE) { 475 if (pvt_bpm_len != pfx_len) { 476 /* Not qualified and stop from traversing its child nodes */ 477 return (pvt_bpm_len > pfx_len) ? SOC_E_LIMIT : SOC_E_NONE; 478 } 479 } 480 481 /* Update bpm_length accordingly */ 482 PVT_BPM_LEN(pvt_node) = rpl_bpm_len; 483 484 /* Update PVT_BKT_DEF for pvt_node and do PPG again */ 485 pvt_def = PVT_BKT_DEF(pvt_node); 486 ppg_def = (_alpm_bkt_node_t *)ppg_data->bkt_def; 487 if (pvt_def == NULL || ppg_def == NULL || pvt_def == ppg_def) { 488 update_pvt = 1; 489 } else { 490 if (sal_memcmp(&pvt_def->adata, &ppg_def->adata, 491 sizeof(_alpm_bkt_adata_t)) != 0) { 492 update_pvt = 1; 493 } 494 } 495 496 PVT_BKT_DEF(pvt_node) = ppg_def; 497 if (update_pvt) { 498 rv = alpm_pvt_update_by_pvt_node(unit, acb, pvt_node, 499 ALPM_PVT_UPDATE_ASSOC_DATA | ALPM_PVT_UPDATE_ALPM_DATA); 500 } 501 502 /* Update callback count */ 503 user_data->ppg_cnt++; 504 505 return rv; 506 } 507 508 static int 509 alpm_ppg_hitbit_cb(alpm_lib_trie_node_t *trie, alpm_lib_trie_bpm_cb_info_t *info) 510 { 511 int rv = BCM_E_NONE, unit; 512 uint32 pfx_len, pvt_bpm_len; 513 514 _alpm_cb_t *acb; 515 _alpm_ppg_cb_user_data_t *user_data; 516 _alpm_ppg_data_t *ppg_data; 517 _alpm_pvt_node_t *pvt_node; 518 519 user_data = info->user_data; 520 unit = user_data->unit; 521 ppg_data = user_data->ppg_data; 522 acb = user_data->ppg_acb; 523 524 pvt_node = (_alpm_pvt_node_t *)trie; 525 pvt_bpm_len = PVT_BPM_LEN(pvt_node); 526 pfx_len = ppg_data->key_len; 527 528 /* Addr & Mask has been screened by propagate function, 529 * no need to do it again */ 530 if (pvt_bpm_len != pfx_len) { 531 /* Not qualified and stop from traversing its child nodes */ 532 return BCM_E_NONE; 533 } 534 535 /* New idx of def_pfx was already updated in regular routine, 536 * Just simply update pivot */ 537 rv = alpm_pvt_update_by_pvt_node(unit, acb, pvt_node, ALPM_PVT_UPDATE_ASSOC_DATA); 538 539 /* Update callback count */ 540 user_data->ppg_cnt++; 541 542 return rv; 543 } 544 545 /* Software propagation */ 546 int 547 alpm_ppg_op(int u, int ppg_op, void *cb, _alpm_ppg_data_t *ppg_data) 548 { 549 int i, rv = BCM_E_NONE; 550 int insert = 0; 551 uint32 vrf_id = 0; 552 uint32 ipt; 553 554 alpm_lib_trie_t *pvt_trie; 555 _alpm_cb_t *acb; 556 _alpm_ppg_cb_user_data_t user_data; 557 558 switch (ppg_op) { 559 case ALPM_PPG_INSERT: 560 insert = 1; 561 break; 562 case ALPM_PPG_DELETE: 563 insert = 0; 564 break; 565 case ALPM_PPG_HBP: 566 insert = 0; 567 break; 568 default: 569 return BCM_E_NONE; 570 } 571 572 vrf_id = ppg_data->vrf_id; 573 ipt = ppg_data->ipt; 574 575 user_data.unit = u; 576 user_data.ppg_data = ppg_data; 577 user_data.ppg_op = ppg_op; 578 user_data.ppg_cnt = 0; 579 580 for (i = 0; i < ACB_CNT(u); i++) { 581 acb = ACB(u, i); 582 if (ACB_VRF_EMPTY(acb, vrf_id)) { 583 continue; 584 } 585 user_data.ppg_acb = acb; 586 587 pvt_trie = ACB_PVT_TRIE(acb, vrf_id, ipt); 588 if (pvt_trie) { 589 rv = alpm_ppg(u, pvt_trie, ppg_data->key, ppg_data->key_len, 590 insert, cb, &user_data); 591 } 592 } 593 594 return rv; 595 596 } 597 598 int 599 alpm_ppg_assoc_data(int u, int ppg_op, _alpm_ppg_data_t *ppg_data) 600 { 601 return alpm_ppg_op(u, ppg_op, alpm_ppg_assoc_data_cb, ppg_data); 602 } 603 604 int 605 alpm_ppg_hitbit(int u, int vrf_id, int ipt, uint32 *key, int key_len) 606 { 607 _alpm_ppg_data_t ppg_data; 608 609 if (ALPM_HIT_SKIP(u)) { 610 return BCM_E_NONE; 611 } 612 613 if (!ALPM_TCAM_HB_IS_PTR(u)) { 614 return BCM_E_NONE; 615 } 616 617 sal_memset(&ppg_data, 0, sizeof(_alpm_ppg_data_t)); 618 ppg_data.ipt = ipt; 619 ppg_data.vrf_id = vrf_id; 620 ppg_data.key_len = key_len; 621 sal_memcpy(ppg_data.key, key, sizeof(ppg_data.key)); 622 623 return alpm_ppg_op(u, ALPM_PPG_HBP, alpm_ppg_hitbit_cb, &ppg_data); 624 } 625 626 /* Delete ALPM pvt trie only for Direct Routes */ 627 int 628 alpm_pvt_trie_delete(int u, _bcm_defip_cfg_t *lpm_cfg) 629 { 630 int rv = BCM_E_NONE; 631 int vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 632 int ipt = ALPM_LPM_IPT(u, lpm_cfg); 633 alpm_lib_trie_t *pvt_trie = NULL; 634 _alpm_pvt_node_t *pvt_node = NULL; 635 636 pvt_trie = ACB_PVT_TRIE(ACB_TOP(u), vrf_id, ipt); 637 rv = alpm_lib_trie_delete(pvt_trie, lpm_cfg->user_data, 638 lpm_cfg->defip_sub_len, (alpm_lib_trie_node_t **)&pvt_node); 639 if (BCM_FAILURE(rv)) { 640 ALPM_ERR(("Trie delete node failure\n")); 641 } 642 643 alpm_util_free(pvt_node); 644 return rv; 645 } 646 647 /* Insert ALPM pvt trie only for Direct Routes which is needed in _tcam_match */ 648 int 649 alpm_pvt_trie_insert(int u, _bcm_defip_cfg_t *lpm_cfg) 650 { 651 int rv = BCM_E_NONE; 652 int vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 653 alpm_lib_trie_t *pvt_trie = NULL; 654 _alpm_pvt_node_t *pvt_node = NULL; 655 656 ALPM_ALLOC_EG(pvt_node, sizeof(_alpm_pvt_node_t), "pvt_node"); 657 PVT_BKT_VRF(pvt_node) = vrf_id; 658 PVT_BKT_PKM(pvt_node) = ALPM_LPM_PKM(u, lpm_cfg); 659 PVT_IDX(pvt_node) = lpm_cfg->defip_index; 660 /* Direct route pvt_node doesn't use bkt_trie, def_pfx & bkt_info */ 661 PVT_KEY_LEN(pvt_node) = lpm_cfg->defip_sub_len; 662 PVT_KEY_CPY(pvt_node, lpm_cfg->user_data); 663 PVT_FLAGS(pvt_node) = lpm_cfg->defip_flags; 664 665 pvt_trie = ACB_PVT_TRIE(ACB_TOP(u), vrf_id, PVT_BKT_IPT(pvt_node)); 666 rv = alpm_lib_trie_insert(pvt_trie, lpm_cfg->user_data, 667 lpm_cfg->defip_sub_len, (alpm_lib_trie_node_t *)pvt_node); 668 return rv; 669 670 bad: 671 if (pvt_node != NULL) { 672 alpm_util_free(pvt_node); 673 } 674 return rv; 675 } 676 677 /* ALPM pvt trie init only for Direct Routes */ 678 int 679 alpm_pvt_trie_init(int u, int vrf_id, int ipt) 680 { 681 int rv = BCM_E_NONE; 682 uint32 max_key_len; 683 _alpm_cb_t *acb = ACB_TOP(u); 684 685 max_key_len = alpm_util_trie_max_key_len(u, ipt); 686 ALPM_IER(alpm_lib_trie_init(max_key_len, &ACB_PVT_TRIE(acb, vrf_id, ipt))); 687 ACB_VRF_INIT_SET(u, acb, vrf_id, ipt); 688 /* VRF DR partially inited: help to decide alpm_vrf_init 689 for case of mix MC & UC, in alpm_cb_insert */ 690 ACB_DR_INIT_SET(u, acb, vrf_id, ipt); 691 692 return rv; 693 } 694 695 static int 696 alpm_pvt_find_by_key(int u, _alpm_cb_t *acb, int vrf_id, int ipt, 697 uint32 *key, uint32 key_len, _alpm_pvt_node_t **pvt_node) 698 { 699 int rv = BCM_E_NONE; 700 alpm_lib_trie_t *pvt_trie; 701 702 pvt_trie = ACB_PVT_TRIE(acb, vrf_id, ipt); 703 rv = alpm_lib_trie_find_lpm(pvt_trie, key, key_len, 704 (alpm_lib_trie_node_t **)pvt_node); 705 if (BCM_FAILURE(rv)) { 706 ALPM_INFO(("**ACB(%d).PVT.FIND failed %d\n", ACB_IDX(acb), rv)); 707 } 708 709 return rv; 710 } 711 712 /* 713 * OUT: pvt_node 714 */ 715 static int 716 alpm_pvt_find(int u, _alpm_cb_t *acb, _bcm_defip_cfg_t *lpm_cfg, 717 _alpm_pvt_node_t **pvt_node) 718 { 719 int rv; 720 rv = alpm_pvt_find_by_key(u, acb, ALPM_LPM_VRF_ID(u, lpm_cfg), 721 ALPM_LPM_IPT(u, lpm_cfg), lpm_cfg->user_data, 722 lpm_cfg->defip_sub_len, pvt_node); 723 return rv; 724 } 725 726 static int 727 alpm_pvt_insert(int u, _alpm_cb_t *acb, 728 _bcm_defip_cfg_t *lpm_cfg) 729 { 730 int rv = 0; 731 732 if (ACB_HAS_TCAM(acb)) { 733 rv = bcm_esw_alpm_tcam_insert(u, lpm_cfg, ALPM_PVT_UPDATE_ALL); 734 } else { 735 rv = alpm_cb_insert(u, ACB_UPR(u, acb), lpm_cfg); 736 } 737 738 ALPM_INFO(("**ACB(%d).PVT.ADD rv %d\n", ACB_IDX(acb), rv)); 739 740 if (BCM_SUCCESS(rv)) { 741 VRF_PVT_LEN_CNT_ADD(acb, ALPM_LPM_VRF_ID(u, lpm_cfg), 742 ALPM_LPM_IPT(u, lpm_cfg), lpm_cfg->defip_sub_len); 743 } 744 745 return rv; 746 } 747 748 static int 749 alpm_pvt_delete(int u, _alpm_cb_t *acb, _bcm_defip_cfg_t *lpm_cfg) 750 { 751 int rv = 0; 752 753 if (ACB_HAS_TCAM(acb)) { 754 rv = bcm_esw_alpm_tcam_delete(u, lpm_cfg); 755 if (BCM_FAILURE(rv)) { 756 ALPM_ERR(("**ACB(%d).PVT.DEL tcam_delete 0x%x/%d vrf %d failed %d\n", 757 ACB_IDX(acb), lpm_cfg->defip_ip_addr, 758 lpm_cfg->defip_sub_len, lpm_cfg->defip_vrf, rv)); 759 } 760 } else { 761 rv = alpm_cb_delete(u, ACB_UPR(u, acb), lpm_cfg); 762 } 763 764 ALPM_INFO(("**ACB(%d).PVT.DEL rv %d\n", ACB_IDX(acb), rv)); 765 766 if (BCM_SUCCESS(rv)) { 767 VRF_PVT_LEN_CNT_DEC(acb, ALPM_LPM_VRF_ID(u, lpm_cfg), 768 ALPM_LPM_IPT(u, lpm_cfg), lpm_cfg->defip_sub_len); 769 } 770 771 return rv; 772 } 773 774 static int 775 alpm_pvt_delete_by_pvt_node(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node) 776 { 777 int rv = BCM_E_NONE; 778 _bcm_defip_cfg_t lpm_cfg; 779 780 sal_memset(&lpm_cfg, 0, sizeof(lpm_cfg)); 781 782 /* defip_flags */ 783 if (PVT_BKT_TRIE(pvt_node) && 784 PVT_BKT_TRIE(pvt_node)->v6_key) { 785 lpm_cfg.defip_flags |= BCM_L3_IP6; 786 } 787 788 /* Key & Length */ 789 alpm_trie_pfx_to_cfg(u, pvt_node->key, PVT_KEY_LEN(pvt_node), &lpm_cfg); 790 sal_memcpy(lpm_cfg.user_data, pvt_node->key, sizeof(pvt_node->key)); 791 lpm_cfg.defip_vrf = ALPM_VRF_ID_TO_VRF(u, PVT_BKT_VRF(pvt_node)); 792 793 /* Assoc-data */ 794 if (PVT_BKT_DEF(pvt_node) != NULL) { 795 alpm_util_adata_trie_to_cfg(u, &PVT_BKT_DEF(pvt_node)->adata, &lpm_cfg); 796 } else { 797 lpm_cfg.default_miss = 1; 798 } 799 800 rv = alpm_pvt_delete(u, acb, &lpm_cfg); 801 802 return rv; 803 } 804 805 /* delete newly created pivot from alpm_cb_path_construct if bucket is empty: 806 unable to insert route in Level3 due to FULL */ 807 static int 808 alpm_pvt_delete_by_empty_bkt(int u, _alpm_cb_t *acb, _bcm_defip_cfg_t *lpm_cfg) 809 { 810 int rv = BCM_E_NONE; 811 int vrf_id, ipt; 812 int bkt_empty; 813 alpm_lib_trie_t *bkt_trie = NULL; 814 alpm_lib_trie_node_t *tn = NULL; 815 _alpm_pvt_node_t *pvt_node = lpm_cfg->pvt_node; 816 817 if (ACB_HAS_TCAM(acb) || pvt_node == NULL) { 818 return rv; /* no need to check */ 819 } 820 821 vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 822 ipt = ALPM_LPM_IPT(u, lpm_cfg); 823 bkt_trie = PVT_BKT_TRIE(pvt_node); 824 825 /* Delete pvt entry if bucket is empty */ 826 bkt_empty = (PVT_KEY_LEN(pvt_node) != 0 && bkt_trie->trie == NULL); 827 if (!bkt_empty) { 828 return rv; /* no need to delete pvt if bkt is not empty */ 829 } 830 831 rv = alpm_pvt_delete_by_pvt_node(u, acb, pvt_node); 832 ALPM_IER(rv); 833 834 rv = alpm_lib_trie_delete(ACB_PVT_TRIE(acb, vrf_id, ipt), pvt_node->key, 835 PVT_KEY_LEN(pvt_node), &tn); 836 if (BCM_FAILURE(rv)) { 837 ALPM_ERR(("Trie delete node failure\n")); 838 } 839 840 (void)alpm_lib_trie_destroy(bkt_trie); 841 alpm_util_free(pvt_node); 842 843 return rv; 844 } 845 846 static int 847 alpm_pvt_update(int u, _alpm_cb_t *acb, _bcm_defip_cfg_t *lpm_cfg, uint32 write_flags) 848 { 849 int rv = BCM_E_NONE; 850 851 _alpm_cb_t *upr_acb = NULL; 852 _alpm_pvt_node_t *pvt_node = NULL; 853 _alpm_bkt_node_t *bkt_node = NULL; 854 855 if (ACB_HAS_TCAM(acb)) { 856 /* Use insert routine to update */ 857 rv = bcm_esw_alpm_tcam_insert(u, lpm_cfg, write_flags); 858 if (BCM_FAILURE(rv)) { 859 ALPM_ERR(("**ACB(%d).PVT.UPD tcam_insert failed %d\n", 860 ACB_IDX(acb), rv)); 861 } 862 } else { 863 upr_acb = ACB_UPR(u, acb); 864 rv = alpm_cb_find(u, upr_acb, lpm_cfg, &pvt_node, &bkt_node); 865 if (BCM_SUCCESS(rv)) { 866 rv = alpm_bkt_ent_write(u, upr_acb, pvt_node, lpm_cfg, 867 bkt_node->ent_idx, write_flags); 868 } else { 869 ALPM_ERR(("pvt_update->alpm_cb_find: rv %d, ACB.%d pvt_node=%p, bkt_node=%p\n", 870 rv, ACB_IDX(upr_acb), pvt_node, bkt_node)); 871 } 872 } 873 874 ALPM_INFO(("**ACB(%d).PVT.UPD rv %d\n", ACB_IDX(acb), rv)); 875 876 return rv; 877 } 878 879 static int 880 alpm_pvt_update_by_pvt_node(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node, uint32 write_flags) 881 { 882 int rv = BCM_E_NONE; 883 _bcm_defip_cfg_t lpm_cfg; 884 885 if (ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_UPDATE_SKIP) { 886 return rv; 887 } 888 889 sal_memset(&lpm_cfg, 0, sizeof(lpm_cfg)); 890 891 /* defip_flags */ 892 if (PVT_BKT_TRIE(pvt_node) && 893 PVT_BKT_TRIE(pvt_node)->v6_key) { 894 lpm_cfg.defip_flags |= BCM_L3_IP6; 895 } 896 897 /* Key & Length */ 898 alpm_trie_pfx_to_cfg(u, pvt_node->key, PVT_KEY_LEN(pvt_node), &lpm_cfg); 899 sal_memcpy(lpm_cfg.user_data, pvt_node->key, sizeof(pvt_node->key)); 900 lpm_cfg.defip_vrf = ALPM_VRF_ID_TO_VRF(u, PVT_BKT_VRF(pvt_node)); 901 902 /* Assoc-data */ 903 if (PVT_BKT_DEF(pvt_node) != NULL) { 904 alpm_util_adata_trie_to_cfg(u, &PVT_BKT_DEF(pvt_node)->adata, &lpm_cfg); 905 } else { 906 lpm_cfg.default_miss = 1; 907 } 908 909 if (ACB_HAS_TCAM(acb)) { 910 lpm_cfg.pvt_node = (uint32 *)pvt_node; 911 } else { 912 if (ACB_BKT_FIXED_FMT(acb, 1)) { 913 lpm_cfg.bkt_kshift = 0; 914 } else { 915 lpm_cfg.bkt_kshift = PVT_KEY_LEN(pvt_node); /* for upr acb bkt */ 916 } 917 } 918 lpm_cfg.bkt_info = &PVT_BKT_INFO(pvt_node); 919 920 rv = alpm_pvt_update(u, acb, &lpm_cfg, write_flags); 921 922 return rv; 923 } 924 925 static int 926 alpm_bkt_find(int u, _alpm_cb_t *acb, 927 _bcm_defip_cfg_t *lpm_cfg, 928 _alpm_pvt_node_t *pvt_node, 929 _alpm_bkt_node_t **bkt_node) 930 { 931 int rv = BCM_E_NOT_FOUND; 932 alpm_lib_trie_t *bkt_trie = PVT_BKT_TRIE(pvt_node); 933 if (bkt_trie) { 934 rv = alpm_lib_trie_search(bkt_trie, lpm_cfg->user_data, lpm_cfg->defip_sub_len, 935 (alpm_lib_trie_node_t **)bkt_node); 936 } 937 return rv; 938 } 939 940 static int 941 alpm_bkt_ent_del(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node, 942 int ent_idx) 943 { 944 int rv = BCM_E_NONE; 945 /* ALPMTBD */ 946 return rv; 947 } 948 949 int 950 alpm_bkt_ent_get_attempt(int u, _alpm_cb_t *acb, _alpm_bkt_pool_conf_t *bp_conf, 951 _alpm_bkt_info_t *bkt_info, uint8 def_fmt, 952 int pfx_len, uint32 *ent_idx, int *fmt_update, int bkt_test) 953 { 954 /* Start with shorter prefix fmt */ 955 int i, rv = BCM_E_NONE; 956 uint8 min_fmt = 0xff; 957 int start, close, step; 958 int bnkpb = BPC_BNK_PER_BKT(bp_conf); 959 int rofs = BI_ROFS(bkt_info); 960 uint32 eidx = 0; 961 962 /* Different bucket use different method for allocation, then after split, 963 * bank distribution will be like this: 964 bank 1: 965 ----> Bank 0: FMT1[*_______________] 966 ----> Bank 1: FMT3[**********______] 967 ----> Bank 2: FMT3[**********______] 968 ----> Bank 3: FMT3[**********______] 969 ----> Bank 4: FMT3[**********______] 970 ----> Bank 5: FMT3[________________] 971 ----> Bank 6: FMT3[________________] 972 ----> Bank 7: FMT3[________________] 973 bank 2: 974 ----> Bank 0: FMT1[________________] 975 ----> Bank 1: FMT1[________________] 976 ----> Bank 2: FMT1[________________] 977 ----> Bank 3: FMT1[________________] 978 ----> Bank 4: FMT3[**______________] 979 ----> Bank 5: FMT3[**********______] 980 ----> Bank 6: FMT3[**********______] 981 ----> Bank 7: FMT3[**********______] 982 */ 983 984 if (!BPC_BKT_WRA(bp_conf) || bkt_info->reverse == 0) { 985 start = rofs; 986 close = rofs + bnkpb; 987 step = 1; 988 } else { 989 start = rofs + bnkpb - 1; 990 close = rofs - 1; 991 step = -1; 992 } 993 994 /* First round is to get a bank that: 995 * with valid fmt type (assigned) AND 996 * proper prefix length AND 997 * bank is not full 998 * 999 * go through each bank to find the most efficient fmt 1000 */ 1001 for (i = start; ABS(i-close) > 0; i += step) { 1002 uint8 bnk_fmt = bkt_info->bnk_fmt[i % bnkpb]; 1003 uint32 vet_bmp = bkt_info->vet_bmp[i % bnkpb]; 1004 1005 /* Ignore invalid fmt type */ 1006 if (!BI_BNK_IS_USED(bkt_info, i % bnkpb) || 1007 bnk_fmt > BPC_FMT_CNT(bp_conf)) { 1008 continue; 1009 } 1010 1011 /* Ignore full bank */ 1012 if (vet_bmp == (1 << BPC_FMT_ENT_MAX(bp_conf, bnk_fmt)) - 1) { 1013 continue; 1014 } 1015 1016 /* Ignore unfit fmt 1bit Length should be considered */ 1017 if (!BPC_BKT_FIXED_FMT(bp_conf) && 1018 pfx_len > BPC_FMT_PFX_LEN(bp_conf, bnk_fmt)) { 1019 continue; 1020 } 1021 1022 if (bnk_fmt < min_fmt) { 1023 min_fmt = bnk_fmt; 1024 eidx = i % bnkpb; 1025 } 1026 } 1027 1028 /* ent_idx format 1029 * ------------------------------- 1030 * | ent idx | bnk idx | bkt idx | 1031 * ------------------------------- 1032 */ 1033 /* Now we find the bank, also need to find the empty slot in this bank */ 1034 if (min_fmt != 0xff) { 1035 for (i = 0; i < BPC_FMT_ENT_MAX(bp_conf, min_fmt); i++) { 1036 if ((bkt_info->vet_bmp[eidx] & (1 << i)) == 0) { 1037 if (!bkt_test) { 1038 bkt_info->bnk_fmt[eidx] = min_fmt; 1039 bkt_info->vet_bmp[eidx] |= 1 << i; 1040 *ent_idx = ALPM_IDX_MAKE(acb, bkt_info, eidx, i); 1041 } 1042 goto end; 1043 } 1044 } 1045 } 1046 1047 if (BPC_BKT_FIXED_FMT(bp_conf)) { 1048 rv = BCM_E_FULL; 1049 goto end; 1050 } 1051 1052 /* do second round if missed in the first round: 1053 * bank fmt is not fit (e.g. prefix length is shorter) BUT 1054 * this bank is empty, SO 1055 * we change the bank fmt and make it available. 1056 */ 1057 for (i = start; ABS(i-close) > 0; i += step) { 1058 uint8 fmt, bnk_fmt = bkt_info->bnk_fmt[i % bnkpb]; 1059 uint32 vet_bmp = bkt_info->vet_bmp[i % bnkpb]; 1060 1061 /* Ignore invalid fmt type */ 1062 if (!BI_BNK_IS_USED(bkt_info, i % bnkpb) || 1063 bnk_fmt > BPC_FMT_CNT(bp_conf) || 1064 vet_bmp != 0) { 1065 continue; 1066 } 1067 1068 /* vet_bmp is empty && bnk_fmt is valid 1069 * from most efficient def_fmt (matches route mode) to least efficient fmt */ 1070 for (fmt = def_fmt; fmt <= BPC_FMT_CNT(bp_conf); fmt++) { 1071 if (pfx_len <= BPC_FMT_PFX_LEN(bp_conf, fmt)) { 1072 /* Entry 0 of bank i */ 1073 if (!bkt_test) { 1074 bkt_info->vet_bmp[i % bnkpb] |= 1; 1075 bkt_info->bnk_fmt[i % bnkpb] = fmt; 1076 *ent_idx = ALPM_IDX_MAKE(acb, bkt_info, i % bnkpb, 0); 1077 1078 if (bnk_fmt != fmt && fmt_update != NULL) { 1079 *fmt_update = TRUE; 1080 } 1081 } 1082 goto end; 1083 } 1084 } 1085 } 1086 1087 rv = BCM_E_FULL; 1088 end: 1089 if (rv == BCM_E_FULL) { 1090 ALPM_VERB(("**ACB(%d).ENT.get: failed (FULL)\n", ACB_IDX(acb))); 1091 } 1092 return rv; 1093 } 1094 1095 int 1096 alpm_bkt_ent_write(int u, _alpm_cb_t *acb, 1097 _alpm_pvt_node_t *pvt_node, 1098 _bcm_defip_cfg_t *lpm_cfg, int ent_idx, uint32 write_flags) 1099 { 1100 int rv; 1101 rv = ALPM_DRV(u)->alpm_bkt_ent_write(u, acb, pvt_node, lpm_cfg, ent_idx, write_flags); 1102 return rv; 1103 } 1104 1105 static int 1106 alpm_bkt_bnks_get(int u, int vrf_id, _alpm_cb_t *acb, 1107 _alpm_bkt_info_t *bkt_info, int *count) 1108 { 1109 int rv = BCM_E_NONE; 1110 int i, bnk_cnt = 0; 1111 1112 for (i = 0; i < ALPM_BPB_MAX; i++) { 1113 uint8 bnk_fmt = bkt_info->bnk_fmt[i]; 1114 if (BI_BNK_IS_USED(bkt_info, i) && 1115 bnk_fmt <= ACB_FMT_CNT(acb, vrf_id)) { 1116 bnk_cnt ++; 1117 } 1118 } 1119 1120 if (count) { 1121 *count = bnk_cnt; 1122 } 1123 1124 return rv; 1125 } 1126 1127 static int 1128 alpm_bkt_ent_get(int u, int vrf_id, _alpm_cb_t *acb, 1129 _alpm_pvt_node_t *pvt_node, int pfx_len, 1130 uint32 *ent_idx, int *fmt_update, int bkt_test) 1131 { 1132 int rv = BCM_E_NONE; 1133 uint8 def_fmt; 1134 _alpm_bkt_info_t *bkt_info = &PVT_BKT_INFO(pvt_node); 1135 1136 def_fmt = alpm_util_bkt_def_fmt_get(u, acb, vrf_id, PVT_BKT_IPT(pvt_node)); 1137 rv = alpm_bkt_ent_get_attempt(u, acb, ACB_BKT_VRF_POOL(acb, vrf_id), 1138 bkt_info, def_fmt, pfx_len, 1139 ent_idx, fmt_update, bkt_test); 1140 if (rv == BCM_E_FULL) { 1141 int bnk_cnt = 0; 1142 /* If all banks are full, check if bucket expansion is required */ 1143 alpm_bkt_bnks_get(u, vrf_id, acb, bkt_info, &bnk_cnt); 1144 if (ACB_BNK_PER_BKT(acb, vrf_id) > bnk_cnt) { 1145 if (bkt_test) { 1146 return BCM_E_NONE; 1147 } 1148 /* To do bucket expansion here */ 1149 if (ACB_BKT_FIXED_FMT(acb, vrf_id)) { 1150 rv = alpm_cb_expand_in_bkt(u, acb, pvt_node, bnk_cnt); 1151 } else { 1152 rv = alpm_cb_expand(u, acb, pvt_node, bnk_cnt, fmt_update); 1153 } 1154 if (BCM_SUCCESS(rv)) { 1155 rv = alpm_bkt_ent_get_attempt(u, acb, 1156 ACB_BKT_VRF_POOL(acb, vrf_id), 1157 bkt_info, def_fmt, pfx_len, 1158 ent_idx, fmt_update, bkt_test); 1159 } 1160 } 1161 } 1162 1163 return rv; 1164 } 1165 1166 static int 1167 alpm_bkt_bnk_chk_rsvd(int u, int ipt, _alpm_bkt_pool_conf_t *bp_conf, int bnk) 1168 { 1169 int rv = BCM_E_NONE; 1170 int used = 0; 1171 SHR_BITDCL *bnk_bmp; 1172 1173 bnk_bmp = BPC_BNK_BMP(bp_conf, ipt); 1174 1175 SHR_BITTEST_RANGE(bnk_bmp, bnk, 1, used); 1176 if (used) { 1177 rv = BCM_E_NOT_FOUND; 1178 } else { 1179 SHR_BITSET_RANGE(bnk_bmp, bnk, 1); 1180 BPC_BNK_USED(bp_conf, ipt) += 1; 1181 } 1182 1183 return rv; 1184 } 1185 1186 static int 1187 alpm_bkt_bnk_alloc_reverse(int u, int ipt, _alpm_bkt_pool_conf_t *bp_conf, 1188 int *bnk, int alloc_sz, int step) 1189 { 1190 int rv = BCM_E_NONE; 1191 int i, bnk_cnt, bnk_end, used = 0; 1192 SHR_BITDCL *bnk_bmp; 1193 1194 bnk_bmp = BPC_BNK_BMP(bp_conf, ipt); 1195 bnk_cnt = BPC_BNK_CNT(bp_conf); 1196 bnk_end = bnk_cnt - alloc_sz + 1; 1197 for (i = bnk_end - 1; i >= 0; i += step) { 1198 SHR_BITTEST_RANGE(bnk_bmp, i, alloc_sz, used); 1199 if (!used) { 1200 break; 1201 } 1202 } 1203 1204 if (i < 0) { /* include *start_bnk is used when step=0xfffffff */ 1205 rv = BCM_E_NOT_FOUND; 1206 } else { 1207 SHR_BITSET_RANGE(bnk_bmp, i, alloc_sz); 1208 BPC_BNK_USED(bp_conf, ipt) += alloc_sz; 1209 *bnk = i; 1210 } 1211 1212 if (rv == BCM_E_NONE) { 1213 ALPM_INFO(("bnk alloc start %d sz %d\n", *bnk, alloc_sz)); 1214 } 1215 1216 return rv; 1217 } 1218 1219 static int 1220 alpm_bkt_bnk_alloc(int u, int ipt, _alpm_bkt_pool_conf_t *bp_conf, 1221 int *bnk, int alloc_sz, int step) 1222 { 1223 int rv = BCM_E_NONE; 1224 int i, bnk_cnt, bnk_end, used = 0; 1225 SHR_BITDCL *bnk_bmp; 1226 1227 if (step < 0) { 1228 return alpm_bkt_bnk_alloc_reverse(u, ipt, bp_conf, bnk, alloc_sz, step); 1229 } 1230 1231 bnk_bmp = BPC_BNK_BMP(bp_conf, ipt); 1232 bnk_cnt = BPC_BNK_CNT(bp_conf); 1233 bnk_end = bnk_cnt - alloc_sz + 1; 1234 i = bnk_end; 1235 if (step == BPC_BNK_PER_BKT(bp_conf)) { 1236 for (i = 0; i < bnk_end; i += step) { 1237 SHR_BITTEST_RANGE(bnk_bmp, i, step, used); 1238 if (!used) { 1239 break; 1240 } 1241 } 1242 } 1243 1244 if (i >= bnk_end) { 1245 for (i = 0; i < bnk_end; i += step) { 1246 SHR_BITTEST_RANGE(bnk_bmp, i, alloc_sz, used); 1247 if (!used) { 1248 break; 1249 } 1250 } 1251 } 1252 1253 if (i >= bnk_end) { /* include *start_bnk is used when step=0xfffffff */ 1254 rv = BCM_E_NOT_FOUND; 1255 } else { 1256 SHR_BITSET_RANGE(bnk_bmp, i, alloc_sz); 1257 BPC_BNK_USED(bp_conf, ipt) += alloc_sz; 1258 *bnk = i; 1259 } 1260 1261 if (rv == BCM_E_NONE) { 1262 ALPM_INFO(("bnk alloc start %d sz %d\n", *bnk, alloc_sz)); 1263 } 1264 1265 return rv; 1266 } 1267 1268 static void 1269 alpm_bkt_sub_bkt_info(int u, _alpm_cb_t *acb, int vrf_id, int ipt, 1270 _alpm_bkt_pool_conf_t *bp_conf, 1271 int start_bnk, int range, int *rt_ipt, uint32 *sub_bkt_bmp) 1272 { 1273 int i, bnk_pbk; 1274 SHR_BITDCL *bnk_bmp; 1275 _alpm_pvt_node_t *pvt_node; 1276 1277 bnk_bmp = BPC_BNK_BMP(bp_conf, ipt); 1278 bnk_pbk = BPC_BNK_PER_BKT(bp_conf); 1279 for (i = start_bnk; i < start_bnk + range; i++) { 1280 if (SHR_BITGET(bnk_bmp, i)) { 1281 int tab_idx = 1282 ALPM_TAB_IDX_GET_BKT_BNK(acb, 0, i / bnk_pbk, i % bnk_pbk); 1283 pvt_node = 1284 (_alpm_pvt_node_t *)ACB_VRF_PVT_PTR(acb, vrf_id, tab_idx); 1285 if (pvt_node != NULL) { 1286 *rt_ipt = PVT_BKT_IPT(pvt_node); 1287 *sub_bkt_bmp |= 1 << BI_SUB_BKT_IDX(&pvt_node->bkt_info); 1288 } 1289 } 1290 } 1291 1292 return ; 1293 } 1294 1295 static int 1296 alpm_bkt_pkm_sbkt_chk(int u, _alpm_cb_t *acb, int vrf_id, int ipt, 1297 _alpm_bkt_pool_conf_t *bp_conf, 1298 int start_bnk, int range, 1299 uint16 *sub_bkt_idx, int *sub_bkt_ipt) 1300 { 1301 uint32 sub_bkt_bmp = 0; 1302 1303 uint16 first_sub_bkt[] = { 1304 0, /* 0b0000 */ 1, /* 0b0001 */ 0, /* 0b0010 */ 2, /* 0b0011 */ 1305 0, /* 0b0100 */ 1, /* 0b0101 */ 0, /* 0b0110 */ 3, /* 0b0111 */ 1306 0, /* 0b1000 */ 1, /* 0b1001 */ 0, /* 0b1010 */ 2, /* 0b1011 */ 1307 0, /* 0b1100 */ 1, /* 0b1101 */ 0, /* 0b1110 */ 1308 }; 1309 1310 *sub_bkt_ipt = -1; 1311 alpm_bkt_sub_bkt_info(u, acb, vrf_id, ipt, bp_conf, start_bnk, range, 1312 sub_bkt_ipt, &sub_bkt_bmp); 1313 /* All 4 sub-pkts are used */ 1314 if (sub_bkt_bmp >= 0xf) { 1315 return BCM_E_NOT_FOUND; 1316 } 1317 1318 *sub_bkt_idx = first_sub_bkt[sub_bkt_bmp]; 1319 return BCM_E_NONE; 1320 } 1321 1322 /* step == 0xfffffff means check if *start_bnk is occupied */ 1323 static int 1324 alpm_bkt_sharing_bnk_alloc(int u, _alpm_cb_t *acb, int vrf_id, int ipt, 1325 _alpm_bkt_pool_conf_t *bp_conf, 1326 _alpm_bkt_info_t *bkt_info, int *avl_sz, 1327 int start_bnk, int alloc_sz, int step) 1328 { 1329 int rv = BCM_E_NONE; 1330 int i, j, bnks, bnk_cnt, bnk_end, bnk_pbk, used; 1331 uint16 sub_bkt_idx = 0; 1332 int count, range = 0; 1333 int check_avl, max_avl_sz = 0; 1334 SHR_BITDCL *bnk_bmp; 1335 1336 sal_memset(bkt_info, 0, sizeof(_alpm_bkt_info_t)); 1337 bnk_bmp = BPC_BNK_BMP(bp_conf, ipt); 1338 bnk_cnt = BPC_BNK_CNT(bp_conf); 1339 bnk_pbk = BPC_BNK_PER_BKT(bp_conf); 1340 1341 /* if step == 0xfffffff means check_exist */ 1342 check_avl = (alloc_sz == 1) && (step > (bnk_cnt + bnk_pbk)); 1343 assert(check_avl || (start_bnk == 0 && step == bnk_pbk)); 1344 1345 /* Case 1: Check if a bank is available */ 1346 if (check_avl) { 1347 i = start_bnk; 1348 range = alloc_sz; 1349 if (!SHR_BITGET(bnk_bmp, i)) { 1350 goto _done; 1351 } 1352 1353 return BCM_E_NOT_FOUND; 1354 } 1355 1356 /* Case 2: Allocate bank from empty buckets */ 1357 range = bnk_pbk; 1358 bnk_end = bnk_cnt - range + 1; 1359 for (i = 0; i < bnk_end; i += step) { 1360 SHR_BITTEST_RANGE(bnk_bmp, i, range, used); 1361 if (!used) { 1362 break; 1363 } 1364 } 1365 if (i < bnk_end) { 1366 goto _done; 1367 } 1368 1369 /* Case 3: Allocate bank from non-empty buckets 1370 * WARNING: V4/V6 should not be sharing same bucket */ 1371 i = 0; 1372 while (i < bnk_end) { 1373 SHR_BITCOUNT_RANGE(bnk_bmp, count, i, range); 1374 if (range == count) { 1375 i += step; 1376 continue; 1377 } 1378 1379 if ((range - count) > max_avl_sz) { 1380 int bkt_ipt; 1381 rv = alpm_bkt_pkm_sbkt_chk(u, acb, vrf_id, ipt, bp_conf, i, range, 1382 &sub_bkt_idx, &bkt_ipt); 1383 if (rv == BCM_E_NOT_FOUND || bkt_ipt != ipt) { 1384 i += step; 1385 continue; 1386 } 1387 1388 max_avl_sz = range - count; 1389 if (max_avl_sz >= alloc_sz) { 1390 /* Check available sub_bkt_idx, 1391 * total sub_bkt_idx cnt is 4, 1392 * check_exist case doesn't need sub_bkt_idx 1393 */ 1394 break; 1395 } 1396 } 1397 1398 i += step; 1399 } 1400 1401 if (i >= bnk_end) { 1402 if (avl_sz != NULL) { 1403 *avl_sz = max_avl_sz; 1404 } 1405 return BCM_E_NOT_FOUND; 1406 } 1407 1408 _done: 1409 BI_ROFS(bkt_info) = 0; 1410 BI_BKT_IDX(bkt_info) = i / bnk_pbk; 1411 BI_SUB_BKT_IDX(bkt_info) = sub_bkt_idx; 1412 bnks = 0; 1413 for (j = i; j < i+range; j++) { 1414 if (!SHR_BITGET(bnk_bmp, j)) { 1415 bkt_info->bnk_fmt[j % bnk_pbk] = 1416 alpm_util_bkt_def_fmt_get(u, acb, vrf_id, ipt); 1417 /* bkt_info->vet_bmp default to 0 */ 1418 SHR_BITSET(bnk_bmp, j); 1419 if (++bnks >= alloc_sz) { 1420 break; 1421 } 1422 } 1423 } 1424 1425 BPC_BNK_USED(bp_conf, ipt) += alloc_sz; 1426 1427 return rv; 1428 } 1429 1430 int 1431 alpm_bkt_bnk_free(int u, int ipt, _alpm_cb_t *acb, 1432 _alpm_bkt_pool_conf_t *bp_conf, 1433 _alpm_bkt_info_t *bkt_info, int bnk) 1434 { 1435 int gbl_bnk, bkt_bnk, tab_idx; 1436 SHR_BITDCL *bnk_bmp; 1437 1438 bnk_bmp = BPC_BNK_BMP(bp_conf, ipt); 1439 bkt_bnk = BPC_BNK_PER_BKT(bp_conf); 1440 gbl_bnk = BI_BKT_IDX(bkt_info) * bkt_bnk + bnk; 1441 if (BI_ROFS(bkt_info) > bnk) { 1442 gbl_bnk += bkt_bnk; 1443 } 1444 1445 if (!SHR_BITGET(bnk_bmp, gbl_bnk)) { 1446 return BCM_E_PARAM; 1447 } 1448 SHR_BITCLR(bnk_bmp, gbl_bnk); 1449 BPC_BNK_USED(bp_conf, ipt) -= 1; 1450 1451 tab_idx = ALPM_TAB_IDX_GET_BI_BNK(acb, bkt_info, bnk); 1452 if (bp_conf->pvt_ptr != NULL) { 1453 bp_conf->pvt_ptr[tab_idx] = NULL; 1454 } 1455 1456 /* Suppose to update bkt_info->rofs when bnk is freed */ 1457 if (BPC_BKT_WRA(bp_conf) && bnk == BI_ROFS(bkt_info) && 1458 (gbl_bnk < (BPC_BNK_CNT(bp_conf) - 1))) { 1459 int new_rofs = (bnk + 1) % bkt_bnk; 1460 if (new_rofs < BI_ROFS(bkt_info)) { 1461 BI_BKT_IDX(bkt_info)++; 1462 } 1463 BI_ROFS(bkt_info) = new_rofs; 1464 } 1465 1466 BI_BNK_FREE(bkt_info, bnk); 1467 1468 ALPM_INFO(("bnk free bnk %d \n", gbl_bnk)); 1469 1470 acb->acb_cnt.c_bnkfree++; 1471 1472 return BCM_E_NONE; 1473 } 1474 1475 static int 1476 alpm_bkt_bnk_shrink(int u, int ipt, _alpm_cb_t *acb, _alpm_bkt_pool_conf_t *bp_conf, 1477 _alpm_bkt_info_t *bkt_info, int *fmt_update) 1478 { 1479 int i, bnkpb, bnk; 1480 int bnks, bnke; 1481 1482 bnkpb = BPC_BNK_PER_BKT(bp_conf); 1483 1484 /* Store bnks and bnke because alpm_bkt_bnk_free could change rofs value */ 1485 bnks = BI_ROFS(bkt_info); 1486 bnke = bnkpb + BI_ROFS(bkt_info); 1487 1488 for (i = bnks; i < bnke; i++) { 1489 bnk = i % bnkpb; 1490 if (BI_BNK_IS_USED(bkt_info, bnk) && bkt_info->vet_bmp[bnk] == 0) { 1491 /* Release bank bnk */ 1492 ALPM_INFO(("**ACB(%d).BNK.RLS: RBBE (%d %d %d *)\n", 1493 ACB_IDX(acb), -1, BI_BKT_IDX(bkt_info), bnk)); 1494 1495 if (fmt_update != NULL) { 1496 *fmt_update = 1; 1497 } 1498 ALPM_IER(alpm_bkt_bnk_free(u, ipt, acb, bp_conf, bkt_info, bnk)); 1499 } 1500 } 1501 1502 acb->acb_cnt.c_bnkshrk++; 1503 1504 return BCM_E_NONE; 1505 } 1506 1507 /* _alpm_bkt_alloc_full to make sure a entire bucket 1508 * is allocated or return FULL */ 1509 static int 1510 alpm_bkt_alloc_attempt(int u, _alpm_cb_t *acb, int vrf_id, int ipt, 1511 int req_bnk_cnt, int step, _alpm_bkt_info_t *bkt_info, 1512 int *avl_bnk_cnt) 1513 { 1514 int rv; 1515 int i, bnk = 0, bnkpb; 1516 1517 if (ACB_BKT_FIXED_FMT(acb, vrf_id)) { 1518 rv = alpm_bkt_sharing_bnk_alloc(u, acb, vrf_id, ipt, 1519 ACB_BKT_VRF_POOL(acb, vrf_id), bkt_info, avl_bnk_cnt, 1520 0, req_bnk_cnt, step); 1521 } else { 1522 rv = alpm_bkt_bnk_alloc(u, ipt, ACB_BKT_VRF_POOL(acb, vrf_id), &bnk, 1523 req_bnk_cnt, bkt_info->reverse ? -1 : step); 1524 if (BCM_SUCCESS(rv)) { 1525 bnkpb = ACB_BNK_PER_BKT(acb, vrf_id); 1526 BI_ROFS(bkt_info) = bnk % bnkpb; 1527 BI_BKT_IDX(bkt_info) = bnk / bnkpb; 1528 sal_memset(bkt_info->vet_bmp, 0, sizeof(bkt_info->vet_bmp)); 1529 sal_memset(bkt_info->bnk_fmt, 0, sizeof(bkt_info->bnk_fmt)); 1530 for (i = 0; i < req_bnk_cnt; i++) { 1531 bkt_info->bnk_fmt[(BI_ROFS(bkt_info) + i) % bnkpb] 1532 = alpm_util_bkt_def_fmt_get(u, acb, vrf_id, ipt); 1533 } 1534 } 1535 } 1536 1537 if (rv == BCM_E_NOT_FOUND) { 1538 rv = BCM_E_FULL; 1539 } 1540 1541 return rv; 1542 } 1543 1544 int 1545 alpm_bkt_bnk_nearest_get(int u, SHR_BITDCL *bnk_bmp, int bnk_sz, 1546 int left_bnk, int right_bnk, int *nst_bnk) 1547 { 1548 int i, rv = BCM_E_NONE; 1549 int nst_left, nst_right; 1550 1551 nst_left = -1; 1552 nst_right = bnk_sz; 1553 1554 if (left_bnk >= 0) { 1555 for (i = left_bnk; i >= 0; i--) { 1556 if (!SHR_BITGET(bnk_bmp, i)) { /* TBD performance */ 1557 break; 1558 } 1559 } 1560 nst_left = i; 1561 } 1562 1563 if (right_bnk < bnk_sz) { 1564 for (i = right_bnk; i < bnk_sz; i++) { 1565 if (!SHR_BITGET(bnk_bmp, i)) { /* TBD performance */ 1566 break; 1567 } 1568 } 1569 nst_right = i; 1570 } 1571 1572 if (nst_left >= 0 && nst_right < bnk_sz) { 1573 if ((left_bnk - nst_left) > (nst_right - right_bnk)) { 1574 *nst_bnk = nst_right; 1575 } else { 1576 *nst_bnk = nst_left; 1577 } 1578 } else if (nst_left >= 0) { 1579 *nst_bnk = nst_left; 1580 } else if (nst_right < bnk_sz) { 1581 *nst_bnk = nst_right; 1582 } else { 1583 rv = BCM_E_FULL; 1584 } 1585 1586 return rv; 1587 } 1588 1589 static int 1590 alpm_bkt_pfx_ent_idx_update(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node, 1591 _alpm_bkt_info_t *src_bkt, int src_bnk, 1592 _alpm_bkt_info_t *dst_bkt, int dst_bnk) 1593 { 1594 int i, rv = BCM_E_UNAVAIL; 1595 int sb = src_bnk; 1596 int db = dst_bnk; 1597 uint32 bak_idx; 1598 _alpm_bkt_pfx_arr_t *pfx_arr = NULL; 1599 _alpm_bkt_node_t *bkt_node = NULL; 1600 alpm_lib_trie_t *bkt_trie = NULL; 1601 1602 bkt_trie = PVT_BKT_TRIE(pvt_node); 1603 ALPM_ALLOC_EG(pfx_arr, sizeof(*pfx_arr), "pfx_arr"); 1604 rv = alpm_lib_trie_traverse(bkt_trie, alpm_trie_pfx_cb, pfx_arr, 1605 trieTraverseOrderIn); 1606 ALPM_IEG(rv); 1607 for (i = 0; i < pfx_arr->pfx_cnt; i++) { 1608 int ent, bnk, bkt; 1609 1610 bkt_node = pfx_arr->pfx[i]; 1611 ent = ALPM_IDX_TO_ENT(bkt_node->ent_idx); 1612 bnk = ALPM_IDX_TO_BNK(acb, bkt_node->ent_idx); 1613 bkt = ALPM_IDX_TO_BKT(acb, bkt_node->ent_idx); 1614 if (bnk < PVT_ROFS(pvt_node)) { 1615 bkt -= 1; 1616 } 1617 1618 if (src_bnk == -1) { 1619 sb = bnk; 1620 db = bnk; 1621 } 1622 1623 bak_idx = bkt_node->ent_idx; 1624 if (bnk == sb && bkt == BI_BKT_IDX(src_bkt)) { 1625 bkt_node->ent_idx = ALPM_IDX_MAKE(acb, dst_bkt, db, ent); 1626 if (ALPM_TCAM_HB_IS_PTR(u) && bak_idx != bkt_node->ent_idx) { 1627 ALPM_IEG(alpm_ppg_hitbit(u, PVT_BKT_VRF(pvt_node), 1628 PVT_BKT_IPT(pvt_node), bkt_node->key, bkt_node->key_len)); 1629 } 1630 } 1631 } 1632 1633 bad: 1634 if (pfx_arr != NULL) { 1635 alpm_util_free(pfx_arr); 1636 } 1637 return rv; 1638 1639 } 1640 1641 static int 1642 alpm_bkt_bnk_copy(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node, 1643 _alpm_bkt_info_t *src_bkt, int src_bnk, 1644 _alpm_bkt_info_t *dst_bkt, int dst_bnk) 1645 { 1646 int rv = BCM_E_UNAVAIL; 1647 int src_idx, dst_idx; 1648 1649 src_idx = ALPM_TAB_IDX_GET_BI_BNK(acb, src_bkt, src_bnk); 1650 dst_idx = ALPM_TAB_IDX_GET_BI_BNK(acb, dst_bkt, dst_bnk); 1651 rv = ALPM_DRV(u)->alpm_bkt_bnk_copy(u, acb, pvt_node, src_bkt, dst_bkt, 1652 src_idx, dst_idx); 1653 if (BCM_SUCCESS(rv)) { 1654 /* Performance improvement ALPMTBD in pfx_ent_idx_update */ 1655 rv = alpm_bkt_pfx_ent_idx_update(u, acb, pvt_node, src_bkt, src_bnk, 1656 dst_bkt, dst_bnk); 1657 } 1658 1659 return rv; 1660 } 1661 1662 int 1663 alpm_bkt_bnk_clear(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node, 1664 int tab_idx) 1665 { 1666 int rv = BCM_E_UNAVAIL; 1667 rv = ALPM_DRV(u)->alpm_bkt_bnk_clear(u, acb, pvt_node, tab_idx); 1668 return rv; 1669 } 1670 1671 /* Receive a new bank 'to_bnk' on one side and release old bank on 1672 * another side 1673 * 1674 * When we reach here, to_bnk should be neighbour of pvt_node's bkt_info. 1675 * After moving is done, free bank to free_bnk. 1676 */ 1677 static int 1678 alpm_bkt_bnk_ripple(int u, _alpm_cb_t *acb, 1679 _alpm_pvt_node_t *pvt_node, int to_bnk, int *free_bnk) 1680 { 1681 int i, ipt, rv = BCM_E_NONE; 1682 int bnkpb, start_bnk, end_bnk, mv_bnk; 1683 int mb, tb, tab_idx = 0; 1684 uint8 bnk_fmt; 1685 uint32 vet_bmp; 1686 _alpm_bkt_info_t *bkt_info, dst_bkt; 1687 int vrf_id; 1688 1689 vrf_id = PVT_BKT_VRF(pvt_node); 1690 ipt = PVT_BKT_IPT(pvt_node); 1691 bkt_info = &PVT_BKT_INFO(pvt_node); 1692 bnkpb = ACB_BNK_PER_BKT(acb, PVT_BKT_VRF(pvt_node)); 1693 start_bnk = PVT_ROFS(pvt_node); 1694 /* Find end bank */ 1695 for (i = 1; i < bnkpb; i++) { 1696 if (!BI_BNK_IS_USED(bkt_info, start_bnk % bnkpb)) { 1697 start_bnk++; 1698 i--; 1699 continue; 1700 } 1701 if (!BI_BNK_IS_USED(bkt_info, (start_bnk+i) % bnkpb)) { 1702 break; 1703 } 1704 } 1705 start_bnk = PVT_BKT_IDX(pvt_node) * bnkpb + start_bnk; 1706 end_bnk = start_bnk + i - 1; 1707 1708 /* 1. copy bank on the other side to to_bnk */ 1709 /* S: start, E: end, T: to_bnk 1710 ----------------- ----------------- 1711 | |#|#|#|#|#| | | -> |#|#|#|#|#| | | | 1712 ----------------- ----------------- 1713 ^ ^ ^ ^ 1714 T S E T 1715 ----------------- ----------------- 1716 | |#|#|#|#|#| | | -> | | |#|#|#|#|#| | 1717 ----------------- ----------------- 1718 ^ ^ ^ ^ 1719 S E T T 1720 */ 1721 if (to_bnk < start_bnk) { 1722 mv_bnk = end_bnk; 1723 /* Adjust start_bnk */ 1724 start_bnk = to_bnk; 1725 } else { 1726 mv_bnk = start_bnk; 1727 1728 /* Adjust start_bnk */ 1729 start_bnk++; 1730 while (start_bnk < end_bnk) { 1731 if (!BI_BNK_IS_USED(bkt_info, start_bnk % bnkpb)) { 1732 start_bnk++; 1733 } else { 1734 break; 1735 } 1736 } 1737 } 1738 mb = mv_bnk % bnkpb; 1739 tb = to_bnk % bnkpb; 1740 1741 /* Save src_idx before rofs, bkt-idx changes */ 1742 if (ACB_BKT_FIXED_FMT(acb, vrf_id)) { 1743 tab_idx = ALPM_TAB_IDX_GET_BI_BNK(acb, bkt_info, mb); 1744 } 1745 1746 sal_memset(&dst_bkt, 0, sizeof(dst_bkt)); 1747 BI_ROFS(&dst_bkt) = start_bnk % bnkpb; 1748 BI_BKT_IDX(&dst_bkt) = start_bnk / bnkpb; 1749 1750 ALPM_IER(alpm_bkt_bnk_copy(u, acb, pvt_node, bkt_info, mb, 1751 &dst_bkt, tb)); 1752 /* 2. Update bkt_info info */ 1753 bnk_fmt = bkt_info->bnk_fmt[mb]; 1754 vet_bmp = bkt_info->vet_bmp[mb]; 1755 ALPM_IER(alpm_bkt_bnk_chk_rsvd(u, ipt, ACB_BKT_VRF_POOL(acb, 1756 PVT_BKT_VRF(pvt_node)), to_bnk)); 1757 /* bkt_info could be changed here includes: 1758 * rofs, bkt-idx, bnk_fmt, so we need to save those values. 1759 */ 1760 ALPM_IER(alpm_bkt_bnk_free(u, ipt, acb, 1761 ACB_BKT_VRF_POOL(acb, PVT_BKT_VRF(pvt_node)), bkt_info, mb)); 1762 1763 PVT_ROFS(pvt_node) = BI_ROFS(&dst_bkt); 1764 PVT_BKT_IDX(pvt_node) = BI_BKT_IDX(&dst_bkt); 1765 bkt_info->bnk_fmt[tb] = bnk_fmt; 1766 bkt_info->vet_bmp[tb] = vet_bmp; 1767 1768 /* 3. Update PVT */ 1769 if (pvt_node != NULL) { 1770 rv = alpm_pvt_update_by_pvt_node(u, acb, pvt_node, ALPM_PVT_UPDATE_ALPM_DATA); 1771 ALPM_IER(rv); 1772 } 1773 1774 /* 4. invalidate old bnk */ 1775 if (ACB_BKT_FIXED_FMT(acb, vrf_id)) { 1776 ALPM_IER(alpm_bkt_bnk_clear(u, acb, pvt_node, tab_idx)); 1777 } 1778 1779 if (tb != mb) { 1780 bkt_info->bnk_fmt[mb] = 0; 1781 bkt_info->vet_bmp[mb] = 0; 1782 } 1783 1784 if (free_bnk != NULL) { 1785 *free_bnk = mv_bnk; 1786 } 1787 1788 acb->acb_cnt.c_ripple++; 1789 1790 return rv; 1791 } 1792 1793 static int 1794 alpm_bkt_move(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node, 1795 _alpm_bkt_info_t *src_bkt, _alpm_bkt_info_t *dst_bkt) 1796 { 1797 int rv = BCM_E_NONE; 1798 int bnkpb, sbnk, dbnk; 1799 int lsbnk, ldbnk; /* Local src/dst bnk */ 1800 _alpm_bkt_info_t tmp_bkt; 1801 int vrf_id; 1802 1803 vrf_id = PVT_BKT_VRF(pvt_node); 1804 bnkpb = ACB_BNK_PER_BKT(acb, PVT_BKT_VRF(pvt_node)); 1805 dbnk = BI_ROFS(dst_bkt); 1806 ldbnk = dbnk % bnkpb; 1807 while (!BI_BNK_IS_USED(dst_bkt, ldbnk)) { 1808 dbnk ++; 1809 ldbnk = dbnk % bnkpb; 1810 } 1811 1812 /* Copy */ 1813 for (sbnk = src_bkt->rofs; sbnk < src_bkt->rofs + bnkpb; sbnk++) { 1814 lsbnk = sbnk % bnkpb; 1815 ldbnk = dbnk % bnkpb; 1816 if (!BI_BNK_IS_USED(src_bkt, lsbnk)) { 1817 continue; 1818 } 1819 1820 dst_bkt->bnk_fmt[ldbnk] = src_bkt->bnk_fmt[lsbnk]; 1821 dst_bkt->vet_bmp[ldbnk] = src_bkt->vet_bmp[lsbnk]; 1822 1823 ALPM_IER(alpm_bkt_bnk_copy(u, acb, pvt_node, src_bkt, lsbnk, 1824 dst_bkt, ldbnk)); 1825 1826 dbnk++; 1827 ldbnk = dbnk % bnkpb; 1828 while (!BI_BNK_IS_USED(dst_bkt, ldbnk)) { 1829 dbnk++; 1830 ldbnk = dbnk % bnkpb; 1831 } 1832 } 1833 1834 /* swap src_bkt <-> dst_bkt info */ 1835 sal_memcpy(&tmp_bkt, src_bkt, sizeof(_alpm_bkt_info_t)); 1836 sal_memcpy(src_bkt, dst_bkt, sizeof(_alpm_bkt_info_t)); 1837 sal_memcpy(dst_bkt, &tmp_bkt, sizeof(_alpm_bkt_info_t)); 1838 1839 if (pvt_node != NULL) { 1840 rv = alpm_pvt_update_by_pvt_node(u, acb, pvt_node, ALPM_PVT_UPDATE_ALPM_DATA); 1841 ALPM_IER(rv); 1842 } 1843 1844 /* Invalidate src bucket */ 1845 for (sbnk = 0; sbnk < bnkpb; sbnk++) { 1846 if (!BI_BNK_IS_USED(dst_bkt, sbnk)) { 1847 continue; 1848 } 1849 1850 if (ACB_BKT_FIXED_FMT(acb, vrf_id)) { 1851 ALPM_IER(alpm_bkt_bnk_clear(u, acb, pvt_node, 1852 ALPM_TAB_IDX_GET_BI_BNK(acb, dst_bkt, sbnk))); 1853 } 1854 dst_bkt->vet_bmp[sbnk] = 0; 1855 } 1856 1857 /* Release bnk to global pool */ 1858 ALPM_IER(alpm_bkt_bnk_shrink(u, PVT_BKT_IPT(pvt_node), acb, 1859 ACB_BKT_VRF_POOL(acb, PVT_BKT_VRF(pvt_node)), dst_bkt, NULL)); 1860 1861 return rv; 1862 } 1863 1864 /* 1865 * 1866 0 1 2 3 4 5 6 7 1867 ----------------- 1868 | |#|#|#|#|#|*|*| 1869 ----------------- 1870 ^ ---> ^ 1871 from to 1872 1873 ----------------- 1874 | |*|*|*|#|#|#| | 1875 ----------------- 1876 ^ <-- ^ 1877 to from 1878 1879 * PLEASE NOTICE THAT from_bnk AND to_bnk INDICATE FREE BANK LOCATION, 1880 * NOT USED BANK LOCATION. 1881 */ 1882 static int 1883 alpm_bkt_free_bnk_move(int u, _alpm_cb_t *acb, _alpm_bkt_pool_conf_t *bp_conf, 1884 int from_bnk, int to_bnk) 1885 { 1886 int mv_bnk, step; 1887 _alpm_pvt_node_t *pvt_node = NULL; 1888 int tab_idx, free_bnk = -1, bnkpb; 1889 int rv = BCM_E_NONE; 1890 1891 bnkpb = BPC_BNK_PER_BKT(bp_conf); 1892 step = from_bnk < to_bnk ? 1 : -1; 1893 mv_bnk = from_bnk + step; 1894 while (ABS(mv_bnk - to_bnk) >= 0) { 1895 tab_idx = ALPM_TAB_IDX_GET_BKT_BNK(acb, 0, 1896 mv_bnk/bnkpb, mv_bnk%bnkpb); 1897 if (bp_conf->pvt_ptr && 1898 bp_conf->pvt_ptr[tab_idx] == NULL) { 1899 from_bnk = mv_bnk; 1900 mv_bnk += step; 1901 continue; 1902 } 1903 1904 if (bp_conf->pvt_ptr != NULL) { 1905 pvt_node = (_alpm_pvt_node_t *)bp_conf->pvt_ptr[tab_idx]; 1906 rv = alpm_bkt_bnk_ripple(u, acb, pvt_node, from_bnk, &free_bnk); 1907 ALPM_IEG(rv); 1908 if (ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_SANITY_NODE) { 1909 rv = alpm_cb_pvt_sanity_cb(u, acb, pvt_node, "FreeBnkMove"); 1910 ALPM_IEG(rv); 1911 } 1912 } 1913 1914 if (free_bnk == to_bnk) { 1915 break; 1916 } else { 1917 from_bnk = free_bnk; 1918 mv_bnk = from_bnk + step; 1919 } 1920 } 1921 1922 bad: 1923 return rv; 1924 } 1925 1926 /* 1927 * To find a minimum range which contains req_cnt free banks 1928 * 1929 * min_left and min_right are return value indicate the range. 1930 */ 1931 int 1932 alpm_bkt_free_bnk_range_get(int u, SHR_BITDCL *bnk_bmp, int bnk_sz, 1933 int req_cnt, int *rng_left, int *rng_right, 1934 int *rng_mid) 1935 { 1936 int i, rv = BCM_E_NONE; 1937 int alloc_sz, idx, free_cnt = 0; 1938 int *free_bnk_arr = NULL; 1939 1940 int min_idx = -1, min_range; 1941 1942 alloc_sz = bnk_sz * sizeof(int); 1943 ALPM_ALLOC_EG(free_bnk_arr, alloc_sz, "free_bnk_arr"); 1944 /* 1945 ------------------------------------------------------------- 1946 | |#|#| | | |#|#|#|#| | |#|#| | |#|#| |#| |#| |#|#|#|#| | |#| 1947 ------------------------------------------------------------- 1948 ^ ^ 1949 0 bnk_sz-1 1950 */ 1951 min_range = bnk_sz; 1952 for (i = 0; i < bnk_sz; i++) { 1953 if (!SHR_BITGET(bnk_bmp, i)) { 1954 free_bnk_arr[free_cnt] = i; 1955 idx = free_cnt - (req_cnt - 1); 1956 if (idx >= 0) { 1957 if (min_range > (free_bnk_arr[free_cnt] - free_bnk_arr[idx])) { 1958 min_range = (free_bnk_arr[free_cnt] - free_bnk_arr[idx]); 1959 min_idx = free_cnt; 1960 } 1961 } 1962 free_cnt ++; 1963 } 1964 } 1965 1966 if (min_idx != -1) { 1967 *rng_left = free_bnk_arr[min_idx - (req_cnt - 1)]; 1968 *rng_right = free_bnk_arr[min_idx]; 1969 *rng_mid = free_bnk_arr[min_idx - (req_cnt - 1) / 2]; 1970 } else { 1971 rv = BCM_E_FULL; 1972 } 1973 1974 bad: 1975 if (free_bnk_arr != NULL) { 1976 alpm_util_free(free_bnk_arr); 1977 } 1978 return rv; 1979 } 1980 1981 static int 1982 alpm_bkt_free(int u, _alpm_cb_t *acb, int vrf_id, int ipt, 1983 _alpm_bkt_info_t *bkt_info) 1984 { 1985 int rv = BCM_E_NONE; 1986 int bnk; 1987 _alpm_bkt_pool_conf_t *bp_conf; 1988 1989 bp_conf = ACB_BKT_VRF_POOL(acb, vrf_id); 1990 for (bnk = 0; bnk < ALPM_BPB_MAX; bnk++) { 1991 if (BI_BNK_IS_USED(bkt_info, bnk)) { 1992 ALPM_IER(alpm_bkt_bnk_free(u, ipt, acb, bp_conf, bkt_info, bnk)); 1993 } 1994 } 1995 bkt_info->reverse = 0; 1996 1997 return rv; 1998 } 1999 2000 /* OUT: bkt_info */ 2001 static int 2002 alpm_bkt_alloc(int u, _alpm_cb_t *acb, int vrf_id, int ipt, int req_bnk_cnt, 2003 _alpm_bkt_info_t *bkt_info, int *avl_bnk_cnt) 2004 { 2005 int rv = BCM_E_NONE; 2006 rv = alpm_bkt_alloc_attempt(u, acb, vrf_id, ipt, req_bnk_cnt, 2007 ACB_BNK_PER_BKT(acb, vrf_id), bkt_info, 2008 avl_bnk_cnt); 2009 if (rv != BCM_E_FULL) { 2010 goto end; 2011 } 2012 2013 /* rv == BCM_E_FULL 2014 * 2015 * No free bkt available, start defragment process to create a 2016 * new available bucket. 2017 * It's also bucket sharing process for TH/TD3 2018 */ 2019 if (ACB_BKT_FIXED_FMT(acb, vrf_id)) { 2020 rv = alpm_cb_merge(u, acb, vrf_id, ipt); 2021 return BCM_SUCCESS(rv) ? BCM_E_BUSY : rv; 2022 } 2023 2024 rv = alpm_cb_defrag(u, acb, vrf_id, ipt); 2025 if (BCM_SUCCESS(rv)) { 2026 rv = alpm_bkt_alloc_attempt(u, acb, vrf_id, ipt, req_bnk_cnt, 2027 1, bkt_info, avl_bnk_cnt); 2028 } 2029 2030 end: 2031 return rv; 2032 } 2033 2034 static int 2035 alpm_bkt_insert(int u, _alpm_cb_t *acb, 2036 _bcm_defip_cfg_t *lpm_cfg, _alpm_pvt_node_t *pvt_node, 2037 uint32 *ent_idx) 2038 { 2039 int rv = BCM_E_NONE; 2040 int fmt_update = 0; 2041 int vrf_id = 0; 2042 int pfx_len; 2043 2044 vrf_id = PVT_BKT_VRF(pvt_node); 2045 if (ACB_BKT_FIXED_FMT(acb, vrf_id)) { 2046 pfx_len = lpm_cfg->defip_sub_len; 2047 } else { 2048 pfx_len = lpm_cfg->defip_sub_len - PVT_KEY_LEN(pvt_node); 2049 } 2050 2051 rv = alpm_bkt_ent_get(u, vrf_id, acb, pvt_node, pfx_len, ent_idx, 2052 &fmt_update, 0); 2053 if (BCM_SUCCESS(rv)) { 2054 rv = alpm_bkt_ent_write(u, acb, pvt_node, lpm_cfg, *ent_idx, ALPM_PVT_UPDATE_ALL); 2055 if (BCM_SUCCESS(rv) && fmt_update && !ACB_BKT_FIXED_FMT(acb, vrf_id)) { 2056 _alpm_tcam_write_t *tcam_write = lpm_cfg->tcam_write; 2057 2058 if (tcam_write && (tcam_write->hw_idx >= 0)) { 2059 int rv1, pkm, ipt; 2060 ipt = PVT_BKT_IPT(pvt_node); 2061 pkm = ALPM_PKM_RECOVER(u, ipt); 2062 rv1 = _tcam_entry_write(u, pkm, tcam_write->ent, tcam_write->hw_idx, 2063 tcam_write->hw_idx); 2064 ALPM_INFO(("Write to TCAM HW at hw_idx %d by pvt update (%d)\n", 2065 tcam_write->hw_idx, rv1)); 2066 tcam_write->hw_idx = -1; /* avoid write again */ 2067 } 2068 2069 rv = alpm_pvt_update_by_pvt_node(u, acb, pvt_node, ALPM_PVT_UPDATE_ALPM_DATA); 2070 } 2071 if (BCM_FAILURE(rv)) { 2072 rv = alpm_bkt_ent_del(u, acb, pvt_node, *ent_idx); 2073 } 2074 } 2075 2076 if (BCM_FAILURE(rv)) { 2077 ALPM_VERB(("**ACB(%d).BKT.INS: failed %d\n", ACB_IDX(acb), rv)); 2078 } 2079 2080 return rv; 2081 } 2082 2083 int 2084 alpm_bkt_delete(int u, _alpm_cb_t *acb, 2085 _bcm_defip_cfg_t *lpm_cfg, _alpm_pvt_node_t *pvt_node, 2086 uint32 *key_idx) 2087 { 2088 int rv = BCM_E_NONE; 2089 2090 /* ALPMTBD */ 2091 2092 return rv; 2093 } 2094 2095 static int 2096 alpm_bkt_pfx_idx_backup(int u, _alpm_bkt_pfx_arr_t *pfx_arr, uint32 **bak_idx) 2097 { 2098 int i, rv = BCM_E_NONE; 2099 int count = pfx_arr->pfx_cnt; 2100 uint32 *pfx_idx; 2101 2102 ALPM_ALLOC_EG(pfx_idx, count * sizeof(uint32), "bak_idx"); 2103 2104 for (i = 0; i < count; i++) { 2105 pfx_idx[i] = pfx_arr->pfx[i]->ent_idx; 2106 } 2107 2108 if (bak_idx != NULL) { 2109 *bak_idx = pfx_idx; 2110 } 2111 2112 bad: 2113 return rv; 2114 } 2115 2116 static void 2117 alpm_bkt_pfx_idx_restore(int u, _alpm_bkt_pfx_arr_t *pfx_arr, uint32 *bak_idx) 2118 { 2119 int i; 2120 uint32 tmp_idx; 2121 int count = pfx_arr->pfx_cnt; 2122 2123 for (i = 0; i < count; i++) { 2124 tmp_idx = pfx_arr->pfx[i]->ent_idx; 2125 pfx_arr->pfx[i]->ent_idx = bak_idx[i]; 2126 bak_idx[i] = tmp_idx; 2127 } 2128 2129 return ; 2130 } 2131 2132 static int 2133 alpm_bkt_pfx_copy(int u, _alpm_cb_t *acb, 2134 _alpm_bkt_pfx_arr_t *pfx_arr, 2135 _alpm_pvt_node_t *opvt_node, 2136 _alpm_pvt_node_t *npvt_node) 2137 { 2138 int i; 2139 int rv = BCM_E_UNAVAIL; 2140 2141 rv = ALPM_DRV(u)->alpm_bkt_pfx_copy(u, acb, pfx_arr, opvt_node, 2142 npvt_node); 2143 if (ALPM_TCAM_HB_IS_PTR(u)) { 2144 for (i = 0; i < pfx_arr->pfx_cnt; i++) { 2145 ALPM_IER(alpm_ppg_hitbit(u, PVT_BKT_VRF(opvt_node), PVT_BKT_IPT(opvt_node), 2146 pfx_arr->pfx[i]->key, pfx_arr->pfx[i]->key_len)); 2147 } 2148 } 2149 return rv; 2150 } 2151 2152 static int 2153 alpm_bkt_pfx_clean(int u, _alpm_cb_t *acb, 2154 _alpm_pvt_node_t *pvt_node, 2155 int count, uint32 *ent_idx) 2156 { 2157 int rv = BCM_E_UNAVAIL; 2158 2159 rv = ALPM_DRV(u)->alpm_bkt_pfx_clean(u, acb, pvt_node, count, ent_idx); 2160 2161 return rv; 2162 } 2163 2164 static int 2165 alpm_bkt_pfx_shrink(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node, void *user_data) 2166 { 2167 int i, rv = BCM_E_NONE; 2168 uint32 *bak_idx = NULL; 2169 alpm_lib_trie_t *bkt_trie = NULL; 2170 _alpm_bkt_pfx_arr_t *pfx_arr = NULL; 2171 _alpm_bkt_info_t *bkt_info = NULL; 2172 int shrink_empty_only; 2173 int from_bkt_split = 0; 2174 2175 bkt_info = &PVT_BKT_INFO(pvt_node); 2176 shrink_empty_only = *(int *)user_data; 2177 from_bkt_split = (shrink_empty_only == 2); 2178 if (shrink_empty_only) { 2179 int tb, tbnk; 2180 int has_empty_bnk = 0; 2181 int bnkpb = ACB_BNK_PER_BKT(acb, PVT_BKT_VRF(pvt_node)); 2182 2183 for (tb = BI_ROFS(bkt_info); tb < BI_ROFS(bkt_info) + bnkpb; tb++) { 2184 tbnk = tb % bnkpb; 2185 if (!BI_BNK_IS_USED(bkt_info, tbnk)) { 2186 continue; 2187 } 2188 if (bkt_info->vet_bmp[tbnk] == 0) { 2189 has_empty_bnk = 1; 2190 break; 2191 } 2192 } 2193 if (!has_empty_bnk) { 2194 if (from_bkt_split) { 2195 shrink_empty_only = 0; 2196 } else { 2197 return rv; 2198 } 2199 } 2200 } 2201 2202 ALPM_ALLOC_EG(pfx_arr, sizeof(*pfx_arr), "pfx_arr"); 2203 bkt_trie = PVT_BKT_TRIE(pvt_node); 2204 rv = alpm_lib_trie_traverse(bkt_trie, alpm_trie_pfx_cb, pfx_arr, 2205 trieTraverseOrderIn); 2206 ALPM_IEG(rv); 2207 rv = alpm_bkt_pfx_idx_backup(u, pfx_arr, &bak_idx); 2208 ALPM_IEG(rv); 2209 2210 rv = ALPM_DRV(u)->alpm_bkt_pfx_shrink(u, acb, pvt_node, pfx_arr, 2211 shrink_empty_only); 2212 2213 if (BCM_SUCCESS(rv)) { 2214 int fmt_update = 0; 2215 rv = alpm_bkt_bnk_shrink(u, PVT_BKT_IPT(pvt_node), acb, 2216 ACB_BKT_VRF_POOL(acb, PVT_BKT_VRF(pvt_node)), 2217 bkt_info, &fmt_update); 2218 ALPM_IEG(rv); 2219 if (fmt_update && !ACB_BKT_FIXED_FMT(acb, PVT_BKT_VRF(pvt_node))) { 2220 rv = alpm_pvt_update_by_pvt_node(u, acb, pvt_node, ALPM_PVT_UPDATE_ALPM_DATA); 2221 ALPM_IEG(rv); 2222 } 2223 } 2224 2225 if (ALPM_TCAM_HB_IS_PTR(u)) { 2226 for (i = 0; i < pfx_arr->pfx_cnt; i++) { 2227 if (bak_idx[i] == pfx_arr->pfx[i]->ent_idx) { 2228 continue; 2229 } 2230 rv = alpm_ppg_hitbit(u, PVT_BKT_VRF(pvt_node), PVT_BKT_IPT(pvt_node), 2231 pfx_arr->pfx[i]->key, pfx_arr->pfx[i]->key_len); 2232 ALPM_IEG(rv); 2233 } 2234 } 2235 2236 bad: 2237 2238 if (bak_idx != NULL) { 2239 alpm_util_free(bak_idx); 2240 } 2241 2242 if (pfx_arr != NULL) { 2243 alpm_util_free(pfx_arr); 2244 } 2245 2246 return rv; 2247 } 2248 2249 static int 2250 alpm_bkt_trie_split_cb(alpm_lib_trie_node_t *trie, alpm_lib_trie_bpm_cb_info_t *info) 2251 { 2252 /* trieNodeTypeInternalPpg indicates internally created node for ppg */ 2253 if (trie->type != trieNodeTypeInternalPpg) { 2254 return alpm_trie_pfx_cb(trie, (void *)info->user_data); 2255 } 2256 2257 return BCM_E_NONE; 2258 } 2259 2260 int 2261 alpm_bkt_split_cb(alpm_lib_trie_node_t *ptrie, alpm_lib_trie_node_t *trie, 2262 alpm_lib_trie_traverse_state_t *state, void *info) 2263 { 2264 _alpm_bkt_split_cb_data_t *cb_data = (_alpm_bkt_split_cb_data_t *)info; 2265 /* Split from default bkt */ 2266 if (ACB_IDX(cb_data->acb) > 0 && cb_data->pvt_len == 0) { 2267 if (ptrie->count < cb_data->bkt_cur_cnt && 2268 trie->count < ptrie->count) { 2269 return 1; 2270 } 2271 } 2272 2273 return 0; 2274 } 2275 2276 static int 2277 alpm_bkt_trie_split(int u, _alpm_cb_t *acb, 2278 _bcm_defip_cfg_t *lpm_cfg, 2279 alpm_lib_trie_t **spl_bkt_trie, 2280 _alpm_pvt_node_t **spl_pvt_node, 2281 int max_key_len, 2282 int *max_spl_cnt) 2283 { 2284 int rv; 2285 int pkm, ipt, vrf_id, max_split_len, bkt_cnt; 2286 uint32 pvt_len, pvt_key[5] = {0}; 2287 2288 _alpm_pvt_node_t *ppn = NULL, *cpn = NULL; 2289 alpm_lib_trie_t *pbt = NULL, *cbt = NULL; 2290 2291 if (lpm_cfg->spl_pn != NULL) { 2292 ppn = (_alpm_pvt_node_t *)lpm_cfg->spl_pn; 2293 } else { 2294 ppn = ACB_HAS_TCAM(acb) ? lpm_cfg->l1_pvt_node : lpm_cfg->pvt_node; 2295 } 2296 pbt = PVT_BKT_TRIE(ppn); 2297 bkt_cnt = pbt->trie->count; 2298 ALPM_IEG(alpm_lib_trie_init(max_key_len, &cbt)); 2299 pkm = ALPM_LPM_PKM(u, lpm_cfg); 2300 ipt = ALPM_PKM2IPT(pkm); 2301 vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 2302 2303 if (lpm_cfg->spl_key_len != 0) { 2304 rv = alpm_lib_trie_split2(pbt, lpm_cfg->spl_key, lpm_cfg->spl_key_len, 2305 pvt_key, &pvt_len, &cbt->trie, 0xfffffff, 2306 TRUE); 2307 } else { 2308 _alpm_bkt_split_cb_data_t scb_data; 2309 scb_data.acb = acb; 2310 scb_data.bkt_cur_cnt = pbt->trie->count; 2311 scb_data.pvt_len = PVT_KEY_LEN(ppn); 2312 alpm_trie_max_split_attr(u, acb, ppn, &max_split_len, max_spl_cnt); 2313 rv = alpm_lib_trie_split(pbt, max_split_len, pvt_key, &pvt_len, 2314 &cbt->trie, FALSE, 2315 ACB_BKT_FIXED_FMT(acb, vrf_id) ? NULL : alpm_bkt_split_cb, 2316 &scb_data, *max_spl_cnt); 2317 } 2318 ALPM_IEG(rv); 2319 2320 /* Split bucket2A in non-last level could cause misplaced routes in other 2321 * buckets in next level of current level. 2322 * Note: bucket2A: bucketA in Level 2. 2323 * bucket3B: bucketB in Level 3. 2324 * Case 1: 2325 * If split node is trieNodeTypePayload node, no misplaced routes are generated. 2326 * Case 2: 2327 * If split node is trieNodeTypeInternal node, then: 2328 * Case 2.1: 2329 * If lpm of split node doesn't exist in this bucket2A, Good. 2330 * Case 2.2: 2331 * If lpm of split node(Say it's pivot of bucket3B) exists in this 2332 * bucket2A, then: 2333 * 2334 * Case 2.2.1: 2335 * no route in bucket3B is covered by split node. Good. 2336 * Case 2.2.2: 2337 * routes in bucket3B are covered by split node. 2338 * ====> Misplaced Routes (Need to move them to new location) 2339 */ 2340 if (ACB_HAS_PVT(acb, vrf_id)) { 2341 if (cbt->trie->type == trieNodeTypeInternal) { 2342 _alpm_pvt_node_t *spl_npn = NULL; 2343 _alpm_bkt_node_t *lpm_bn = NULL; 2344 _alpm_bkt_node_t tmp_bn; 2345 /* Case 2 */ 2346 spl_npn = lpm_cfg->spl_npn; 2347 if (spl_npn) { 2348 sal_memcpy(tmp_bn.key, spl_npn->key, sizeof(tmp_bn.key)); 2349 tmp_bn.key_len = spl_npn->key_len; 2350 } 2351 if (spl_npn && spl_npn->key_len < pvt_len) { 2352 (void)alpm_lib_trie_insert(pbt, tmp_bn.key, 2353 tmp_bn.key_len, (alpm_lib_trie_node_t *)&tmp_bn); 2354 } 2355 rv = alpm_lib_trie_find_lpm(pbt, pvt_key, pvt_len, (alpm_lib_trie_node_t **)&lpm_bn); 2356 if (spl_npn && spl_npn->key_len < pvt_len) { 2357 (void)alpm_lib_trie_delete(pbt, tmp_bn.key, 2358 tmp_bn.key_len, (alpm_lib_trie_node_t **)&tmp_bn); 2359 } 2360 if (BCM_FAILURE(rv)) { 2361 acb->acb_cnt.c_spl_mp_cs21++; 2362 rv = BCM_E_NONE; 2363 } else { 2364 /* Case 2.2 */ 2365 _alpm_cb_t *nxt_cb = NULL; 2366 _alpm_pvt_node_t *lpm_pn = NULL; 2367 _alpm_bkt_pfx_arr_t *pfx_arr = NULL; 2368 alpm_lib_trie_t *pvt_trie; 2369 alpm_lib_trie_node_t *tmp_node; 2370 2371 nxt_cb = ACB_DWN(u, acb); 2372 pvt_trie = ACB_PVT_TRIE(nxt_cb, vrf_id, ipt); 2373 if (spl_npn && spl_npn->key_len < pvt_len) { 2374 (void)alpm_lib_trie_insert(pvt_trie, spl_npn->key, 2375 spl_npn->key_len, (alpm_lib_trie_node_t *)spl_npn); 2376 } 2377 rv = alpm_pvt_find_by_key(u, nxt_cb, vrf_id, ipt, 2378 lpm_bn->key, lpm_bn->key_len, &lpm_pn); 2379 if (BCM_SUCCESS(rv) && PVT_BKT_TRIE(lpm_pn)->trie) { 2380 alpm_lib_trie_bpm_cb_info_t cb_info; 2381 ALPM_ALLOC_EG(pfx_arr, sizeof(*pfx_arr), "pfx_arr"); 2382 cb_info.pfx = pvt_key; 2383 cb_info.len = pvt_len; 2384 cb_info.user_data = pfx_arr; 2385 /* PERF OPT point */ 2386 rv = alpm_lib_trie_ppg(PVT_BKT_TRIE(lpm_pn), 0, 2387 pvt_key, pvt_len, alpm_bkt_trie_split_cb, 2388 &cb_info); 2389 if (BCM_SUCCESS(rv)) { 2390 if (pfx_arr->pfx_cnt == 0) { 2391 acb->acb_cnt.c_spl_mp_cs221++; 2392 } else { 2393 acb->acb_cnt.c_spl_mp_cs222++; 2394 2395 rv = BCM_E_BUSY; 2396 if (spl_npn && spl_npn == lpm_pn) { 2397 lpm_cfg->spl_pn = lpm_cfg->spl_opn; 2398 } else { 2399 lpm_cfg->spl_pn = lpm_pn; 2400 } 2401 sal_memcpy(lpm_cfg->spl_key, pvt_key, sizeof(lpm_cfg->spl_key)); 2402 lpm_cfg->spl_key_len = pvt_len; 2403 } 2404 } 2405 alpm_util_free(pfx_arr); 2406 } 2407 if (spl_npn && spl_npn->key_len < pvt_len) { 2408 (void)alpm_lib_trie_delete(pvt_trie, spl_npn->key, 2409 spl_npn->key_len, &tmp_node); 2410 } 2411 } 2412 } else { 2413 /* Case 1: split node is trieNodeTypePayload node. */ 2414 acb->acb_cnt.c_spl_mp_cs1++; 2415 } 2416 } 2417 2418 ALPM_IEG(rv); 2419 2420 ALPM_ALLOC_EG(cpn, sizeof(_alpm_pvt_node_t), "pvt_node"); 2421 PVT_BKT_TRIE(cpn) = cbt; 2422 PVT_BKT_VRF(cpn) = vrf_id; 2423 PVT_BKT_PKM(cpn) = pkm; 2424 PVT_KEY_CPY(cpn, pvt_key); 2425 PVT_KEY_LEN(cpn) = pvt_len; 2426 PVT_FLAGS(cpn) = lpm_cfg->defip_flags; 2427 *spl_pvt_node = cpn; 2428 *spl_bkt_trie = cbt; 2429 2430 ALPM_INFO(("**ACB(%d).BKT.SPLIT %d entries from bkt %d(cnt %d)\n", 2431 ACB_IDX(acb), cbt->trie->count, 2432 PVT_BKT_IDX(ppn), bkt_cnt)); 2433 2434 return rv; 2435 2436 bad: 2437 2438 if (cbt != NULL) { 2439 if (cbt->trie != NULL) { 2440 int rv2; 2441 rv2 = alpm_lib_trie_merge(pbt, cbt->trie, pvt_key, pvt_len); 2442 if (BCM_FAILURE(rv2)) { 2443 ALPM_ERR(("alpm_lib_trie_merge error in trie split, rv %d\n", rv2)); 2444 } 2445 } 2446 2447 alpm_lib_trie_destroy(cbt); 2448 } 2449 2450 if (cpn != NULL) { 2451 alpm_util_free(cpn); 2452 } 2453 2454 return rv; 2455 } 2456 2457 static int 2458 alpm_bkt_split_pvt_add(int u, _alpm_cb_t *acb, 2459 _bcm_defip_cfg_t *pvt_lpm_cfg, 2460 _alpm_pvt_node_t *pvt_node) 2461 { 2462 int rv = BCM_E_NONE; 2463 int ipt, vrf_id; 2464 int pvt_len = 0; 2465 alpm_lib_trie_t *pfx_trie = NULL; 2466 _alpm_pfx_node_t *pfx_node = NULL; 2467 2468 pvt_len = PVT_KEY_LEN(pvt_node); 2469 ipt = ALPM_LPM_IPT(u, pvt_lpm_cfg); 2470 vrf_id = ALPM_LPM_VRF_ID(u, pvt_lpm_cfg); 2471 pfx_trie = ALPM_VRF_TRIE(u, vrf_id, ipt); 2472 2473 /* Assoc-data and bpm_len info of pvt_lpm_cfg comes from alpm_lib_trie_find_lpm */ 2474 ALPM_IER(alpm_lib_trie_find_lpm(pfx_trie, pvt_node->key, pvt_len, 2475 (alpm_lib_trie_node_t **)&pfx_node)); 2476 PVT_BPM_LEN(pvt_node) = pfx_node->key_len; 2477 PVT_BKT_DEF(pvt_node) = pfx_node->bkt_ptr; 2478 2479 /* Construct KEY(IP address), should come from pvt_key */ 2480 alpm_trie_pfx_to_cfg(u, pvt_node->key, pvt_len, pvt_lpm_cfg); 2481 sal_memcpy(pvt_lpm_cfg->user_data, pvt_node->key, sizeof(uint32) * 5); 2482 /* Construct Assoc-data */ 2483 if (pfx_node->bkt_ptr != NULL) { 2484 alpm_util_adata_trie_to_cfg(u, &pfx_node->bkt_ptr->adata, pvt_lpm_cfg); 2485 pvt_lpm_cfg->default_miss = 0; 2486 } else { 2487 alpm_util_adata_zero_cfg(u, pvt_lpm_cfg); 2488 pvt_lpm_cfg->default_miss = 1; 2489 } 2490 rv = alpm_pvt_insert(u, acb, pvt_lpm_cfg); 2491 if (BCM_SUCCESS(rv)) { 2492 PVT_IDX(pvt_node) = pvt_lpm_cfg->defip_index; 2493 rv = alpm_lib_trie_insert(ACB_PVT_TRIE(acb, vrf_id, ipt), pvt_node->key, pvt_len, 2494 (alpm_lib_trie_node_t *)pvt_node); 2495 } 2496 /* rv = *_E_FULL is allowed here */ 2497 2498 return rv; 2499 } 2500 2501 /* Case of add new L1 pvt during L2 bkt split: 2502 If new L2 bkt belongs to new L1 pvt, add new L2 bkt. 2503 */ 2504 static int 2505 alpm_bkt_add_to_npvt(int u, _alpm_cb_t *acb, 2506 _bcm_defip_cfg_t *lpm_cfg, 2507 _alpm_pvt_node_t *npvt_node) 2508 { 2509 int rv = BCM_E_NONE; 2510 int vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 2511 int ipt = ALPM_LPM_IPT(u, lpm_cfg); 2512 uint32 *prefix, length; 2513 uint32 ent_idx; 2514 int bkt_trie_added = 0; 2515 2516 alpm_lib_trie_t *bkt_trie = NULL; 2517 alpm_lib_trie_node_t *tmp_node = NULL; 2518 _alpm_bkt_node_t *bkt_node = NULL; 2519 _alpm_pvt_node_t *pvt_node; 2520 2521 _alpm_tcam_write_t *tcam_write = lpm_cfg->tcam_write; 2522 2523 ALPM_IEG(alpm_pvt_find(u, acb, lpm_cfg, &pvt_node)); 2524 if (pvt_node == npvt_node) { /* belongs to new L1 pvt */ 2525 lpm_cfg->l1_pvt_node = pvt_node; 2526 /* lpm_cfg->tcam_write may update here due to new L2 pvt added */ 2527 2528 rv = alpm_bkt_insert(u, acb, lpm_cfg, pvt_node, &ent_idx); 2529 2530 tcam_write->rv = rv; 2531 if (BCM_FAILURE(rv)) { 2532 /* If FULL, return no error, continue and will try again 2533 bkt split when back to alpm_cb_insert */ 2534 if (rv == BCM_E_FULL) { 2535 ALPM_INFO(("ACB(%d): new L2 bkt add FULL (%d) and retry\n", ACB_IDX(acb), rv)); 2536 return BCM_E_NONE; 2537 } else { 2538 ALPM_ERR(("ACB(%d): new L2 bkt add failed (%d)\n", ACB_IDX(acb), rv)); 2539 } 2540 } else { 2541 ALPM_INFO(("ACB(%d): new L2 bkt add OK\n", ACB_IDX(acb))); 2542 } 2543 } else { 2544 return BCM_E_NONE; /* exit */ 2545 } 2546 2547 /* return FULL when Expand exceeds bnk_threshold */ 2548 if (rv == BCM_E_RESOURCE) { 2549 rv = BCM_E_FULL; 2550 } 2551 2552 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 2553 2554 lpm_cfg->defip_index = ent_idx; 2555 2556 /* Allocate Payload */ 2557 ALPM_ALLOC_EG(bkt_node, sizeof(_alpm_bkt_node_t), "bkt_node"); 2558 prefix = lpm_cfg->user_data; 2559 length = lpm_cfg->defip_sub_len; 2560 sal_memcpy(bkt_node->key, prefix, sizeof(bkt_node->key)); 2561 bkt_node->key_len = length; 2562 bkt_node->ent_idx = ent_idx; 2563 alpm_util_adata_cfg_to_trie(u, lpm_cfg, &bkt_node->adata); 2564 /* Insert the prefix */ 2565 /* bucket trie insert */ 2566 bkt_trie = PVT_BKT_TRIE(pvt_node); 2567 rv = alpm_lib_trie_insert(bkt_trie, prefix, length, (alpm_lib_trie_node_t *)bkt_node); 2568 ALPM_IEG(rv); 2569 bkt_trie_added = 1; 2570 2571 ALPM_IEG(alpm_vrf_pfx_trie_add(u, acb, lpm_cfg, bkt_node)); 2572 2573 if (BCM_SUCCESS(rv) && 2574 ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_SANITY_NODE) { 2575 rv = alpm_cb_pvt_sanity_cb(u, acb, pvt_node, "CBInsert"); 2576 } 2577 2578 VRF_ROUTE_ADD(acb, vrf_id, ipt); 2579 2580 return rv; 2581 2582 bad: 2583 if (bkt_trie_added) { 2584 (void)alpm_lib_trie_delete(bkt_trie, prefix, length, &tmp_node); 2585 } 2586 if (bkt_node != NULL) { 2587 alpm_util_free(bkt_node); 2588 } 2589 2590 return rv; 2591 } 2592 2593 /* 2594 * OUT pvt_node, 2595 * OUT bkt_node 2596 */ 2597 2598 int 2599 alpm_cb_find(int u, _alpm_cb_t *acb, _bcm_defip_cfg_t *lpm_cfg, 2600 _alpm_pvt_node_t **pvt_node, _alpm_bkt_node_t **bkt_node) 2601 { 2602 int rv = BCM_E_NONE; 2603 2604 rv = alpm_pvt_find(u, acb, lpm_cfg, pvt_node); 2605 if (BCM_SUCCESS(rv)) { 2606 rv = alpm_bkt_find(u, acb, lpm_cfg, *pvt_node, bkt_node); 2607 } else { 2608 rv = BCM_E_NOT_FOUND; 2609 } 2610 2611 return rv; 2612 } 2613 2614 /* 2615 * Find and update the match in the database. 2616 * Returns BCM_E_NONE, if found and updated. 2617 * BCM_E_NOT_FOUND if not found 2618 * BCM_E_FAIL, if update failed. 2619 */ 2620 static int 2621 alpm_cb_update(int u, _alpm_cb_t *acb, 2622 _bcm_defip_cfg_t *lpm_cfg) 2623 { 2624 _alpm_ppg_data_t pdata; 2625 _alpm_pvt_node_t *pvt_node; 2626 _alpm_bkt_node_t *bkt_node; 2627 int rv = BCM_E_NONE; 2628 2629 /* Find and update the entry */ 2630 pvt_node = (_alpm_pvt_node_t *)lpm_cfg->pvt_node; 2631 bkt_node = (_alpm_bkt_node_t *)lpm_cfg->bkt_node; 2632 if (bkt_node == NULL) { 2633 ALPM_ERR(("**ACB(%d).FIND.UPDATE bkt_node == NULL...\n", 2634 ACB_IDX(acb))); 2635 return BCM_E_FAIL; 2636 } 2637 alpm_util_adata_cfg_to_trie(u, lpm_cfg, &bkt_node->adata); 2638 ALPM_IER(alpm_bkt_ent_write(u, acb, pvt_node, lpm_cfg, bkt_node->ent_idx, ALPM_PVT_UPDATE_ASSOC_DATA)); 2639 2640 if (ACB_HAS_RTE(acb, ALPM_LPM_VRF_ID(u, lpm_cfg))) { 2641 /* Perform INSERT propagation to update assoc_data */ 2642 alpm_ppg_prepare(u, lpm_cfg, lpm_cfg->defip_sub_len, bkt_node, &pdata); 2643 ALPM_IER(alpm_ppg_assoc_data(u, ALPM_PPG_INSERT, &pdata)); 2644 } 2645 return rv; 2646 } 2647 2648 static int 2649 alpm_vrf_pfx_trie_add(int u, _alpm_cb_t *acb, 2650 _bcm_defip_cfg_t *lpm_cfg, void *udata) 2651 { 2652 int rv = BCM_E_NONE, ipt, vrf_id; 2653 uint32 *prefix; 2654 uint32 length; 2655 2656 alpm_lib_trie_t *pfx_trie = NULL; 2657 alpm_lib_trie_node_t *lpmp; 2658 _alpm_pfx_node_t *pfx_node = NULL, *tmp_node; 2659 2660 vrf_id = lpm_cfg->defip_vrf; 2661 if (vrf_id == BCM_L3_VRF_GLOBAL) { 2662 /* GLobal low */ 2663 vrf_id = ALPM_VRF_ID_GLO(u); 2664 } else if (vrf_id < 0) { 2665 assert(0); 2666 } 2667 2668 if (ACB_HAS_PVT(acb, vrf_id)) { 2669 return rv; 2670 } 2671 2672 ipt = ALPM_LPM_IPT(u, lpm_cfg); 2673 pfx_trie = ALPM_VRF_TRIE(u, vrf_id, ipt); 2674 2675 if (lpm_cfg->defip_sub_len == 0) { 2676 /* Add a route already in trie */ 2677 lpmp = NULL; 2678 rv = alpm_lib_trie_find_lpm(pfx_trie, 0, 0, &lpmp); 2679 if (BCM_SUCCESS(rv)) { 2680 tmp_node = (_alpm_bkt_node_t *)lpmp; 2681 tmp_node->bkt_ptr = udata; 2682 } 2683 2684 return rv; 2685 } 2686 2687 /* Non default route start from here */ 2688 prefix = lpm_cfg->user_data; 2689 length = lpm_cfg->defip_sub_len; 2690 2691 ALPM_ALLOC_EG(pfx_node, sizeof(_alpm_pfx_node_t), "VRF_trie_node"); 2692 2693 sal_memcpy(pfx_node->key, prefix, sizeof(pfx_node->key)); 2694 pfx_node->key_len = length; 2695 pfx_node->ent_idx = lpm_cfg->defip_index; 2696 pfx_node->bkt_ptr = udata; 2697 2698 rv = alpm_lib_trie_insert(pfx_trie, prefix, length, (alpm_lib_trie_node_t *)pfx_node); 2699 if (BCM_FAILURE(rv)) { 2700 if (pfx_node != NULL) { 2701 alpm_util_free(pfx_node); 2702 } 2703 } 2704 2705 bad: 2706 return rv; 2707 } 2708 2709 static int 2710 alpm_vrf_pfx_trie_delete(int u, _alpm_cb_t *acb, 2711 _bcm_defip_cfg_t *lpm_cfg, void *udata, 2712 _alpm_bkt_node_t **alt_def_pfx, 2713 uint32 *alt_bpm_len) 2714 { 2715 int rv = BCM_E_NONE, rv2, ipt, vrf_id; 2716 uint32 *prefix; 2717 uint32 pfx_len, bpm_len; 2718 2719 alpm_lib_trie_t *pfx_trie = NULL; 2720 alpm_lib_trie_node_t *lpmp = NULL; 2721 _alpm_pfx_node_t *pfx_node = NULL, *tmp_node; 2722 2723 vrf_id = lpm_cfg->defip_vrf; 2724 if (vrf_id == BCM_L3_VRF_GLOBAL) { 2725 /* Global low */ 2726 vrf_id = ALPM_VRF_ID_GLO(u); 2727 } else if (vrf_id < 0) { 2728 assert(0); 2729 } 2730 2731 if (ACB_HAS_PVT(acb, vrf_id)) { 2732 return rv; 2733 } 2734 2735 ipt = ALPM_LPM_IPT(u, lpm_cfg); 2736 pfx_trie = ALPM_VRF_TRIE(u, vrf_id, ipt); 2737 prefix = lpm_cfg->user_data; 2738 pfx_len = lpm_cfg->defip_sub_len; 2739 2740 if (pfx_len != 0) { 2741 rv = alpm_lib_trie_delete(pfx_trie, prefix, pfx_len, &lpmp); 2742 pfx_node = (_alpm_bkt_node_t *)lpmp; 2743 ALPM_IEG(rv); 2744 2745 /* Find the alternative best prefix match node */ 2746 lpmp = NULL; 2747 rv = alpm_lib_trie_find_lpm(pfx_trie, prefix, pfx_len, &lpmp); 2748 tmp_node = (_alpm_pfx_node_t *)lpmp; 2749 if (BCM_SUCCESS(rv)) { 2750 _alpm_bkt_node_t *t = (_alpm_bkt_node_t *)(tmp_node->bkt_ptr); 2751 if (t != NULL) { 2752 /* Means default route exists */ 2753 bpm_len = t->key_len; 2754 } else { 2755 /* This should happen only if the lpm is a default route */ 2756 bpm_len = 0; 2757 } 2758 2759 *alt_def_pfx = t; 2760 *alt_bpm_len = bpm_len; 2761 } else { 2762 /* Not expected */ 2763 ALPM_IEG(rv); 2764 } 2765 } else { 2766 /* Delete a default route */ 2767 lpmp = NULL; 2768 rv = alpm_lib_trie_find_lpm(pfx_trie, prefix, pfx_len, &lpmp); 2769 tmp_node = (_alpm_pfx_node_t *)lpmp; 2770 tmp_node->bkt_ptr = NULL; 2771 } 2772 2773 if (pfx_node != NULL) { 2774 alpm_util_free(pfx_node); 2775 } 2776 2777 return rv; 2778 2779 bad: 2780 /* Recover if necessary */ 2781 if (pfx_node != NULL) { 2782 rv2 = alpm_lib_trie_insert(pfx_trie, prefix, 2783 pfx_len, (alpm_lib_trie_node_t *)pfx_node); 2784 if (BCM_FAILURE(rv2)) { 2785 ALPM_ERR(("Recover failed\n")); 2786 } 2787 } 2788 return rv; 2789 } 2790 2791 static int 2792 alpm_vrf_pfx_trie_init(int u, int vrf_id, int ipt) 2793 { 2794 int rv = BCM_E_NONE; 2795 alpm_lib_trie_t *root = NULL; 2796 uint32 max_key_len; 2797 uint32 key[5] = {0}; 2798 _alpm_pfx_node_t *pfx_node = NULL; 2799 2800 max_key_len = alpm_util_trie_max_key_len(u, ipt); 2801 2802 ALPM_ALLOC_EG(pfx_node, sizeof(*pfx_node), "Payload for pfx trie key"); 2803 sal_memset(pfx_node, 0, sizeof(*pfx_node)); 2804 rv = alpm_lib_trie_init(max_key_len, &ALPM_VRF_TRIE(u, vrf_id, ipt)); 2805 if (BCM_SUCCESS(rv)) { 2806 root = ALPM_VRF_TRIE(u, vrf_id, ipt); 2807 rv = alpm_lib_trie_insert(root, key, 0, &(pfx_node->node)); 2808 } 2809 2810 if (BCM_FAILURE(rv)) { 2811 alpm_util_free(pfx_node); 2812 if (root != NULL) { 2813 alpm_lib_trie_destroy(root); 2814 ALPM_VRF_TRIE(u, vrf_id, ipt) = NULL; 2815 } 2816 } 2817 2818 bad: 2819 return rv; 2820 } 2821 2822 int 2823 alpm_vrf_pfx_trie_deinit(int u, int vrf_id, int ipt) 2824 { 2825 int rv = BCM_E_NONE; 2826 alpm_lib_trie_t *root = NULL; 2827 uint32 key[5] = {0}; 2828 _alpm_pfx_node_t *pfx_node = NULL; 2829 2830 root = ALPM_VRF_TRIE(u, vrf_id, ipt); 2831 if (root == NULL) { 2832 return rv; 2833 } 2834 rv = alpm_lib_trie_delete(root, key, 0, (alpm_lib_trie_node_t **)&pfx_node); 2835 if (BCM_SUCCESS(rv)) { 2836 alpm_util_free(pfx_node); 2837 ALPM_IER(alpm_lib_trie_destroy(root)); 2838 ALPM_VRF_TRIE(u, vrf_id, ipt) = NULL; 2839 } 2840 2841 return rv; 2842 } 2843 2844 int 2845 alpm_vrf_pvt_node_init(int u, _alpm_cb_t *acb, 2846 alpm_lib_trie_t *pvt_root, 2847 _bcm_defip_cfg_t *pvt_cfg, 2848 _alpm_pvt_node_t **pvt_node) 2849 { 2850 int rv = BCM_E_NONE; 2851 int vrf_id; 2852 int ipt; 2853 uint32 max_key_len; 2854 _alpm_pvt_node_t *tmp_node = NULL; 2855 2856 ipt = ALPM_LPM_IPT(u, pvt_cfg); 2857 vrf_id = ALPM_LPM_VRF_ID(u, pvt_cfg); 2858 2859 ALPM_ALLOC_EG(tmp_node, sizeof(_alpm_pvt_node_t), "pvt_node"); 2860 2861 /* kshift = 0 */ 2862 max_key_len = alpm_util_trie_max_key_len(u, ipt); 2863 ALPM_IEG(alpm_lib_trie_init(max_key_len, &PVT_BKT_TRIE(tmp_node))); 2864 if (pvt_cfg->bkt_info) { 2865 sal_memcpy(&PVT_BKT_INFO(tmp_node), pvt_cfg->bkt_info, sizeof(_alpm_bkt_info_t)); 2866 } 2867 PVT_BKT_VRF(tmp_node) = vrf_id; 2868 PVT_BKT_PKM(tmp_node) = ALPM_LPM_PKM(u, pvt_cfg); 2869 PVT_BKT_DEF(tmp_node) = NULL; 2870 PVT_BPM_LEN(tmp_node) = 0; 2871 PVT_KEY_LEN(tmp_node) = pvt_cfg->defip_sub_len; 2872 PVT_KEY_CPY(tmp_node, pvt_cfg->user_data); 2873 PVT_FLAGS(tmp_node) = pvt_cfg->defip_flags; 2874 2875 PVT_IDX(tmp_node) = pvt_cfg->defip_index; 2876 2877 *pvt_node = tmp_node; 2878 2879 return rv; 2880 2881 bad: 2882 if (tmp_node != NULL) { 2883 alpm_util_free(tmp_node); 2884 } 2885 2886 if (PVT_BKT_TRIE(tmp_node) != NULL) { 2887 alpm_lib_trie_destroy(PVT_BKT_TRIE(tmp_node)); 2888 PVT_BKT_TRIE(tmp_node) = NULL; 2889 } 2890 2891 return rv; 2892 } 2893 2894 static int 2895 alpm_vrf_pvt_node_delete(int u, _alpm_cb_t *acb, int vrf_id, int ipt, 2896 _bcm_defip_cfg_t *lpm_cfg) 2897 { 2898 int rv = BCM_E_NONE; 2899 _alpm_pvt_node_t *pvt_node = NULL; 2900 alpm_lib_trie_t *pvt_root = NULL; 2901 2902 pvt_root = ACB_PVT_TRIE(acb, vrf_id, ipt); 2903 if (pvt_root == NULL) { 2904 return rv; 2905 } 2906 rv = alpm_lib_trie_delete(pvt_root, lpm_cfg->user_data, lpm_cfg->defip_sub_len, 2907 (alpm_lib_trie_node_t **)&pvt_node); 2908 if (BCM_SUCCESS(rv)) { 2909 ALPM_IER(alpm_lib_trie_destroy(PVT_BKT_TRIE(pvt_node))); 2910 alpm_util_free(pvt_node); 2911 } 2912 2913 return rv; 2914 } 2915 2916 int 2917 alpm_vrf_pvt_trie_deinit(int u, _alpm_cb_t *acb, int vrf_id, int ipt, 2918 _bcm_defip_cfg_t *lpm_cfg) 2919 { 2920 int rv = BCM_E_NONE; 2921 2922 rv = alpm_vrf_pvt_node_delete(u, acb, vrf_id, ipt, lpm_cfg); 2923 if (BCM_SUCCESS(rv)) { 2924 ALPM_IER(alpm_lib_trie_destroy(ACB_PVT_TRIE(acb, vrf_id, ipt))); 2925 ACB_PVT_TRIE(acb, vrf_id, ipt) = NULL; 2926 } 2927 2928 return rv; 2929 } 2930 2931 static int 2932 alpm_cb_pvt_add(int u, _alpm_cb_t *acb, int vrf_id, int ipt, 2933 _bcm_defip_cfg_t *lpm_cfg) 2934 { 2935 int rv = BCM_E_NONE; 2936 int pvt_node_inited = 0, pvt_root_inited = 0; 2937 2938 uint32 max_key_len; 2939 alpm_lib_trie_t *pvt_root; 2940 _alpm_bkt_info_t bkt_info; 2941 _alpm_pvt_node_t *pvt_node = NULL; 2942 2943 pvt_root = ACB_PVT_TRIE(acb, vrf_id, ipt); 2944 if (pvt_root == NULL) { 2945 max_key_len = alpm_util_trie_max_key_len(u, ipt); 2946 ALPM_IEG(alpm_lib_trie_init(max_key_len, &ACB_PVT_TRIE(acb, vrf_id, ipt))); 2947 pvt_root = ACB_PVT_TRIE(acb, vrf_id, ipt); 2948 pvt_root_inited = 1; 2949 } 2950 ALPM_IEG(alpm_vrf_pvt_node_init(u, acb, pvt_root, lpm_cfg, &pvt_node)); 2951 pvt_node_inited = 1; 2952 if (!pvt_root_inited) { 2953 _alpm_pfx_node_t *pfx_node = NULL; 2954 alpm_lib_trie_t *pfx_trie = NULL; 2955 2956 pfx_trie = ALPM_VRF_TRIE(u, vrf_id, ipt); 2957 if (pfx_trie != NULL) { 2958 ALPM_IER(alpm_lib_trie_find_lpm(pfx_trie, pvt_node->key, pvt_node->key_len, 2959 (alpm_lib_trie_node_t **)&pfx_node)); 2960 PVT_BPM_LEN(pvt_node) = pfx_node->key_len; 2961 PVT_BKT_DEF(pvt_node) = pfx_node->bkt_ptr; 2962 } 2963 } 2964 2965 if (ACB_HAS_TCAM(acb)) { /* need for TCAM write */ 2966 lpm_cfg->pvt_node = (uint32 *)pvt_node; 2967 } 2968 2969 retry: 2970 sal_memset(&bkt_info, 0, sizeof(_alpm_bkt_info_t)); 2971 rv = alpm_bkt_alloc(u, acb, vrf_id, ipt, 1, &bkt_info, NULL); 2972 if (rv == BCM_E_BUSY) { 2973 ALPM_IEG_PRT_EXCEPT(alpm_bkt_alloc(u, acb, vrf_id, ipt, 1, &bkt_info, NULL), BCM_E_FULL); 2974 } 2975 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 2976 lpm_cfg->bkt_info = &bkt_info; 2977 sal_memcpy(&PVT_BKT_INFO(pvt_node), &bkt_info, sizeof(_alpm_bkt_info_t)); 2978 2979 rv = alpm_pvt_insert(u, acb, lpm_cfg); 2980 /* Upper level of BCM_E_BUSY point, 2981 * ACB_HAS_RTE may not be a good condition, but considering 2982 * it's only 3 levels so it also works. 2983 */ 2984 if (rv == BCM_E_BUSY && lpm_cfg->spl_pn && ACB_HAS_RTE(acb, vrf_id)) { 2985 ALPM_IEG(alpm_bkt_free(u, acb, vrf_id, ipt, &bkt_info)); 2986 sal_memset(&bkt_info, 0, sizeof(_alpm_bkt_info_t)); 2987 rv = alpm_bkt_alloc(u, acb, vrf_id, ipt, 2988 ACB_BNK_PER_BKT(acb, vrf_id), 2989 &bkt_info, NULL); 2990 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 2991 2992 /* Case 2.2.2, split given l3 pvt_node first */ 2993 rv = alpm_cb_split(u, acb, lpm_cfg, &bkt_info, 0xffff); 2994 2995 if (BCM_SUCCESS(rv)) { 2996 lpm_cfg->spl_pn = NULL; 2997 lpm_cfg->spl_key_len = 0; 2998 lpm_cfg->l1_pvt_node = NULL; 2999 /* PERF OPT point */ 3000 goto retry; 3001 } 3002 } 3003 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 3004 3005 PVT_IDX(pvt_node) = lpm_cfg->defip_index; 3006 lpm_cfg->pvt_node = (uint32 *)pvt_node; 3007 ALPM_IEG(alpm_lib_trie_insert(ACB_PVT_TRIE(acb, vrf_id, ipt), 3008 pvt_node->key, pvt_node->key_len, 3009 (void *)pvt_node)); 3010 3011 bad: 3012 if (BCM_FAILURE(rv)) { 3013 /* ALPMTBD rollback */ 3014 if (lpm_cfg->bkt_info != NULL) { 3015 (void)alpm_bkt_free(u, acb, vrf_id, ipt, &bkt_info); 3016 lpm_cfg->bkt_info = NULL; 3017 } 3018 3019 if (pvt_root_inited) { 3020 (void)alpm_vrf_pvt_trie_deinit(u, acb, vrf_id, ipt, lpm_cfg); 3021 } else if (pvt_node_inited) { 3022 (void)alpm_vrf_pvt_node_delete(u, acb, vrf_id, ipt, lpm_cfg); 3023 } 3024 } 3025 3026 return rv; 3027 3028 } 3029 3030 static void 3031 alpm_vrf_spl_len_calc(int u, _alpm_cb_t *acb, int vrf_id, uint8 db_type, 3032 uint32 *splen1, uint32 *splen2) 3033 { 3034 int idx, bpb; 3035 uint32 diff1[5] = {6, 5, 7, 6, 0}; 3036 uint32 diff2[5] = {2, 3, 3, 4, 0}; 3037 3038 bpb = ACB_BNK_PER_BKT(acb, vrf_id) > 4; 3039 3040 if (ACB_IDX(acb) > 0) { 3041 idx = bpb << 1 | db_type; 3042 } else { 3043 idx = 4; 3044 } 3045 *splen1 = diff1[idx]; 3046 *splen2 = diff2[idx]; 3047 3048 return; 3049 } 3050 3051 /* 3052 * alpm_vrf_init 3053 * Add a VRF default route when a L3 VRF is added 3054 * Adds a 0.0 entry into VRF 3055 */ 3056 static int 3057 alpm_vrf_init(int u, _alpm_cb_t *acb, int vrf_id, int ipt, uint8 db_type) 3058 { 3059 int rv = BCM_E_NONE; 3060 _bcm_defip_cfg_t pvt_cfg; 3061 3062 /* Need to set db_type at the beginning */ 3063 ACB_VRF_DB_TYPE_SET(u, acb, vrf_id, ipt, db_type); 3064 3065 sal_memset(&pvt_cfg, 0, sizeof(pvt_cfg)); 3066 pvt_cfg.defip_vrf = ALPM_VRF_ID_TO_VRF(u, vrf_id); 3067 pvt_cfg.defip_flags |= ALPM_IS_IPV6(ipt) ? BCM_L3_IP6 : 0; 3068 3069 if (ALPM_TCAM_ZONED(u)) { 3070 pvt_cfg.default_miss = 1; 3071 } 3072 3073 ALPM_IEG_PRT_EXCEPT(alpm_cb_pvt_add(u, acb, vrf_id, ipt, &pvt_cfg), BCM_E_FULL); 3074 3075 ACB_VRF_INIT_SET(u, acb, vrf_id, ipt); 3076 ACB_DR_INIT_CLEAR(u, acb, vrf_id, ipt); /* clear DR partially inited */ 3077 3078 alpm_vrf_spl_len_calc(u, acb, vrf_id, db_type, 3079 &ACB_VRF_SPLEN_DIFF1(u, acb, vrf_id, ipt), 3080 &ACB_VRF_SPLEN_DIFF2(u, acb, vrf_id, ipt)); 3081 3082 if (ACB_HAS_RTE(acb, vrf_id)) { 3083 rv = alpm_vrf_pfx_trie_init(u, vrf_id, ipt); 3084 } 3085 3086 bad: 3087 if (BCM_FAILURE(rv)) { 3088 /* ALPMTBD rollback */ 3089 if (pvt_cfg.bkt_info != NULL) { 3090 (void)alpm_bkt_free(u, acb, vrf_id, ipt, 3091 (_alpm_bkt_info_t *)pvt_cfg.bkt_info); 3092 } 3093 (void)alpm_vrf_pvt_trie_deinit(u, acb, vrf_id, ipt, &pvt_cfg); 3094 ACB_VRF_INIT_CLEAR(u, acb, vrf_id, ipt); 3095 } 3096 return rv; 3097 3098 } 3099 3100 /* 3101 * alpm_vrf_deinit 3102 * Delete the VRF default route when a L3 VRF is destroyed 3103 */ 3104 int 3105 alpm_vrf_deinit(int u, int vrf_id, int ipt) 3106 { 3107 int i, rv = BCM_E_NONE; 3108 _bcm_defip_cfg_t lpm_cfg; 3109 _alpm_pvt_node_t *pvt_node = NULL; 3110 _alpm_cb_t *acb; 3111 3112 sal_memset(&lpm_cfg, 0, sizeof(lpm_cfg)); 3113 lpm_cfg.defip_vrf = ALPM_VRF_ID_TO_VRF(u, vrf_id); 3114 if (ALPM_IS_IPV6(ipt)) { 3115 lpm_cfg.defip_flags |= BCM_L3_IP6; 3116 } 3117 if (ALPM_TCAM_ZONED(u)) { 3118 lpm_cfg.default_miss = 1; 3119 } 3120 3121 for (i = ACB_CNT(u) - 1; i >= 0; i--) { 3122 acb = ACB(u, i); 3123 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt)) { 3124 continue; 3125 } 3126 3127 ALPM_IER(alpm_pvt_find(u, acb, &lpm_cfg, &pvt_node)); 3128 /* Banks are already freed via _pfx_shrink */ 3129 /* add Entry into tcam as default routes for the VRF */ 3130 if (ACB_HAS_TCAM(acb)) { 3131 lpm_cfg.pvt_node = pvt_node; 3132 ALPM_IER(alpm_bkt_bnk_shrink(u, ipt, acb, 3133 ACB_BKT_VRF_POOL(acb, vrf_id), 3134 &PVT_BKT_INFO(pvt_node), NULL)); 3135 } else { 3136 lpm_cfg.pvt_node = NULL; 3137 } 3138 lpm_cfg.bkt_node = NULL; 3139 ALPM_IER(alpm_pvt_delete(u, acb, &lpm_cfg)); 3140 ALPM_IER(alpm_vrf_pvt_trie_deinit(u, acb, vrf_id, ipt, &lpm_cfg)); 3141 ACB_VRF_INIT_CLEAR(u, acb, vrf_id, ipt); 3142 } 3143 3144 rv = alpm_vrf_pfx_trie_deinit(u, vrf_id, ipt); 3145 3146 return rv; 3147 } 3148 3149 /* Check the bank usage against threshold for TH3 only when bnk_cnt > 8K */ 3150 static int 3151 alpm_cb_bnk_threshold_exceed(int u, _alpm_cb_t *acb, int vrf_id, int ipt) 3152 { 3153 _alpm_bkt_pool_conf_t *bp_conf = ACB_BKT_VRF_POOL(acb, vrf_id); 3154 3155 if (!ACB_BKT_FIXED_FMT(acb, 1) && 3156 ACB_HAS_RTE(acb, vrf_id) && 3157 (BPC_BNK_CNT(bp_conf) > 8192) && 3158 ((BPC_BNK_USED(bp_conf, ipt) * 100 / BPC_BNK_CNT(bp_conf)) > 3159 ALPMC(u)->_alpm_bnk_threshold)) { 3160 return TRUE; 3161 } 3162 3163 return FALSE; 3164 } 3165 3166 /* What is expected here when entering this function: 3167 * all occupied banks are continuous. 3168 * all i in {i | bkt_info->bnk_fmt[i] is used} are continuous AND 3169 * foreach i belongs to {i | bkt_info->bnk_fmt[i] is used}: 3170 * bkt_info->vet_bmp[i]!=0 3171 */ 3172 int 3173 alpm_cb_expand(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *pvt_node, int bnk_cnt, int *fmt_update) 3174 { 3175 int i, ipt, rv = BCM_E_FULL; 3176 _alpm_bkt_info_t *bkt_info; 3177 _alpm_bkt_pool_conf_t *bp_conf; 3178 int bnkpb, start, end; 3179 int leftnb, rightnb; 3180 int def_fmt; 3181 3182 ipt = PVT_BKT_IPT(pvt_node); 3183 def_fmt = alpm_util_bkt_def_fmt_get(u, acb, PVT_BKT_VRF(pvt_node), ipt); 3184 *fmt_update = FALSE; 3185 3186 ALPM_VERB(("Expanding ALPM CB %d bkt %d......\n", 3187 acb->acb_idx, PVT_BKT_IDX(pvt_node))); 3188 3189 /* There 4 cases when expanding a bucket */ 3190 /* Case 1: neighbour bank available 3191 * -> occupy neighbour bank */ 3192 /* 3193 0 1 2 3 4 5 6 7 3194 ----------------- 3195 |#|#|#|#|#| | | | 3196 ----------------- 3197 ^ 3198 rofs=0 3199 ----------------- 3200 | | |#|#|#|#| | | 3201 ----------------- 3202 ^ 3203 rofs=2 3204 ----------------- 3205 | | | |#|#|#|#|#| 3206 ----------------- 3207 ^ 3208 rofs=3 bkt+1 3209 ----------------- ----------------- 3210 | | | | | |#|#|#| |#|#| | | | | | | 3211 ----------------- ----------------- 3212 ^ 3213 rofs=5 3214 */ 3215 3216 /* There is a neighbour */ 3217 bkt_info = &PVT_BKT_INFO(pvt_node); 3218 bp_conf = ACB_BKT_VRF_POOL(acb, PVT_BKT_VRF(pvt_node)); 3219 bnkpb = BPC_BNK_PER_BKT(bp_conf); 3220 start = PVT_ROFS(pvt_node); 3221 end = PVT_ROFS(pvt_node) + bnkpb; 3222 3223 /* Get neighbour bank offset based on bkt-idx */ 3224 for (i = start; i < end; i++) { 3225 if (!BI_BNK_IS_USED(bkt_info, i % bnkpb)) { 3226 break; 3227 } 3228 } 3229 3230 leftnb = PVT_BKT_IDX(pvt_node) * bnkpb + start - 1; 3231 rightnb = PVT_BKT_IDX(pvt_node) * bnkpb + i; 3232 if (leftnb >= 0) { 3233 rv = alpm_bkt_bnk_chk_rsvd(u, ipt, bp_conf, leftnb); 3234 if (BCM_SUCCESS(rv)) { 3235 if (PVT_BKT_IDX(pvt_node) != (leftnb / bnkpb)) { 3236 /* Update */ 3237 PVT_BKT_IDX(pvt_node) = leftnb / bnkpb; 3238 } 3239 3240 PVT_ROFS(pvt_node) = leftnb % bnkpb; 3241 bkt_info->bnk_fmt[PVT_ROFS(pvt_node)] = def_fmt; 3242 *fmt_update = TRUE; 3243 goto end; 3244 } 3245 } 3246 3247 if (rightnb < BPC_BNK_CNT(bp_conf)) { 3248 rv = alpm_bkt_bnk_chk_rsvd(u, ipt, bp_conf, rightnb); 3249 if (BCM_SUCCESS(rv)) { 3250 bkt_info->bnk_fmt[rightnb % bnkpb] = def_fmt; 3251 *fmt_update = TRUE; 3252 goto end; 3253 } 3254 } 3255 3256 /* Case 2: No neighbour bank, but there are other 3257 * continuous banks available: 3258 * -> Move banks to other area */ 3259 start = 0; 3260 rv = alpm_bkt_bnk_alloc(u, ipt, bp_conf, &start, bnk_cnt+1, 1); 3261 if (BCM_SUCCESS(rv)) { 3262 _alpm_bkt_info_t dst_bkt; 3263 3264 sal_memset(&dst_bkt, 0, sizeof(dst_bkt)); 3265 BI_ROFS(&dst_bkt) = start % bnkpb; 3266 BI_BKT_IDX(&dst_bkt) = start / bnkpb; 3267 for (i = 0; i <= bnk_cnt; i++) { 3268 dst_bkt.bnk_fmt[(BI_ROFS(&dst_bkt) + i) % bnkpb] = def_fmt; 3269 } 3270 3271 /* Move banks */ 3272 rv = alpm_bkt_move(u, acb, pvt_node, bkt_info, &dst_bkt); 3273 goto end; 3274 } 3275 3276 /* Check bank usage threshold */ 3277 if (alpm_cb_bnk_threshold_exceed(u, acb, PVT_BKT_VRF(pvt_node), ipt)) { 3278 /* return E_RESOURCE in ALPM.expand to no split with unexpected 3279 bucket situation. It will change to E_FULL outside */ 3280 return BCM_E_RESOURCE; 3281 } 3282 3283 /* Case 3: No neighbour bank, no continuous banks available 3284 * -> move empty bank to neighbour bank */ 3285 /* ALPMTBD, can be optimized by using partial defragmentation to 3286 * create a free bucket then do Case 2. 3287 */ 3288 3289 /* Find nearest unused bit position */ 3290 if (leftnb >= 0 || rightnb < BPC_BNK_CNT(bp_conf)) { 3291 int nst_bnk = -1; 3292 rv = alpm_bkt_bnk_nearest_get(u, 3293 BPC_BNK_BMP(bp_conf, ipt), 3294 BPC_BNK_CNT(bp_conf), 3295 leftnb, rightnb, &nst_bnk); 3296 if (BCM_SUCCESS(rv)) { 3297 /* Move unused nst_bnk */ 3298 if (nst_bnk > rightnb) { 3299 /* Move nst_bnk to rightnb */ 3300 rv = alpm_bkt_free_bnk_move(u, acb, bp_conf, nst_bnk, rightnb); 3301 ALPM_IER(rv); 3302 /* Now rightnb is free */ 3303 rv = alpm_bkt_bnk_chk_rsvd(u, ipt, bp_conf, rightnb); 3304 if (BCM_SUCCESS(rv)) { 3305 bkt_info->bnk_fmt[rightnb % bnkpb] = def_fmt; 3306 *fmt_update = TRUE; 3307 goto end; 3308 } 3309 } else if (nst_bnk < leftnb) { 3310 /* Move nst_bnk to leftnb */ 3311 rv = alpm_bkt_free_bnk_move(u, acb, bp_conf, nst_bnk, leftnb); 3312 ALPM_IER(rv); 3313 /* Now leftnb is free */ 3314 rv = alpm_bkt_bnk_chk_rsvd(u, ipt, bp_conf, leftnb); 3315 if (BCM_SUCCESS(rv)) { 3316 if (PVT_BKT_IDX(pvt_node) != (leftnb / bnkpb)) { 3317 /* Update */ 3318 PVT_BKT_IDX(pvt_node) = leftnb / bnkpb; 3319 } 3320 PVT_ROFS(pvt_node) = leftnb % bnkpb; 3321 bkt_info->bnk_fmt[PVT_ROFS(pvt_node)] = def_fmt; 3322 3323 *fmt_update = TRUE; 3324 goto end; 3325 } 3326 } else { 3327 /* Shouldn't be here */ 3328 rv = BCM_E_FULL; 3329 } 3330 } 3331 } 3332 3333 /* Case 4: table full */ 3334 3335 end: 3336 if (BCM_SUCCESS(rv)) { 3337 if (ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_SANITY_NODE) { 3338 rv = alpm_cb_pvt_sanity_cb(u, acb, pvt_node, "Expand"); 3339 } 3340 acb->acb_cnt.c_expand++; 3341 } 3342 return rv; 3343 } 3344 3345 /* What is expected here when entering this function: 3346 * all occupied banks are continuous. 3347 * all i in {i | bkt_info->bnk_fmt[i] is used} are continuous AND 3348 * foreach i belongs to {i | bkt_info->bnk_fmt[i] is used}: 3349 * bkt_info->vet_bmp[i]!=0 3350 */ 3351 int 3352 alpm_cb_expand_in_bkt(int u, _alpm_cb_t *acb, 3353 _alpm_pvt_node_t *pvt_node, int bnk_cnt) 3354 { 3355 int i, rv = BCM_E_FULL; 3356 int bnkpb, end; 3357 _alpm_bkt_info_t *bkt_info; 3358 _alpm_bkt_pool_conf_t *bp_conf; 3359 _alpm_bkt_info_t dst_bkt; 3360 3361 ALPM_VERB(("Expanding ALPM CB %d bkt %d......\n", 3362 acb->acb_idx, PVT_BKT_IDX(pvt_node))); 3363 3364 /* Case 1: bank available in the same bucket 3365 * -> occupy the free bank */ 3366 3367 bkt_info = &PVT_BKT_INFO(pvt_node); 3368 bp_conf = ACB_BKT_VRF_POOL(acb, PVT_BKT_VRF(pvt_node)); 3369 bnkpb = BPC_BNK_PER_BKT(bp_conf); 3370 end = bnkpb; 3371 3372 /* Occupy the free bank in the same bucket based on bkt_idx */ 3373 for (i = 0; i < end; i++) { 3374 int glb_bnk; 3375 if (BI_BNK_IS_USED(bkt_info, i)) { 3376 continue; 3377 } 3378 3379 glb_bnk = PVT_BKT_IDX(pvt_node) * bnkpb + i; 3380 rv = alpm_bkt_sharing_bnk_alloc(u, acb, PVT_BKT_VRF(pvt_node), 3381 PVT_BKT_IPT(pvt_node), 3382 bp_conf, &dst_bkt, NULL, 3383 glb_bnk, 1, 0xfffffff); 3384 if (BCM_SUCCESS(rv)) { 3385 BI_ROFS(bkt_info) = 0; 3386 bkt_info->bnk_fmt[glb_bnk % bnkpb] = 3387 dst_bkt.bnk_fmt[glb_bnk % bnkpb]; 3388 goto end; 3389 } 3390 } 3391 3392 /* Case 2: No free bank in the same bucket, but there are other 3393 * continuous banks available: 3394 * -> Move banks to other area */ 3395 rv = alpm_bkt_sharing_bnk_alloc(u, acb, PVT_BKT_VRF(pvt_node), 3396 PVT_BKT_IPT(pvt_node), 3397 bp_conf, &dst_bkt, NULL, 3398 0, bnk_cnt+1, bnkpb); 3399 if (BCM_SUCCESS(rv)) { 3400 /* Move banks */ 3401 rv = alpm_bkt_move(u, acb, pvt_node, bkt_info, &dst_bkt); 3402 goto end; 3403 } 3404 3405 /* Other case: table full */ 3406 3407 end: 3408 if (BCM_SUCCESS(rv)) { 3409 if (ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_SANITY_NODE) { 3410 rv = alpm_cb_pvt_sanity_cb(u, acb, pvt_node, "Expand"); 3411 } 3412 acb->acb_cnt.c_expand++; 3413 } else if (rv == BCM_E_NOT_FOUND) { 3414 rv = BCM_E_FULL; 3415 } 3416 return rv; 3417 } 3418 3419 int 3420 alpm_cb_defrag(int u, _alpm_cb_t *acb, int vrf_id, int ipt) 3421 { 3422 int rv = BCM_E_NONE; 3423 int i, j, bnkpb; 3424 int rngl, rngr, rngm; 3425 _alpm_bkt_pool_conf_t *bp_conf; 3426 SHR_BITDCL *bnk_bmp; 3427 3428 bp_conf = ACB_BKT_VRF_POOL(acb, vrf_id); 3429 bnkpb = BPC_BNK_PER_BKT(bp_conf); 3430 3431 if (BPC_BNK_CNT(bp_conf) - BPC_BNK_USED(bp_conf, ipt) < bnkpb) { 3432 return BCM_E_FULL; 3433 } 3434 3435 /* Check bank usage threshold */ 3436 if (alpm_cb_bnk_threshold_exceed(u, acb, vrf_id, ipt)) { 3437 return BCM_E_FULL; 3438 } 3439 3440 /* Find best zone for defragmentation */ 3441 bnk_bmp = BPC_BNK_BMP(bp_conf, ipt); 3442 rv = alpm_bkt_free_bnk_range_get(u, 3443 bnk_bmp, BPC_BNK_CNT(bp_conf), 3444 bnkpb, &rngl, &rngr, &rngm); 3445 3446 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 3447 3448 if (ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_DEFRAG) { 3449 cli_out("free range get: bpb %d, range left %d, right %d, mid %d\n", 3450 bnkpb, rngl, rngr, rngm); 3451 alpm_util_bnk_range_print(u, bnk_bmp, 0xfffffff, 32, rngl, rngr); 3452 } 3453 3454 /* 3455 --------------------------- 3456 | |#|#| | | | |#|#|#| | | | 3457 --------------------------- 3458 ^ ^ ^ 3459 rngl rngm rngr 3460 3461 --------------------------- 3462 | |#| |#| |#| |#| |#| |#| | 3463 --------------------------- 3464 ^ ^ ^ 3465 rngl rngm rngr 3466 */ 3467 for (i = rngm - 1; i > rngl; i--) { 3468 if (!SHR_BITGET(bnk_bmp, i)) { 3469 continue; 3470 } 3471 for (j = i - 1; j >= rngl; j--) { 3472 if (SHR_BITGET(bnk_bmp, j)) { 3473 continue; 3474 } 3475 3476 /* bnk_bmp could be changed here */ 3477 rv = alpm_bkt_free_bnk_move(u, acb, bp_conf, j, i); 3478 ALPM_IEG(rv); 3479 break; 3480 } 3481 } 3482 3483 for (i = rngm + 1; i < rngr; i++) { 3484 if (!SHR_BITGET(bnk_bmp, i)) { 3485 continue; 3486 } 3487 for (j = i + 1; j <= rngr; j++) { 3488 if (SHR_BITGET(bnk_bmp, j)) { 3489 continue; 3490 } 3491 3492 /* bnk_bmp could be changed here */ 3493 rv = alpm_bkt_free_bnk_move(u, acb, bp_conf, j, i); 3494 ALPM_IEG(rv); 3495 break; 3496 } 3497 } 3498 3499 if (ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_DEFRAG) { 3500 cli_out("After Defrag: \n"); 3501 alpm_util_bnk_range_print(u, bnk_bmp, 0xfffffff, 32, 3502 rngl, rngr); 3503 } 3504 3505 acb->acb_cnt.c_defrag++; 3506 3507 bad: 3508 return rv; 3509 } 3510 3511 static int 3512 alpm_cb_split(int u, _alpm_cb_t *acb, _bcm_defip_cfg_t *lpm_cfg, 3513 _alpm_bkt_info_t *nbkt_info, int max_spl_cnt) 3514 { 3515 int rv = BCM_E_NONE; 3516 int max_key_len, ipt; 3517 int bkt_allocated = 0; 3518 int vrf_id = 0; 3519 int shrink_empty_only = 2; 3520 3521 uint32 *bak_idx = NULL; 3522 3523 alpm_lib_trie_t *nbkt_trie = NULL; 3524 3525 _alpm_bkt_pfx_arr_t *pfx_arr = NULL; 3526 _alpm_pvt_node_t *opvt_node = NULL; 3527 _alpm_pvt_node_t *npvt_node = NULL; 3528 _bcm_defip_cfg_t pvt_lpm_cfg; 3529 _alpm_tcam_write_t *tcam_write = lpm_cfg->tcam_write; 3530 3531 ipt = ALPM_LPM_IPT(u, lpm_cfg); 3532 vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 3533 3534 max_key_len = alpm_util_trie_max_key_len(u, ipt); 3535 /* 1. alpm_lib_trie_split to get split-prefix set 3536 * Allocate a new bucket based on the split prefixes 3537 * min_sz, in TH-style-ALPM devices, it's entry count, 3538 * in FMT-enabled deivces, it's bank count */ 3539 rv = alpm_bkt_trie_split(u, acb, lpm_cfg, &nbkt_trie, &npvt_node, 3540 max_key_len, &max_spl_cnt); 3541 ALPM_IEG(rv); 3542 3543 if (max_spl_cnt < 0xffff && !ACB_BKT_FIXED_FMT(acb, 1)) { 3544 rv = alpm_bkt_free(u, acb, vrf_id, ipt, nbkt_info); 3545 ALPM_IEG(rv); 3546 sal_memset(nbkt_info, 0, sizeof(_alpm_bkt_info_t)); 3547 nbkt_info->reverse = 1; 3548 rv = alpm_bkt_alloc(u, acb, vrf_id, ipt, ACB_BNK_PER_BKT(acb, vrf_id), 3549 nbkt_info, NULL); 3550 /* Should not see error here */ 3551 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 3552 } 3553 3554 /* 3. HW: Copy split prefixes from old bucket to new bucket */ 3555 sal_memcpy(&PVT_BKT_INFO(npvt_node), nbkt_info, sizeof(_alpm_bkt_info_t)); 3556 bkt_allocated = TRUE; 3557 3558 ALPM_ALLOC_EG(pfx_arr, sizeof(*pfx_arr), "pfx_arr"); 3559 rv = alpm_lib_trie_traverse(nbkt_trie, alpm_trie_pfx_cb, pfx_arr, 3560 trieTraverseOrderIn); 3561 ALPM_IEG(rv); 3562 3563 /* for !FIXED_FMT: 3564 * Need to sort pfx_arr here, node with longer prefix length comes first, 3565 * Should let longer bkt node to choose bkt_ent_get first 3566 */ 3567 if (!ACB_BKT_FIXED_FMT(acb, 1)) { 3568 _shr_sort(pfx_arr->pfx, pfx_arr->pfx_cnt, sizeof(_alpm_bkt_node_t *), 3569 alpm_util_pfx_len_cmp); 3570 } 3571 3572 /* 3. Save old ent_idx of prefixes for recovery */ 3573 rv = alpm_bkt_pfx_idx_backup(u, pfx_arr, &bak_idx); 3574 ALPM_IEG(rv); 3575 3576 if (lpm_cfg->spl_pn != NULL) { 3577 opvt_node = (_alpm_pvt_node_t *)lpm_cfg->spl_pn; 3578 } else { 3579 opvt_node = ACB_HAS_TCAM(acb) ? lpm_cfg->l1_pvt_node : lpm_cfg->pvt_node; 3580 } 3581 3582 /* bkt_pfx_copy updates ent_idx of each prefix in the new trie */ 3583 rv = alpm_bkt_pfx_copy(u, acb, pfx_arr, opvt_node, npvt_node); 3584 ALPM_IEG(rv); 3585 3586 /* Free unused banks of new pivot to Global bank pool */ 3587 rv = alpm_bkt_bnk_shrink(u, ipt, acb, ACB_BKT_VRF_POOL(acb, vrf_id), 3588 &PVT_BKT_INFO(npvt_node), NULL); 3589 ALPM_IEG(rv); 3590 3591 if (!ACB_BKT_FIXED_FMT(acb, 1) && ACB_HAS_TCAM(acb)) { 3592 /* Check if an extra split is required */ 3593 rv = alpm_bkt_ent_get(u, vrf_id, acb, npvt_node, lpm_cfg->defip_sub_len, NULL, NULL, 1); 3594 if (rv == BCM_E_FULL) { 3595 int rsvd = (ipt == ALPM_IPT_V6) ? 1 : 0; 3596 /* Cannot affort another split, so should return here */ 3597 if (bcm_esw_alpm_tcam_avail(u, vrf_id, ipt, PVT_KEY_LEN(npvt_node), 0) <= rsvd) { 3598 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 3599 } 3600 } 3601 } 3602 3603 /* 4. HW: insert new pivot 3604 * recursion happens here: BCM_E_FULL is expected 3605 */ 3606 sal_memcpy(&pvt_lpm_cfg, lpm_cfg, sizeof(pvt_lpm_cfg)); 3607 /* never insert new pvt with HIT=1 (from original lpm_cfg->defip_flags) */ 3608 pvt_lpm_cfg.defip_flags &= ~BCM_L3_HIT; 3609 if (ACB_HAS_TCAM(acb)) { 3610 pvt_lpm_cfg.pvt_node = (uint32 *)npvt_node; 3611 pvt_lpm_cfg.bkt_info = NULL; 3612 } else { 3613 pvt_lpm_cfg.l1_pvt_node = NULL; 3614 pvt_lpm_cfg.pvt_node = NULL; 3615 pvt_lpm_cfg.spl_pn = NULL; 3616 pvt_lpm_cfg.spl_opn = opvt_node; 3617 pvt_lpm_cfg.spl_npn = npvt_node; 3618 pvt_lpm_cfg.bkt_info = (uint32 *)&PVT_BKT_INFO(npvt_node); 3619 if (ACB_BKT_FIXED_FMT(acb, 1)) { 3620 pvt_lpm_cfg.bkt_kshift = 0; 3621 } else { 3622 /* for upr acb bkt */ 3623 pvt_lpm_cfg.bkt_kshift = PVT_KEY_LEN(npvt_node); 3624 } 3625 } 3626 pvt_lpm_cfg.bkt_node = NULL; 3627 3628 /* pvt_lpm_cfg.tcam_write has same pointer as lpm_cfg->tcam_write */ 3629 rv = alpm_bkt_split_pvt_add(u, acb, &pvt_lpm_cfg, npvt_node); 3630 /* rv = *_E_FULL is allowed here */ 3631 if (rv == BCM_E_FULL) { 3632 ALPM_INFO(("**ACB(%d).BKT.SPLIT return Full\n", ACB_IDX(acb))); 3633 } else if (rv == BCM_E_BUSY) { 3634 lpm_cfg->spl_pn = pvt_lpm_cfg.spl_pn; 3635 sal_memcpy(lpm_cfg->spl_key, pvt_lpm_cfg.spl_key, sizeof(lpm_cfg->spl_key)); 3636 lpm_cfg->spl_key_len = pvt_lpm_cfg.spl_key_len; 3637 } 3638 3639 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 3640 3641 /* Case of add new L1 pvt during L2 bkt split: 3642 - If new L2 bkt belongs to new L1 pvt, add new L2 bkt first. 3643 - Then write returned lpm_cfg->tcam_write to TCAM HW */ 3644 if (tcam_write != NULL) { 3645 rv = alpm_bkt_add_to_npvt(u, acb, lpm_cfg, npvt_node); 3646 if (tcam_write->hw_idx >= 0) { 3647 int rv1; 3648 rv1 = _tcam_entry_write(u, ALPM_LPM_PKM(u, lpm_cfg), tcam_write->ent, 3649 tcam_write->hw_idx, tcam_write->hw_idx); 3650 ALPM_INFO(("Write to TCAM HW at hw_idx %d after add new L2 bkt\n", 3651 tcam_write->hw_idx)); 3652 ALPM_IEG(rv1); 3653 } 3654 /* check returned rv after _tcam_entry_write done */ 3655 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 3656 } 3657 3658 /* 3659 * In case of pivot insert failure, we need to : 3660 * a). recover split_trie 3661 * b). Invalidate new bucket. 3662 */ 3663 3664 /* 5. HW: Invalidate split prefixes in the old bucket */ 3665 rv = alpm_bkt_pfx_clean(u, acb, opvt_node, pfx_arr->pfx_cnt, bak_idx); 3666 ALPM_IEG(rv); 3667 3668 /* 6. SW: Shrink old bucket, 3669 * A important step to make sure banks are continuously occupied by pivot 3670 */ 3671 rv = alpm_bkt_pfx_shrink(u, acb, opvt_node, &shrink_empty_only); 3672 ALPM_IEG(rv); 3673 3674 /* 7. SW: release temporary resources */ 3675 alpm_util_free(bak_idx); 3676 alpm_util_free(pfx_arr); 3677 3678 if (ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_SANITY_NODE) { 3679 rv = alpm_cb_pvt_sanity_cb(u, acb, opvt_node, "SplitOpvt"); 3680 if (BCM_SUCCESS(rv)) { 3681 rv = alpm_cb_pvt_sanity_cb(u, acb, npvt_node, "SplitNpvt"); 3682 } 3683 } 3684 3685 if ((PVT_KEY_LEN(opvt_node) != 0 && 3686 PVT_BKT_TRIE(opvt_node)->trie == NULL)) { 3687 alpm_lib_trie_node_t *tn = NULL; 3688 rv = alpm_pvt_delete_by_pvt_node(u, acb, opvt_node); 3689 if (BCM_FAILURE(rv)) { 3690 ALPM_ERR(("alpm_pvt_delete_by_pvt_node(trie==NULL) failure\n")); 3691 } 3692 rv = alpm_lib_trie_delete(ACB_PVT_TRIE(acb, vrf_id, ipt), opvt_node->key, 3693 PVT_KEY_LEN(opvt_node), &tn); 3694 if (BCM_FAILURE(rv)) { 3695 ALPM_ERR(("Trie delete node failure\n")); 3696 } 3697 (void)alpm_lib_trie_destroy(PVT_BKT_TRIE(opvt_node)); 3698 alpm_util_free(tn); 3699 3700 /* Set lpm_cfg the corresponding opvt_node pointer to NULL */ 3701 if (lpm_cfg->spl_pn == opvt_node) { 3702 lpm_cfg->spl_pn = NULL; 3703 } 3704 if (lpm_cfg->l1_pvt_node == opvt_node) { 3705 lpm_cfg->l1_pvt_node = NULL; 3706 } 3707 if (lpm_cfg->pvt_node == opvt_node) { 3708 lpm_cfg->pvt_node = NULL; 3709 } 3710 } 3711 3712 acb->acb_cnt.c_split++; 3713 if (BCM_SUCCESS(rv)) { 3714 ALPM_MERGE_STATE_CHANGED(u, vrf_id); 3715 } 3716 3717 return rv; 3718 3719 bad: 3720 /* Clean new bucket */ 3721 if (bak_idx != NULL) { 3722 alpm_bkt_pfx_idx_restore(u, pfx_arr, bak_idx); 3723 (void)alpm_bkt_pfx_clean(u, acb, npvt_node, pfx_arr->pfx_cnt, bak_idx); 3724 alpm_util_free(bak_idx); 3725 } 3726 3727 if (pfx_arr != NULL) { 3728 alpm_util_free(pfx_arr); 3729 } 3730 3731 /* free allocated bucket */ 3732 if (bkt_allocated) { 3733 sal_memcpy(nbkt_info, &PVT_BKT_INFO(npvt_node), sizeof(_alpm_bkt_info_t)); 3734 } 3735 (void)alpm_bkt_free(u, acb, vrf_id, ipt, nbkt_info); 3736 3737 if (nbkt_trie != NULL) { 3738 if (nbkt_trie->trie != NULL) { 3739 (void)alpm_lib_trie_merge(PVT_BKT_TRIE(opvt_node), nbkt_trie->trie, 3740 npvt_node->key, PVT_KEY_LEN(npvt_node)); 3741 } 3742 3743 alpm_lib_trie_destroy(nbkt_trie); 3744 } 3745 3746 if (npvt_node != NULL) { 3747 alpm_util_free(npvt_node); 3748 } 3749 3750 return rv; 3751 } 3752 3753 static int 3754 alpm_cb_merge_pvt(int u, _alpm_cb_t *acb, _alpm_pvt_node_t *src_pvt, 3755 _alpm_pvt_node_t *dst_pvt, int merge_dir) 3756 { 3757 int rv = BCM_E_NONE; 3758 int i, bnk_pbk; 3759 int ipt, vrf_id; 3760 uint32 *bak_idx = NULL; 3761 3762 int step_trie_merged = 0; 3763 3764 SHR_BITDCL *bnk_bmp; 3765 alpm_lib_trie_node_t *tn = NULL; 3766 _alpm_pvt_node_t *prt_pvt, *chd_pvt, *tmp_pvt; 3767 _alpm_bkt_info_t tmp_bi; 3768 _alpm_bkt_pool_conf_t *bp_conf; 3769 _alpm_bkt_pfx_arr_t *pfx_arr = NULL; 3770 3771 ipt = PVT_BKT_IPT(src_pvt); 3772 vrf_id = PVT_BKT_VRF(src_pvt); 3773 bp_conf = ACB_BKT_VRF_POOL(acb, vrf_id); 3774 bnk_pbk = BPC_BNK_PER_BKT(bp_conf); 3775 bnk_bmp = BPC_BNK_BMP(bp_conf, ipt); 3776 3777 /* 1. Expand the bkt of dst_pvt */ 3778 for (i = PVT_BKT_IDX(dst_pvt) * bnk_pbk; 3779 i < (PVT_BKT_IDX(dst_pvt) + 1) * bnk_pbk; i++) { 3780 if (SHR_BITGET(bnk_bmp, i)) { 3781 continue; 3782 } 3783 3784 PVT_BKT_INFO(dst_pvt).bnk_fmt[i % bnk_pbk] = 3785 alpm_util_bkt_def_fmt_get(u, acb, vrf_id, ipt); 3786 SHR_BITSET(bnk_bmp, i); 3787 BPC_BNK_USED(bp_conf, ipt) += 1; 3788 } 3789 3790 /* 2. Copy pfx from src_pvt to dst_pvt */ 3791 ALPM_ALLOC_EG(pfx_arr, sizeof(*pfx_arr), "pfx_arr"); 3792 rv = alpm_lib_trie_traverse(PVT_BKT_TRIE(src_pvt), alpm_trie_pfx_cb, pfx_arr, 3793 trieTraverseOrderIn); 3794 ALPM_IEG(rv); 3795 rv = alpm_bkt_pfx_idx_backup(u, pfx_arr, &bak_idx); 3796 ALPM_IEG(rv); 3797 rv = alpm_bkt_pfx_copy(u, acb, pfx_arr, src_pvt, dst_pvt); 3798 ALPM_IEG(rv); 3799 3800 if (merge_dir == ACB_MERGE_PARENT_TO_CHILD) { 3801 prt_pvt = src_pvt; 3802 chd_pvt = dst_pvt; 3803 } else { 3804 prt_pvt = dst_pvt; 3805 chd_pvt = src_pvt; 3806 } 3807 3808 /* 3. Merge trie */ 3809 rv = alpm_lib_trie_merge(PVT_BKT_TRIE(prt_pvt), PVT_BKT_TRIE(chd_pvt)->trie, 3810 chd_pvt->key, chd_pvt->key_len); 3811 ALPM_IEG(rv); 3812 step_trie_merged = 1; 3813 3814 if (merge_dir == ACB_MERGE_PARENT_TO_CHILD) { 3815 /* 4. Update pvt bkt_ptr if copy from parent to child */ 3816 sal_memcpy(&tmp_bi, &PVT_BKT_INFO(prt_pvt), sizeof(_alpm_bkt_info_t)); 3817 sal_memcpy(&PVT_BKT_INFO(prt_pvt), &PVT_BKT_INFO(chd_pvt), 3818 sizeof(_alpm_bkt_info_t)); 3819 rv = alpm_pvt_update_by_pvt_node(u, acb, prt_pvt, ALPM_PVT_UPDATE_ALPM_DATA); 3820 if (BCM_FAILURE(rv)) { 3821 /* Not expecting delete failure here */ 3822 ALPM_ERR(("cb_merge pvt update failed, rv=%d\n", rv)); 3823 } 3824 /* Recovery bkt info for invalidation */ 3825 sal_memcpy(&PVT_BKT_INFO(prt_pvt), &tmp_bi, sizeof(_alpm_bkt_info_t)); 3826 } 3827 3828 /* 5. Invalid old entries 3829 * Not expecting failures on invalidation */ 3830 rv = alpm_bkt_pfx_clean(u, acb, src_pvt, pfx_arr->pfx_cnt, bak_idx); 3831 ALPM_IEG(rv); 3832 rv = alpm_bkt_bnk_shrink(u, ipt, acb, ACB_BKT_VRF_POOL(acb, vrf_id), 3833 &PVT_BKT_INFO(src_pvt), NULL); 3834 ALPM_IEG(rv); 3835 rv = alpm_bkt_bnk_shrink(u, ipt, acb, ACB_BKT_VRF_POOL(acb, vrf_id), 3836 &PVT_BKT_INFO(dst_pvt), NULL); 3837 ALPM_IEG(rv); 3838 3839 /* 6. Delete child pvt entry from pvt table */ 3840 rv = alpm_pvt_delete_by_pvt_node(u, acb, chd_pvt); 3841 if (BCM_FAILURE(rv)) { 3842 /* Not expecting delete failure here */ 3843 ALPM_ERR(("cb_merge pvt delete failed, rv=%d\n", rv)); 3844 } 3845 3846 /* 7. Destroy child pvt from trie, tn is chd_pvt */ 3847 rv = alpm_lib_trie_delete(ACB_PVT_TRIE(acb, vrf_id, ipt), chd_pvt->key, 3848 PVT_KEY_LEN(chd_pvt), &tn); 3849 if (BCM_FAILURE(rv)) { 3850 /* Not expecting delete failure here */ 3851 ALPM_ERR(("cb_merge alpm_lib_trie_delete failed, rv=%d\n", rv)); 3852 } 3853 /* Should copy bi before alpm_lib_trie_destroy tn */ 3854 if (merge_dir == ACB_MERGE_PARENT_TO_CHILD) { 3855 int tab_idx, bnk; 3856 _alpm_bkt_info_t *bi; 3857 bi = &PVT_BKT_INFO(prt_pvt); 3858 sal_memcpy(bi, &PVT_BKT_INFO(chd_pvt), sizeof(_alpm_bkt_info_t)); 3859 3860 /* Update pvt_ptr for child bucket */ 3861 for (bnk = 0; bnk < bnk_pbk; bnk++) { 3862 if (BI_BNK_IS_USED(bi, bnk)) { 3863 tab_idx = ALPM_TAB_IDX_GET_BI_BNK(acb, bi, bnk); 3864 bp_conf->pvt_ptr[tab_idx] = prt_pvt; 3865 } 3866 } 3867 } 3868 3869 tmp_pvt = (_alpm_pvt_node_t *)tn; 3870 alpm_lib_trie_destroy(PVT_BKT_TRIE(tmp_pvt)); 3871 alpm_util_free(tmp_pvt); 3872 alpm_util_free(bak_idx); 3873 alpm_util_free(pfx_arr); 3874 3875 return rv; 3876 3877 bad: 3878 if (step_trie_merged) { 3879 uint32 pvt[5], len; 3880 alpm_lib_trie_split2(PVT_BKT_TRIE(prt_pvt), chd_pvt->key, 3881 chd_pvt->key_len, pvt, &len, 3882 &(PVT_BKT_TRIE(chd_pvt)->trie), 3883 PVT_BKT_TRIE(chd_pvt)->trie->count, 1); 3884 } 3885 3886 /* Clean new bucket */ 3887 if (bak_idx != NULL) { 3888 alpm_bkt_pfx_idx_restore(u, pfx_arr, bak_idx); 3889 (void)alpm_bkt_pfx_clean(u, acb, dst_pvt, pfx_arr->pfx_cnt, bak_idx); 3890 alpm_util_free(bak_idx); 3891 } 3892 3893 if (pfx_arr != NULL) { 3894 alpm_util_free(pfx_arr); 3895 } 3896 return rv; 3897 } 3898 3899 static int 3900 alpm_cb_merge_cb(alpm_lib_trie_node_t *ptrie, alpm_lib_trie_node_t *trie, 3901 alpm_lib_trie_traverse_state_t *state, void *info) 3902 { 3903 int u, rv; 3904 int bnkpb, entpb; 3905 int vrf_id; 3906 _alpm_cb_t *acb; 3907 _alpm_pvt_node_t *prt_pvt, *chd_pvt, *src_pvt, *dst_pvt; 3908 _alpm_cb_merge_ctrl_t *merge_ctrl; 3909 _alpm_cb_merge_type_t merge_dir = ACB_MERGE_INVALID; 3910 3911 prt_pvt = (_alpm_pvt_node_t *)ptrie; 3912 chd_pvt = (_alpm_pvt_node_t *)trie; 3913 if (!prt_pvt) { 3914 return BCM_E_NONE; 3915 } 3916 3917 if (PVT_BKT_TRIE(prt_pvt)->trie == NULL) { 3918 merge_dir = ACB_MERGE_PARENT_TO_CHILD; 3919 } 3920 3921 if (PVT_BKT_TRIE(chd_pvt)->trie == NULL) { 3922 merge_dir = ACB_MERGE_CHILD_TO_PARENT; 3923 } 3924 3925 merge_ctrl = (_alpm_cb_merge_ctrl_t *)info; 3926 u = merge_ctrl->unit; 3927 acb = merge_ctrl->acb; 3928 vrf_id = merge_ctrl->vrf_id; 3929 bnkpb = merge_ctrl->bnk_pbkt; 3930 entpb = merge_ctrl->ent_pbnk; 3931 3932 if (merge_dir == ACB_MERGE_INVALID) { 3933 int mrts, prt_bnks, chd_bnks; 3934 3935 mrts = PVT_BKT_TRIE(prt_pvt)->trie->count + 3936 PVT_BKT_TRIE(chd_pvt)->trie->count; 3937 if (mrts > bnkpb * entpb) { 3938 return BCM_E_NONE; 3939 } 3940 3941 prt_bnks = bnkpb - alpm_util_bkt_token_bnks(u, acb, vrf_id, prt_pvt); 3942 chd_bnks = bnkpb - alpm_util_bkt_token_bnks(u, acb, vrf_id, chd_pvt); 3943 3944 if (mrts <= prt_bnks * entpb) { 3945 merge_dir = ACB_MERGE_CHILD_TO_PARENT; 3946 } else if (mrts <= chd_bnks * entpb) { 3947 merge_dir = ACB_MERGE_PARENT_TO_CHILD; 3948 } else { 3949 return BCM_E_NONE; 3950 } 3951 } 3952 3953 if (merge_dir == ACB_MERGE_PARENT_TO_CHILD) { 3954 src_pvt = prt_pvt; 3955 dst_pvt = chd_pvt; 3956 } else { 3957 src_pvt = chd_pvt; 3958 dst_pvt = prt_pvt; 3959 } 3960 3961 rv = alpm_cb_merge_pvt(u, acb, src_pvt, dst_pvt, merge_dir); 3962 3963 if (BCM_FAILURE(rv)) { 3964 ALPM_ERR(("alpm merge failed rv %d\n", rv)); 3965 return rv; 3966 } 3967 3968 *state = trieTraverseStateDel; 3969 if (++merge_ctrl->merge_count >= ACB_MERGE_THRESHOLD) { 3970 *state = trieTraverseStateDone; 3971 } 3972 3973 acb->acb_cnt.c_merge++; 3974 3975 return BCM_E_NONE; 3976 3977 } 3978 3979 int 3980 alpm_cb_merge(int u, _alpm_cb_t *acb, int vrf_id, int ipt) 3981 { 3982 int rv = BCM_E_NONE; 3983 uint8 fmt; 3984 alpm_lib_trie_t *pvt_trie; 3985 _alpm_cb_merge_ctrl_t merge_ctrl; 3986 3987 pvt_trie = ACB_PVT_TRIE(acb, vrf_id, ipt); 3988 if (!ALPM_MERGE_REQD(u, vrf_id) || 3989 pvt_trie == NULL || 3990 pvt_trie->trie == NULL) { 3991 return BCM_E_FULL; 3992 } 3993 3994 sal_memset(&merge_ctrl, 0, sizeof(merge_ctrl)); 3995 merge_ctrl.unit = u; 3996 merge_ctrl.ipt = ipt; 3997 merge_ctrl.vrf_id = vrf_id; 3998 merge_ctrl.acb = acb; 3999 4000 fmt = alpm_util_bkt_def_fmt_get(u, acb, vrf_id, ipt); 4001 merge_ctrl.bnk_pbkt = ACB_BNK_PER_BKT(acb, vrf_id); 4002 merge_ctrl.ent_pbnk = ACB_FMT_ENT_MAX(acb, vrf_id, fmt); 4003 4004 rv = alpm_lib_trie_traverse2(pvt_trie, alpm_cb_merge_cb, &merge_ctrl, 4005 trieTraverseOrderPost); 4006 4007 if (BCM_FAILURE(rv)) { 4008 ALPM_ERR(("Logic bucket merge failed, ipt %d vrf_id %d rv %d.\n", 4009 ipt, vrf_id, rv)); 4010 } 4011 4012 if (merge_ctrl.merge_count == 0) { 4013 ALPM_MERGE_STATE_CHKED(u, vrf_id); 4014 rv = BCM_E_FULL; 4015 } 4016 4017 return rv; 4018 } 4019 4020 int 4021 alpm_cb_delete(int u, _alpm_cb_t *acb, _bcm_defip_cfg_t *lpm_cfg) 4022 { 4023 int rv = BCM_E_NONE; 4024 int ipt, vrf_id, pfx_len; 4025 int bkt_empty; 4026 uint32 *prefix; 4027 int shrink_empty_only = 1; 4028 4029 _alpm_ppg_data_t ppg_data; 4030 _alpm_pvt_node_t *pvt_node; 4031 _alpm_bkt_node_t *bkt_node = NULL; 4032 _alpm_bkt_node_t *alt_def_pfx = NULL; 4033 uint32 alt_bmp_len = 0; 4034 4035 alpm_lib_trie_t *bkt_trie = NULL; 4036 alpm_lib_trie_node_t *tn = NULL; 4037 4038 ipt = ALPM_LPM_IPT(u, lpm_cfg); 4039 vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 4040 prefix = lpm_cfg->user_data; 4041 pfx_len = lpm_cfg->defip_sub_len; 4042 4043 /* Check Init */ 4044 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt)) { 4045 return BCM_E_PARAM; 4046 } 4047 4048 pvt_node = ACB_HAS_TCAM(acb) ? lpm_cfg->l1_pvt_node : lpm_cfg->pvt_node; 4049 if (pvt_node == NULL) { 4050 ALPM_IEG(alpm_pvt_find(u, acb, lpm_cfg, &pvt_node)); 4051 } 4052 4053 bkt_trie = PVT_BKT_TRIE(pvt_node); 4054 rv = alpm_lib_trie_delete(bkt_trie, prefix, pfx_len, &tn); 4055 ALPM_IEG(rv); 4056 bkt_node = (_alpm_bkt_node_t *)tn; 4057 4058 rv = alpm_vrf_pfx_trie_delete(u, acb, lpm_cfg, pvt_node, 4059 &alt_def_pfx, &alt_bmp_len); 4060 ALPM_IEG(rv); 4061 4062 /* do insert propagation to update existing default datas */ 4063 if (ACB_HAS_RTE(acb, vrf_id)) { 4064 /* Fill in AUX Scratch and perform PREFIX Operation */ 4065 alpm_ppg_prepare(u, lpm_cfg, alt_bmp_len, alt_def_pfx, &ppg_data); 4066 rv = alpm_ppg_assoc_data(u, ALPM_PPG_DELETE, &ppg_data); 4067 ALPM_IEG(rv); 4068 } 4069 4070 /* Delete pvt entry if bucket is empty */ 4071 bkt_empty = (PVT_KEY_LEN(pvt_node) != 0 && bkt_trie->trie == NULL); 4072 if (bkt_empty) { 4073 rv = alpm_pvt_delete_by_pvt_node(u, acb, pvt_node); 4074 ALPM_IEG(rv); 4075 } 4076 4077 /* Invalid the bucket entry */ 4078 rv = alpm_bkt_pfx_clean(u, acb, pvt_node, 1, &bkt_node->ent_idx); 4079 ALPM_IEG(rv); 4080 4081 if (ACB_BKT_WRA(acb, PVT_BKT_VRF(pvt_node))) { 4082 if (bkt_empty) { 4083 rv = alpm_bkt_bnk_shrink(u, ipt, acb, 4084 ACB_BKT_VRF_POOL(acb, PVT_BKT_VRF(pvt_node)), 4085 &PVT_BKT_INFO(pvt_node), NULL); 4086 ALPM_IEG(rv); 4087 } else { 4088 rv = alpm_bkt_pfx_shrink(u, acb, pvt_node, &shrink_empty_only); 4089 ALPM_IEG(rv); 4090 } 4091 } else { 4092 if (bkt_empty || bkt_trie->trie != NULL || 4093 VRF_ROUTE_CNT(acb, vrf_id, ipt) == 0) { 4094 rv = alpm_bkt_bnk_shrink(u, ipt, acb, 4095 ACB_BKT_VRF_POOL(acb, PVT_BKT_VRF(pvt_node)), 4096 &PVT_BKT_INFO(pvt_node), NULL); 4097 ALPM_IEG(rv); 4098 } 4099 } 4100 4101 alpm_util_free(bkt_node); 4102 4103 if (bkt_empty) { 4104 rv = alpm_lib_trie_delete(ACB_PVT_TRIE(acb, vrf_id, ipt), pvt_node->key, 4105 PVT_KEY_LEN(pvt_node), &tn); 4106 if (BCM_FAILURE(rv)) { 4107 ALPM_ERR(("Trie delete node failure\n")); 4108 } 4109 4110 (void)alpm_lib_trie_destroy(bkt_trie); 4111 alpm_util_free(pvt_node); 4112 } else { 4113 if (BCM_SUCCESS(rv) && 4114 ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_SANITY_NODE) { 4115 rv = alpm_cb_pvt_sanity_cb(u, acb, pvt_node, "CBDelete"); 4116 } 4117 } 4118 4119 if (BCM_SUCCESS(rv)) { 4120 ALPM_MERGE_STATE_CHANGED(u, vrf_id); 4121 } 4122 4123 VRF_ROUTE_DEC(acb, vrf_id, ipt); 4124 4125 return rv; 4126 4127 bad: 4128 /* Roll back ? */ 4129 return rv; 4130 } 4131 4132 uint32 4133 alpm_cb_pvt_most_ref_len_get(int u, uint32 *pvt_len_cnt, int max_len) 4134 { 4135 int i; 4136 int max_cnt = 0, max_ref_len = 0; 4137 4138 for (i = 0; i < 128; i++) { 4139 if (i >= max_len) { 4140 break; 4141 } 4142 if (max_cnt < pvt_len_cnt[i]) { 4143 max_cnt = pvt_len_cnt[i]; 4144 max_ref_len = i; 4145 } 4146 } 4147 return max_ref_len; 4148 } 4149 4150 static int 4151 alpm_trie_pfx_len_ref_cnt_cb(alpm_lib_trie_node_t *node, void *user_data) 4152 { 4153 uint32 *pl_ref_cnt; 4154 4155 pl_ref_cnt = (uint32 *)user_data; 4156 if (node->type == trieNodeTypePayload) { 4157 uint32 key_len = ((_alpm_bkt_node_t *)node)->key_len; 4158 pl_ref_cnt[key_len]++; 4159 } 4160 return BCM_E_NONE; 4161 } 4162 4163 int 4164 alpm_cb_path_construct(int u, _alpm_cb_t *acb, _bcm_defip_cfg_t *lpm_cfg) 4165 { 4166 int rv = BCM_E_NONE; 4167 int vrf_id, ipt; 4168 int fmt_update = 0; 4169 4170 vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 4171 ipt = ALPM_LPM_IPT(u, lpm_cfg); 4172 4173 if (lpm_cfg->l1_pvt_node != NULL && !ACB_HAS_TCAM(acb)) { 4174 _alpm_bkt_info_t bkt_info; 4175 _alpm_cb_t *top_cb = ACB_TOP(u); 4176 _alpm_pvt_node_t *l1_pvt_node = lpm_cfg->l1_pvt_node; 4177 rv = alpm_bkt_ent_get(u, vrf_id, top_cb, l1_pvt_node, 4178 l1_pvt_node->key_len, NULL, &fmt_update, 1); 4179 /* return FULL when Expand exceeds bnk_threshold */ 4180 if (rv == BCM_E_RESOURCE) { 4181 return BCM_E_FULL; 4182 } 4183 4184 if (rv == BCM_E_FULL) { 4185 sal_memset(&bkt_info, 0, sizeof(_alpm_bkt_info_t)); 4186 rv = alpm_bkt_alloc(u, top_cb, vrf_id, ipt, 4187 ACB_BNK_PER_BKT(top_cb, vrf_id), 4188 &bkt_info, NULL); 4189 ALPM_IER_PRT_EXCEPT(rv, BCM_E_FULL); 4190 rv = alpm_cb_split(u, top_cb, lpm_cfg, &bkt_info, 0xffff); 4191 if (rv == BCM_E_BUSY && ACB_HAS_RTE(acb, vrf_id) && lpm_cfg->spl_pn) { 4192 sal_memset(&bkt_info, 0, sizeof(_alpm_bkt_info_t)); 4193 rv = alpm_bkt_alloc(u, acb, vrf_id, ipt, 4194 ACB_BNK_PER_BKT(acb, vrf_id), 4195 &bkt_info, NULL); 4196 ALPM_IER_PRT_EXCEPT(rv, BCM_E_FULL); 4197 /* Case 2.2.2, split given l3 pvt_node first */ 4198 rv = alpm_cb_split(u, acb, lpm_cfg, &bkt_info, 0xffff); 4199 ALPM_IER_PRT_EXCEPT(rv, BCM_E_FULL); 4200 lpm_cfg->spl_pn = NULL; 4201 lpm_cfg->spl_key_len = 0; 4202 } else if (BCM_FAILURE(rv)) { 4203 ALPM_IER_PRT_EXCEPT(rv, BCM_E_FULL); 4204 } else { 4205 lpm_cfg->pvt_node = NULL; 4206 } 4207 lpm_cfg->l1_pvt_node = NULL; 4208 } else { 4209 int most_ref_len = 0; 4210 uint32 pl_ref_cnt[128]; 4211 _bcm_defip_cfg_t l2_lpm_cfg; 4212 _alpm_pvt_node_t *pvt_node; 4213 4214 pvt_node = lpm_cfg->l1_pvt_node; 4215 sal_memcpy(&l2_lpm_cfg, lpm_cfg, sizeof(l2_lpm_cfg)); 4216 4217 sal_memset(pl_ref_cnt, 0, sizeof(pl_ref_cnt)); 4218 rv = alpm_lib_trie_traverse(PVT_BKT_TRIE(pvt_node), 4219 alpm_trie_pfx_len_ref_cnt_cb, pl_ref_cnt, 4220 trieTraverseOrderIn); 4221 if (BCM_SUCCESS(rv)) { 4222 most_ref_len = alpm_cb_pvt_most_ref_len_get(u, pl_ref_cnt, 4223 l2_lpm_cfg.defip_sub_len); 4224 } 4225 if (most_ref_len == 0) { 4226 most_ref_len = alpm_cb_pvt_most_ref_len_get(u, 4227 VRF_PVT_LEN_CNT_PTR(acb, vrf_id, ipt), 4228 l2_lpm_cfg.defip_sub_len); 4229 } 4230 4231 if (pvt_node->key_len < most_ref_len && 4232 most_ref_len < l2_lpm_cfg.defip_sub_len) { 4233 l2_lpm_cfg.defip_sub_len = most_ref_len; 4234 } else { 4235 l2_lpm_cfg.defip_sub_len = pvt_node->key_len; 4236 } 4237 l2_lpm_cfg.bkt_kshift = l2_lpm_cfg.defip_sub_len; 4238 alpm_util_ipmask_apply(u, &l2_lpm_cfg); 4239 alpm_trie_cfg_to_pfx(u, &l2_lpm_cfg, l2_lpm_cfg.user_data); 4240 if (PVT_BKT_DEF(pvt_node)) { 4241 alpm_util_adata_trie_to_cfg(u, &PVT_BKT_DEF(pvt_node)->adata, 4242 &l2_lpm_cfg); 4243 l2_lpm_cfg.default_miss = 0; 4244 } else { 4245 alpm_util_adata_zero_cfg(u, &l2_lpm_cfg); 4246 l2_lpm_cfg.default_miss = 1; 4247 } 4248 rv = alpm_cb_pvt_add(u, acb, vrf_id, ipt, &l2_lpm_cfg); 4249 if (BCM_FAILURE(rv)) { 4250 ALPM_IER_PRT_EXCEPT(rv, BCM_E_FULL); 4251 } else { 4252 lpm_cfg->pvt_node = l2_lpm_cfg.pvt_node; 4253 } 4254 lpm_cfg->l1_pvt_node = NULL; 4255 } 4256 } 4257 4258 return rv; 4259 } 4260 4261 int 4262 alpm_cb_insert(int u, _alpm_cb_t *acb, _bcm_defip_cfg_t *lpm_cfg) 4263 { 4264 int rv = BCM_E_NONE; 4265 int vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 4266 int ipt = ALPM_LPM_IPT(u, lpm_cfg); 4267 uint32 *prefix, length; 4268 uint32 ent_idx; 4269 int retry_count = 0, retry_max = 3; 4270 int bkt_trie_added = 0; 4271 4272 alpm_lib_trie_t *bkt_trie = NULL; 4273 alpm_lib_trie_node_t *tmp_node = NULL; 4274 4275 _alpm_ppg_data_t ppg_data; 4276 _alpm_bkt_node_t *bkt_node = NULL; 4277 _alpm_pvt_node_t *pvt_node, *upr_pvt_node; 4278 _alpm_tcam_write_t tcam_write; 4279 4280 /* Init ALPM structure for first insert or was DR partially inited (MC first) */ 4281 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt) || ACB_DR_INITED(u, acb, vrf_id, ipt)) { 4282 uint8 db_type = alpm_util_route_type_get(u, lpm_cfg); 4283 ALPM_IEG(alpm_vrf_init(u, acb, vrf_id, ipt, db_type)); 4284 } 4285 4286 if (ACB_BKT_FIXED_FMT(acb, vrf_id)) { 4287 retry_max = 1; 4288 } 4289 4290 pvt_node = ACB_HAS_TCAM(acb) ? lpm_cfg->l1_pvt_node : lpm_cfg->pvt_node; 4291 4292 retry: 4293 if (pvt_node == NULL) { 4294 ALPM_IEG(alpm_pvt_find(u, acb, lpm_cfg, &pvt_node)); 4295 if (ACB_HAS_TCAM(acb)) { 4296 lpm_cfg->l1_pvt_node = pvt_node; 4297 } else { 4298 rv = alpm_pvt_find(u, ACB_UPR(u, acb), lpm_cfg, &upr_pvt_node); 4299 ALPM_IEG(rv); 4300 if (pvt_node && upr_pvt_node) { 4301 if (upr_pvt_node->key_len <= pvt_node->key_len) { 4302 lpm_cfg->pvt_node = pvt_node; 4303 } else { 4304 lpm_cfg->l1_pvt_node = upr_pvt_node; 4305 ALPM_IEG_PRT_EXCEPT(alpm_cb_path_construct(u, acb, lpm_cfg), BCM_E_FULL); 4306 pvt_node = lpm_cfg->pvt_node; 4307 if (pvt_node == NULL) { 4308 goto retry; 4309 } 4310 } 4311 } 4312 } 4313 } 4314 4315 /* entry shouldn't exist, insert the entry into the RAM */ 4316 rv = alpm_bkt_insert(u, acb, lpm_cfg, pvt_node, &ent_idx); 4317 4318 /* return FULL when Expand exceeds bnk_threshold */ 4319 if (rv == BCM_E_RESOURCE) { 4320 rv = BCM_E_FULL; 4321 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 4322 } 4323 4324 retry_spl: 4325 if (rv == BCM_E_FULL && retry_count < retry_max) { 4326 int avl_bnk_cnt = 0; 4327 int max_spl_cnt = 0xffff; 4328 _alpm_bkt_info_t bkt_info; 4329 _alpm_tcam_write_t *ptcam_write; 4330 4331 /* Case of add new L1 pvt from L2 bkt split: 4332 This is only for 3-lvl ALPM (TH3). 4333 TCAM entry pending to write to HW until add new L2 bkt if it 4334 belongs to new L1 pvt (otherwise mis-forwarding may happen) */ 4335 if (ACB_IDX(acb) != ACB_VRF_BTM_IDX(u, vrf_id)) { 4336 tcam_write.hw_idx = -1; /* initialized as invalid */ 4337 tcam_write.rv = 0xffff; /* init tcam_write.rv with 0xffff, will be changed 4338 to BCM_E_XXX in L2 bkt insert within L2 bkt split */ 4339 lpm_cfg->tcam_write = &tcam_write; 4340 } else { 4341 lpm_cfg->tcam_write = NULL; 4342 } 4343 4344 /* Perform bucket merge before allocation only for fixed fmt */ 4345 if (ACB_BKT_FIXED_FMT(acb, vrf_id)) { 4346 uint8 def_fmt; 4347 if (!bcm_esw_alpm_tcam_avail(u, vrf_id, ipt, lpm_cfg->defip_sub_len, 0) && 4348 ACB_HAS_TCAM(acb)) { 4349 rv = alpm_cb_merge(u, acb, vrf_id, ipt); 4350 ALPM_IEG(rv); 4351 /* pvt node could be merged and freed, 4352 * Need a faster version ALPMTBD */ 4353 pvt_node = NULL; 4354 goto retry; 4355 } 4356 sal_memset(&bkt_info, 0, sizeof(_alpm_bkt_info_t)); 4357 rv = alpm_bkt_alloc(u, acb, vrf_id, ipt, 4358 ACB_BNK_PER_BKT(acb, vrf_id), 4359 &bkt_info, &avl_bnk_cnt); 4360 if (rv == BCM_E_BUSY) { 4361 /* pvt node could be merged and freed, 4362 * Need a faster version ALPMTBD */ 4363 pvt_node = NULL; 4364 goto retry; 4365 } else if (rv == BCM_E_FULL) { 4366 if (avl_bnk_cnt > 0) { 4367 sal_memset(&bkt_info, 0, sizeof(_alpm_bkt_info_t)); 4368 rv = alpm_bkt_alloc(u, acb, vrf_id, ipt, 4369 avl_bnk_cnt, &bkt_info, NULL); 4370 if (rv == BCM_E_BUSY) { 4371 /* pvt node could be merged and freed, 4372 * Need a faster version ALPMTBD */ 4373 pvt_node = NULL; 4374 goto retry; 4375 } 4376 } 4377 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 4378 } else { 4379 avl_bnk_cnt = ACB_BNK_PER_BKT(acb, vrf_id); 4380 } 4381 4382 def_fmt = alpm_util_bkt_def_fmt_get(u, acb, vrf_id, ipt); 4383 max_spl_cnt = avl_bnk_cnt * ACB_FMT_ENT_MAX(acb, vrf_id, def_fmt) - 1; 4384 } else { 4385 sal_memset(&bkt_info, 0, sizeof(_alpm_bkt_info_t)); 4386 rv = alpm_bkt_alloc(u, acb, vrf_id, ipt, 4387 ACB_BNK_PER_BKT(acb, vrf_id), 4388 &bkt_info, &avl_bnk_cnt); 4389 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 4390 } 4391 4392 rv = alpm_cb_split(u, acb, lpm_cfg, &bkt_info, max_spl_cnt); 4393 /* Upper level of BCM_E_BUSY point, 4394 * ACB_HAS_RTE may not be a good condition, but considering 4395 * it's only 3 levels so it also works. 4396 */ 4397 if (rv == BCM_E_BUSY && ACB_HAS_RTE(acb, vrf_id) && lpm_cfg->spl_pn) { 4398 sal_memset(&bkt_info, 0, sizeof(_alpm_bkt_info_t)); 4399 rv = alpm_bkt_alloc(u, acb, vrf_id, ipt, 4400 ACB_BNK_PER_BKT(acb, vrf_id), 4401 &bkt_info, &avl_bnk_cnt); 4402 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 4403 4404 /* Case 2.2.2, split given l3 pvt_node first */ 4405 rv = alpm_cb_split(u, acb, lpm_cfg, &bkt_info, max_spl_cnt); 4406 if (BCM_SUCCESS(rv)) { 4407 lpm_cfg->spl_pn = NULL; 4408 lpm_cfg->spl_key_len = 0; 4409 /* PERF OPT point */ 4410 pvt_node = NULL; 4411 goto retry; 4412 } 4413 } 4414 4415 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 4416 4417 ptcam_write = lpm_cfg->tcam_write; 4418 if (ptcam_write != NULL) { 4419 if (ptcam_write->rv == BCM_E_NONE) { 4420 goto _exit; /* already done in alpm_bkt_add_to_npvt */ 4421 } else if (ptcam_write->rv == BCM_E_FULL) { 4422 rv = BCM_E_FULL; 4423 retry_count ++; 4424 goto retry_spl; /* skip alpm_bkt_insert */ 4425 } 4426 } 4427 4428 /* Need a faster version ALPMTBD */ 4429 pvt_node = NULL; 4430 retry_count ++; 4431 goto retry; 4432 } 4433 4434 ALPM_IEG_PRT_EXCEPT(rv, BCM_E_FULL); 4435 4436 lpm_cfg->defip_index = ent_idx; 4437 4438 /* Allocate Payload */ 4439 ALPM_ALLOC_EG(bkt_node, sizeof(_alpm_bkt_node_t), "bkt_node"); 4440 prefix = lpm_cfg->user_data; 4441 length = lpm_cfg->defip_sub_len; 4442 sal_memcpy(bkt_node->key, prefix, sizeof(bkt_node->key)); 4443 bkt_node->key_len = length; 4444 bkt_node->ent_idx = ent_idx; 4445 alpm_util_adata_cfg_to_trie(u, lpm_cfg, &bkt_node->adata); 4446 /* Insert the prefix */ 4447 /* bucket trie insert */ 4448 bkt_trie = PVT_BKT_TRIE(pvt_node); 4449 rv = alpm_lib_trie_insert(bkt_trie, prefix, length, (alpm_lib_trie_node_t *)bkt_node); 4450 ALPM_IEG(rv); 4451 bkt_trie_added = 1; 4452 4453 rv = alpm_vrf_pfx_trie_add(u, acb, lpm_cfg, bkt_node); 4454 ALPM_IEG(rv); 4455 4456 /* do insert propagation to update existing default datas */ 4457 if (ACB_HAS_RTE(acb, vrf_id)) { 4458 /* Fill in AUX Scratch and perform PREFIX Operation */ 4459 alpm_ppg_prepare(u, lpm_cfg, 0, bkt_node, &ppg_data); 4460 rv = alpm_ppg_assoc_data(u, ALPM_PPG_INSERT, &ppg_data); 4461 } 4462 if (BCM_SUCCESS(rv) && 4463 ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_SANITY_NODE) { 4464 rv = alpm_cb_pvt_sanity_cb(u, acb, pvt_node, "CBInsert"); 4465 } 4466 4467 VRF_ROUTE_ADD(acb, vrf_id, ipt); 4468 _exit: 4469 lpm_cfg->tcam_write = NULL; 4470 if (rv == BCM_E_FULL) { 4471 acb->acb_cnt.c_full++; 4472 } 4473 return rv; 4474 4475 bad: 4476 if (bkt_trie_added) { 4477 (void)alpm_lib_trie_delete(bkt_trie, prefix, length, &tmp_node); 4478 } 4479 if (bkt_node != NULL) { 4480 alpm_util_free(bkt_node); 4481 } 4482 lpm_cfg->tcam_write = NULL; 4483 if (rv == BCM_E_FULL) { 4484 acb->acb_cnt.c_full++; 4485 } 4486 return rv; 4487 } 4488 4489 static int 4490 bcm_esw_alpm_ctrl_deinit(int u) 4491 { 4492 int rv = BCM_E_NONE; 4493 4494 if (ALPM_DRV(u)) { 4495 ALPM_DRV(u)->alpm_ctrl_deinit(u); 4496 } 4497 4498 if (ALPMC(u)->_vrf_pfx_hdl != NULL) { 4499 alpm_util_free(ALPMC(u)->_vrf_pfx_hdl); 4500 } 4501 4502 if (ALPMC(u)->_alpm_merge_state != NULL) { 4503 alpm_util_free(ALPMC(u)->_alpm_merge_state); 4504 } 4505 4506 if (ALPMC(u)->_alpm_err_msg_buf != NULL) { 4507 alpm_util_free(ALPMC(u)->_alpm_err_msg_buf); 4508 } 4509 4510 if (ALPMC(u) != NULL) { 4511 alpm_util_free(ALPMC(u)); 4512 ALPMC(u) = NULL; 4513 } 4514 4515 return rv; 4516 } 4517 4518 int 4519 bcm_esw_alpm_ctrl_init(int u) 4520 { 4521 int rv = BCM_E_NONE; 4522 int vrf_id_cnt; 4523 int alloc_sz; 4524 int pair_ent_cnt = 0; 4525 int bnk_thres; 4526 int max_tcams = SOC_L3_DEFIP_MAX_TCAMS_GET(u); 4527 int tcam_depth = SOC_L3_DEFIP_TCAM_DEPTH_GET(u); 4528 int def_ipv6_128b_entries = tcam_depth * max_tcams / 4; 4529 4530 alloc_sz = sizeof(_alpm_ctrl_t); 4531 ALPM_ALLOC_EG(ALPMC(u), alloc_sz, "ALPMC"); 4532 4533 ALPMC(u)->_alpm_max_vrf_id = SOC_VRF_MAX(u); 4534 4535 /* Init ALPMC variables */ 4536 if (SAL_BOOT_SIMULATION && SOC_IS_TOMAHAWK3(u)) { 4537 ALPM_HIT_SKIP(u) = soc_property_get(u, spn_L3_ALPM_HIT_SKIP, 1); 4538 } else { 4539 ALPM_HIT_SKIP(u) = soc_property_get(u, spn_L3_ALPM_HIT_SKIP, 0); 4540 } 4541 ALPM_MODE(u) = soc_alpm_cmn_mode_get(u); 4542 if (ALPM_MODE_CHK(u, BCM_ALPM_MODE_PARALLEL) || 4543 ALPM_MODE_CHK(u, BCM_ALPM_MODE_TCAM_ALPM)) { 4544 ALPM_TCAM_ZONED(u) = TRUE; 4545 } 4546 4547 /* Due to swith control L3Max128BV6Entries, pair_ent_cnt 4548 shouldn't come directly from spn_NUM_IPV6_LPM_128B_ENTRIES */ 4549 ALPM_128B(u) = SOC_ALPM_128B_ENABLE(u); 4550 pair_ent_cnt = SOC_L3_DEFIP_MAX_128B_ENTRIES(u); 4551 if (pair_ent_cnt > (def_ipv6_128b_entries * 2)) { 4552 pair_ent_cnt = def_ipv6_128b_entries * 2; 4553 } 4554 4555 ALPM_TCAM_PAIR_BLK_CNT(u) = (pair_ent_cnt + (tcam_depth - 1)) / tcam_depth; 4556 4557 /* these two thresholds are applicable only for TH3 */ 4558 ALPMC(u)->_alpm_bulk_wr_threshold = 4559 soc_property_get(u, "l3_alpm2_bulk_wr_threshold", 16); 4560 bnk_thres = soc_property_get(u, spn_L3_ALPM2_BNK_THRESHOLD, 95); 4561 if (bnk_thres <= 0 || bnk_thres > 100) { 4562 bnk_thres = 95; 4563 } 4564 ALPMC(u)->_alpm_bnk_threshold = bnk_thres; 4565 4566 ALPMC(u)->_alpm_spl[ALPM_PKM_32B] = 4567 soc_property_get(u, "l3_alpm2_spl_hw", 24); 4568 ALPMC(u)->_alpm_spl[ALPM_PKM_64B] = 4569 soc_property_get(u, "l3_alpm2_spl_sw", 56); 4570 ALPMC(u)->_alpm_spl[ALPM_PKM_128] = 4571 soc_property_get(u, "l3_alpm2_spl_dw", 120); 4572 4573 ALPMC(u)->_alpm_dbg_bmp = soc_property_get(u, "l3_alpm2_dbg_bmp", 0x0); 4574 if (ALPMC(u)->_alpm_dbg_bmp != 0) { 4575 int i; 4576 ALPM_INFO(("[ALPM-INIT] _alpm_dbg_bmp enabled bit(s) [")); 4577 for (i = 0; i < 32; i++) { 4578 if (ALPMC(u)->_alpm_dbg_bmp & (1 << i)) { 4579 ALPM_INFO(("%d ", i)); 4580 } 4581 } 4582 ALPM_INFO(("]\n")); 4583 } 4584 4585 ALPMC(u)->_alpm_dbg_info_bmp = soc_property_get(u, "l3_alpm2_dbg_info_bmp", 0x07); 4586 4587 /* Private VRFs + 2 Global VRFs */ 4588 vrf_id_cnt = ALPM_VRF_ID_CNT(u); 4589 alloc_sz = sizeof(_alpm_pfx_ctrl_t) * vrf_id_cnt; 4590 ALPM_ALLOC_EG(ALPMC(u)->_vrf_pfx_hdl, alloc_sz, "_vrf_pfx_hdl"); 4591 4592 alloc_sz = sizeof(int) * vrf_id_cnt; 4593 ALPM_ALLOC_EG(ALPMC(u)->_alpm_merge_state, alloc_sz, "_alpm_merge_state"); 4594 4595 alloc_sz = _ALPM_ERR_MSG_BUF_CNT * _ALPM_ERR_MSG_BUF_ENT_SZ; 4596 ALPM_ALLOC_EG(ALPMC(u)->_alpm_err_msg_buf, alloc_sz, "_alpm_err_msg_buf"); 4597 4598 if (soc_feature(u, soc_feature_alpm2)) { 4599 if (SOC_IS_TOMAHAWK3(u)) { 4600 ALPMC(u)->alpm_driver = &th3_alpm_driver; 4601 } else 4602 { 4603 ALPMC(u)->alpm_driver = &th_alpm_driver; 4604 } 4605 } 4606 4607 if (ALPM_128B(u)) { 4608 ALPM_BKT_RSVD(u) = soc_property_get(u, spn_L3_ALPM_IPV6_128B_BKT_RSVD, 0); 4609 if (ALPM_BKT_RSVD(u)) { 4610 /* Based on 8K Buckets */ 4611 ALPM_BKT_RSVD_CNT(u) = 4612 pair_ent_cnt * 2 * 8192 / (tcam_depth * max_tcams); 4613 } 4614 } 4615 4616 rv = ALPM_DRV(u)->alpm_ctrl_init(u); 4617 if (BCM_FAILURE(rv)) { 4618 goto bad; 4619 } 4620 4621 return rv; 4622 4623 bad: 4624 bcm_esw_alpm_ctrl_deinit(u); 4625 return rv; 4626 } 4627 4628 /* ALPM ctrl cleanup for faster delete_all */ 4629 int 4630 bcm_esw_alpm_ctrl_cleanup(int u) 4631 { 4632 int rv = BCM_E_NONE; 4633 int vrf_id_cnt; 4634 int alloc_sz; 4635 4636 rv = alpm_trie_clear_all(u); 4637 4638 vrf_id_cnt = ALPM_VRF_ID_CNT(u); 4639 alloc_sz = sizeof(int) * vrf_id_cnt; 4640 sal_memset(ALPMC(u)->_alpm_merge_state, 0, alloc_sz); 4641 4642 alloc_sz = _ALPM_ERR_MSG_BUF_CNT * _ALPM_ERR_MSG_BUF_ENT_SZ; 4643 sal_memset(ALPMC(u)->_alpm_err_msg_buf, 0, alloc_sz); 4644 4645 rv = ALPM_DRV(u)->alpm_ctrl_cleanup(u); 4646 return rv; 4647 } 4648 4649 /* Initialize ALPM Subsytem */ 4650 4651 int 4652 bcm_esw_alpm_deinit(int u) 4653 { 4654 int rv = BCM_E_NONE; 4655 4656 BCM_IF_ERROR_RETURN(alpm_trie_clear_all(u)); 4657 BCM_IF_ERROR_RETURN(bcm_esw_alpm_trace_deinit(u)); 4658 BCM_IF_ERROR_RETURN(bcm_esw_alpm_hit_deinit(u)); 4659 BCM_IF_ERROR_RETURN(bcm_esw_alpm_ctrl_deinit(u)); 4660 BCM_IF_ERROR_RETURN(bcm_esw_alpm_tcam_deinit(u)); 4661 alpm_util_mem_stat_clear(); 4662 4663 return rv; 4664 } 4665 4666 static void 4667 bcm_esw_alpm_init_done(int u, int rv) 4668 { 4669 int i; 4670 int banks, mode, urpf; 4671 char *mode_str[] = { 4672 "invalid", 4673 "combined", 4674 "parallel", 4675 "mixed" 4676 }; 4677 4678 if (BCM_FAILURE(rv)) { 4679 LOG_CLI(("*** unit %d: alpm init failed\n", u)); 4680 return; 4681 } 4682 4683 /* pass */ 4684 /* *** unit 0: alpm level 2 loaded: 4 banks in combined-128 (urpf) */ 4685 urpf = SOC_URPF_STATUS_GET(u); 4686 mode = ALPM_MODE(u); 4687 4688 for (i = 0; i < ACB_CNT(u); i++) { 4689 banks = ACB_PHY_BNK_PER_BKT(ACB(u, i)); 4690 LOG_CLI(("*** unit %d: alpm level %d loaded: %d banks in %s-%s %s\n", 4691 u, i+2, banks, mode_str[mode+1], ALPM_128B(u) ? "128" : "64", 4692 urpf ? "(urpf)" : "")); 4693 4694 } 4695 } 4696 4697 int 4698 bcm_esw_alpm_init(int u) 4699 { 4700 int rv = BCM_E_NONE; 4701 4702 if (ALPMC(u) && ALPMC(u)->_alpm_inited) { 4703 ALPM_IEG(bcm_esw_alpm_deinit(u)); 4704 } 4705 4706 ALPM_IEG(bcm_esw_alpm_ctrl_init(u)); 4707 ALPM_IEG(bcm_esw_alpm_tcam_init(u)); 4708 ALPM_IEG(bcm_esw_alpm_hit_init(u)); 4709 ALPM_IEG(bcm_esw_alpm_trace_init(u)); 4710 4711 ALPMC(u)->_alpm_inited = TRUE; 4712 4713 bad: 4714 bcm_esw_alpm_init_done(u, rv); 4715 return rv; 4716 } 4717 4718 /* 4719 * Function: 4720 * bcm_esw_alpm_cleanup 4721 * Purpose: 4722 * Fast ALPM delete all 4723 * Parameters: 4724 * u - (IN)Device unit number. 4725 * trv_data - (IN)Delete pattern + compare,act,notify routines for TCAM Direct routes. 4726 * trv_data1 - (IN)Delete pattern + compare,act,notify routines for ALPM routes. 4727 * Returns: 4728 * BCM_E_XXX 4729 */ 4730 int 4731 bcm_esw_alpm_cleanup(int u, _bcm_l3_trvrs_data_t *trv_data, 4732 _bcm_l3_trvrs_data_t *trv_data1) 4733 { 4734 int rv = BCM_E_NONE; 4735 int us = 0; 4736 4737 if (ALPMC(u) && ALPMC(u)->_alpm_inited) { 4738 4739 if (!ALPM_HIT_SKIP(u) && ALPMDH(u)) { 4740 us = ALPMDH(u)->interval; /* save */ 4741 rv = alpm_dist_hitbit_enable_set(u, 0); 4742 } 4743 4744 /* Fast delete all by travel data in below order: 4745 1) TCAM direct routes + ecmp_nh (trv_data) 4746 2) TCAM Hw table 4747 3) ALPM ecmp_nh (trv_data1) */ 4748 rv = bcm_esw_alpm_fast_delete_all(u, trv_data, trv_data1); 4749 if (BCM_FAILURE(rv)) { 4750 ALPM_ERR(("ALPM/TCAM fast_delete_all travel failed (%d)", rv)); 4751 } 4752 4753 rv = bcm_esw_alpm_ctrl_cleanup(u); 4754 if (BCM_FAILURE(rv)) { 4755 ALPM_ERR(("ALPM ctrl cleanup failed (%d)", rv)); 4756 } 4757 4758 rv = bcm_esw_alpm_tcam_cleanup(u); 4759 if (BCM_FAILURE(rv)) { 4760 ALPM_ERR(("ALPM tcam cleanup failed (%d)", rv)); 4761 } 4762 4763 if (!ALPM_HIT_SKIP(u) && ALPMDH(u)) { 4764 rv = ALPM_DRV(u)->alpm_hit_cleanup(u); 4765 if (BCM_FAILURE(rv)) { 4766 ALPM_ERR(("ALPM hitbit cleanup failed (%d)", rv)); 4767 } 4768 rv = alpm_dist_hitbit_enable_set(u, us); 4769 } 4770 4771 alpm_trace_log(u, ALPM_TRACE_OP_DELETE_ALL, NULL, 0, rv); 4772 } 4773 4774 return rv; 4775 } 4776 4777 /* 4778 * bcm_esw_alpm_insert 4779 * For IPV4 assume only both IP_ADDR0 is valid 4780 * Moving multiple entries around in h/w vs doing a linear search in s/w 4781 */ 4782 int 4783 bcm_esw_alpm_insert(int u, _bcm_defip_cfg_t *lpm_cfg) 4784 { 4785 int rv = BCM_E_NONE, rv2; 4786 int vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 4787 int ipt = ALPM_LPM_IPT(u, lpm_cfg); 4788 int pvt_info = lpm_cfg->defip_alpm_cookie; 4789 _alpm_cb_t *acb = NULL; 4790 4791 alpm_util_ipmask_apply(u, lpm_cfg); 4792 alpm_trie_cfg_to_pfx(u, lpm_cfg, lpm_cfg->user_data); 4793 4794 /* Routes reside in TCAM only in below cases: 4795 * Global High routes 4796 * Global low routes in Mixed mode 4797 */ 4798 if (ALPM_LPM_DIRECT_RTE(u, lpm_cfg)) { 4799 /* Init pvt_trie for direct routes */ 4800 acb = ACB_TOP(u); 4801 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt)) { 4802 ALPM_IER(alpm_pvt_trie_init(u, vrf_id, ipt)); 4803 } 4804 4805 /* Insert into TCAM directly and return */ 4806 rv = bcm_esw_alpm_tcam_insert(u, lpm_cfg, ALPM_PVT_UPDATE_ALL); 4807 if (BCM_SUCCESS(rv)) { 4808 if (!(pvt_info & BCM_ALPM_LPM_LOOKUP_HIT)) { 4809 VRF_ROUTE_ADD(acb, vrf_id, ipt); 4810 } 4811 /* Insert only Direct route pvt trie */ 4812 rv = alpm_pvt_trie_insert(u, lpm_cfg); 4813 if (rv == BCM_E_EXISTS && 4814 (lpm_cfg->defip_flags & BCM_L3_REPLACE)) { 4815 rv = BCM_E_NONE; 4816 } 4817 } 4818 if (rv == BCM_E_FULL) { 4819 acb->acb_cnt.c_full++; 4820 } 4821 return(rv); 4822 } 4823 4824 /* Route mode and default route validation */ 4825 ALPM_IER(alpm_util_route_type_check(u, lpm_cfg)); 4826 ALPM_IER(alpm_util_def_check(u, lpm_cfg, TRUE)); 4827 acb = ACB_VRF_BTM(u, vrf_id); 4828 4829 /* Find and update the entry */ 4830 if (pvt_info & BCM_ALPM_LOOKUP_HIT) { 4831 rv = alpm_cb_update(u, acb, lpm_cfg); 4832 return rv; 4833 } 4834 4835 /* entry is not found in database */ 4836 /* Insert the entry into the database, if FULL, split the bucket */ 4837 /* Insert prefix into trie */ 4838 /* Split trie : Insertion into trie results into Split */ 4839 /* Allocate a TCAM entry for PIVOT and bucket and move entries */ 4840 rv = alpm_cb_path_construct(u, acb, lpm_cfg); 4841 if (rv == BCM_E_FULL) { 4842 acb->acb_cnt.c_full++; 4843 } 4844 ALPM_IER_PRT_EXCEPT(rv, BCM_E_FULL); 4845 4846 rv = alpm_cb_insert(u, acb, lpm_cfg); 4847 if (BCM_SUCCESS(rv)) { 4848 lpm_cfg->defip_index = 4849 alpm_util_ent_phy_idx_get(u, acb, vrf_id, lpm_cfg->defip_index); 4850 } else if (rv != BCM_E_FULL) { 4851 ALPM_ERR(("**ACB(%d).INSERT: Failed %d\n", ACB_IDX(acb), rv)); 4852 } else { /* FULL */ 4853 int rv3; 4854 rv3 = alpm_pvt_delete_by_empty_bkt(u, acb, lpm_cfg); 4855 if (BCM_FAILURE(rv3)) { 4856 ALPM_ERR(("**ACB(%d).INSERT: Full. " 4857 "Pvt delete by empty bkt: Failed %d\n", ACB_IDX(acb), rv3)); 4858 } 4859 } 4860 4861 rv2 = alpm_cb_sanity(u, 0x3, vrf_id, ipt); 4862 rv = (rv == BCM_E_NONE) ? rv2 : rv; 4863 4864 return(rv); 4865 } 4866 4867 /* 4868 * bcm_esw_alpm_lookup 4869 * For IPV4 assume only both IP_ADDR0 is valid 4870 * Moving multiple entries around in h/w vs doing a linear search in s/w 4871 */ 4872 int 4873 bcm_esw_alpm_lookup(int u, _bcm_defip_cfg_t *lpm_cfg) 4874 { 4875 int rv = BCM_E_NONE; 4876 _alpm_cb_t *acb = NULL; 4877 _alpm_pvt_node_t *pvt_node = NULL, *upr_pvt_node = NULL; 4878 _alpm_bkt_node_t *bkt_node = NULL, *upr_bkt_node = NULL; 4879 int ipt = ALPM_LPM_IPT(u, lpm_cfg); 4880 int vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 4881 4882 alpm_util_ipmask_apply(u, lpm_cfg); 4883 4884 /* Prepare trie key format in lpm_cfg->user_data for further use */ 4885 alpm_trie_cfg_to_pfx(u, lpm_cfg, lpm_cfg->user_data); 4886 4887 if (ALPM_LPM_DIRECT_RTE(u, lpm_cfg)) { 4888 if (!ACB_VRF_INITED(u, ACB_TOP(u), vrf_id, ipt)) { 4889 ALPM_VERB(("**LOOKUP:VRF %d is not initialized\n", vrf_id)); 4890 return BCM_E_NOT_FOUND; 4891 } 4892 rv = bcm_esw_alpm_tcam_match(u, lpm_cfg, &lpm_cfg->defip_index); 4893 if (BCM_SUCCESS(rv)) { 4894 lpm_cfg->defip_alpm_cookie = BCM_ALPM_LPM_LOOKUP_HIT; 4895 } 4896 return rv; 4897 } 4898 4899 acb = ACB_VRF_BTM(u, vrf_id); 4900 4901 /* Check VRF/Key_mode based initialization */ 4902 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt)) { 4903 ALPM_VERB(("**LOOKUP:VRF %d is not initialized\n", vrf_id)); 4904 return BCM_E_NOT_FOUND; 4905 } 4906 4907 /* Find and update the entry */ 4908 rv = alpm_cb_find(u, acb, lpm_cfg, &pvt_node, &bkt_node); 4909 if (!ACB_HAS_TCAM(acb)) { 4910 (void)alpm_cb_find(u, ACB_UPR(u, acb), lpm_cfg, 4911 &upr_pvt_node, &upr_bkt_node); 4912 if (pvt_node && upr_pvt_node) { 4913 if (upr_pvt_node->key_len <= pvt_node->key_len) { 4914 lpm_cfg->pvt_node = (uint32 *)pvt_node; 4915 lpm_cfg->bkt_node = (uint32 *)bkt_node; 4916 lpm_cfg->l1_pvt_node = NULL; 4917 } else { 4918 lpm_cfg->pvt_node = NULL; 4919 lpm_cfg->bkt_node = NULL; 4920 lpm_cfg->l1_pvt_node = (uint32 *)upr_pvt_node; 4921 rv = BCM_E_NOT_FOUND; 4922 } 4923 } 4924 } else { 4925 lpm_cfg->l1_pvt_node = (uint32 *)pvt_node; 4926 lpm_cfg->pvt_node = (uint32 *)pvt_node; 4927 lpm_cfg->bkt_node = (uint32 *)bkt_node; 4928 } 4929 4930 if (BCM_SUCCESS(rv)) { 4931 /* Copy ALPM memory to LPM entry */ 4932 alpm_util_adata_trie_to_cfg(u, &bkt_node->adata, lpm_cfg); 4933 lpm_cfg->defip_index = 4934 alpm_util_ent_phy_idx_get(u, acb, vrf_id, bkt_node->ent_idx); 4935 lpm_cfg->defip_alpm_cookie = BCM_ALPM_LOOKUP_HIT; 4936 if (ACB_VRF_DB_TYPE(u, acb, vrf_id, ipt)) { 4937 lpm_cfg->defip_alpm_cookie |= ALPM_ROUTE_FULL_MD; 4938 } 4939 /* Get HIT bit from matched entry */ 4940 if (!ALPM_HIT_SKIP(u)) { 4941 int idx, ent; 4942 int hit_val; 4943 _alpm_tbl_t tbl; 4944 ent = ALPM_IDX_TO_ENT(bkt_node->ent_idx); 4945 idx = ALPM_TAB_IDX_GET(bkt_node->ent_idx); 4946 tbl = BPC_BKT_TBL(ACB_BKT_VRF_POOL(acb, vrf_id)); 4947 ALPM_HIT_LOCK(u); 4948 hit_val = alpm_rte_hit_get(u, vrf_id, tbl, idx, ent); 4949 lpm_cfg->defip_flags |= (hit_val > 0 ? BCM_L3_HIT : 0); 4950 ALPM_HIT_UNLOCK(u); 4951 } 4952 } 4953 4954 return(rv); 4955 } 4956 4957 /* 4958 * bcm_esw_alpm_delete 4959 */ 4960 int 4961 bcm_esw_alpm_delete(int u, _bcm_defip_cfg_t *lpm_cfg) 4962 { 4963 int rv = BCM_E_NONE; 4964 _alpm_cb_t *acb; 4965 _alpm_pvt_node_t *pvt_node; 4966 _alpm_bkt_node_t *bkt_node; 4967 4968 uint32 ipt = ALPM_LPM_IPT(u, lpm_cfg); 4969 uint32 vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg); 4970 4971 alpm_util_ipmask_apply(u, lpm_cfg); 4972 /* ALPM prefix */ 4973 alpm_trie_cfg_to_pfx(u, lpm_cfg, lpm_cfg->user_data); 4974 4975 /* Prefix resides in TCAM directly */ 4976 if (ALPM_LPM_DIRECT_RTE(u, lpm_cfg)) { 4977 acb = ACB_TOP(u); 4978 rv = bcm_esw_alpm_tcam_delete(u, lpm_cfg); 4979 4980 if (BCM_SUCCESS(rv)) { 4981 /* Delete only pvt trie for direct routes */ 4982 rv = alpm_pvt_trie_delete(u, lpm_cfg); 4983 VRF_ROUTE_DEC(acb, vrf_id, ipt); 4984 if (VRF_ROUTE_CNT(acb, vrf_id, ipt) == 0) { 4985 (void)alpm_lib_trie_destroy(ACB_PVT_TRIE(acb, vrf_id, ipt)); 4986 ACB_VRF_INIT_CLEAR(u, acb, vrf_id, ipt); 4987 ACB_DR_INIT_CLEAR(u, acb, vrf_id, ipt); 4988 ACB_PVT_TRIE(acb, vrf_id, ipt) = NULL; 4989 } 4990 } 4991 return rv; 4992 } 4993 4994 ALPM_IER(alpm_util_def_check(u, lpm_cfg, FALSE)); 4995 4996 acb = ACB_VRF_BTM(u, vrf_id); 4997 4998 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt)) { 4999 ALPM_ERR(("**ACB(%d).DELETE:VRF %d/%d is not initialized\n", 5000 ACB_IDX(acb), vrf_id, ipt)); 5001 return BCM_E_NONE; 5002 } 5003 5004 pvt_node = (_alpm_pvt_node_t *)lpm_cfg->pvt_node; 5005 bkt_node = (_alpm_bkt_node_t *)lpm_cfg->bkt_node; 5006 5007 if (bkt_node == NULL) { 5008 _alpm_pvt_node_t *upr_pvt_node = NULL; 5009 _alpm_bkt_node_t *upr_bkt_node = NULL; 5010 5011 (void)alpm_cb_find(u, acb, lpm_cfg, &pvt_node, &bkt_node); 5012 if (!ACB_HAS_TCAM(acb)) { 5013 (void)alpm_cb_find(u, ACB_UPR(u, acb), lpm_cfg, 5014 &upr_pvt_node, &upr_bkt_node); 5015 if (pvt_node && upr_pvt_node) { 5016 if (upr_pvt_node->key_len <= pvt_node->key_len) { 5017 lpm_cfg->pvt_node = (uint32 *)pvt_node; 5018 lpm_cfg->bkt_node = (uint32 *)bkt_node; 5019 lpm_cfg->l1_pvt_node = NULL; 5020 } else { 5021 lpm_cfg->pvt_node = NULL; 5022 lpm_cfg->bkt_node = NULL; 5023 lpm_cfg->l1_pvt_node = (uint32 *)upr_pvt_node; 5024 bkt_node = NULL; 5025 } 5026 } 5027 } else { 5028 lpm_cfg->l1_pvt_node = (uint32 *)pvt_node; 5029 lpm_cfg->pvt_node = (uint32 *)pvt_node; 5030 lpm_cfg->bkt_node = (uint32 *)bkt_node; 5031 } 5032 } 5033 5034 if (bkt_node == NULL) { 5035 lpm_cfg->pvt_node = NULL; 5036 return BCM_E_NOT_FOUND; 5037 } 5038 5039 rv = alpm_cb_delete(u, acb, lpm_cfg); 5040 5041 if (BCM_SUCCESS(rv) && VRF_ROUTE_CNT(acb, vrf_id, ipt) == 0) { 5042 rv = alpm_vrf_deinit(u, vrf_id, ipt); 5043 } 5044 5045 return(rv); 5046 } 5047 5048 /* 5049 * bcm_esw_alpm_update 5050 */ 5051 int 5052 bcm_esw_alpm_update(int u, _bcm_defip_cfg_t *lpm_cfg) 5053 { 5054 int rv; 5055 5056 rv = bcm_esw_alpm_lookup(u, lpm_cfg); 5057 if (BCM_SUCCESS(rv)) { 5058 rv = bcm_esw_alpm_insert(u, lpm_cfg); 5059 } 5060 5061 return rv; 5062 } 5063 5064 /* Get current ALPM route data mode in the VRF and IP type */ 5065 int 5066 bcm_esw_alpm_vrf_data_mode_get(int u, bcm_vrf_t vrf, uint32 flags, 5067 bcm_l3_vrf_route_data_mode_t *mode) 5068 { 5069 int ipt, vrf_id; 5070 _alpm_cb_t *acb; 5071 5072 if (ALPMC(u) && ALPMC(u)->_alpm_inited) { 5073 vrf_id = ALPM_VRF_TO_VRFID(u, vrf); 5074 ipt = (flags & BCM_L3_IP6) ? ALPM_IPT_V6 : ALPM_IPT_V4; 5075 5076 acb = ACB_VRF_BTM(u, vrf_id); 5077 *mode = (bcm_l3_vrf_route_data_mode_t) ACB_VRF_DB_TYPE(u, acb, vrf_id, ipt); 5078 ALPM_INFO(("bcm_esw_alpm_vrf_data_mode_get(VRF:%d) = %d\n", vrf_id, *mode)); 5079 return BCM_E_NONE; 5080 } else { 5081 return BCM_E_UNAVAIL; 5082 } 5083 } 5084 5085 /* Set ALPM route data mode in the VRF and IP type */ 5086 int 5087 bcm_esw_alpm_vrf_data_mode_set(int u, bcm_vrf_t vrf, uint32 flags, 5088 bcm_l3_vrf_route_data_mode_t mode) 5089 { 5090 int i, ipt, vrf_id; 5091 _alpm_cb_t *acb; 5092 bcm_l3_vrf_route_data_mode_t cur_mode; 5093 5094 if (ALPMC(u) && ALPMC(u)->_alpm_inited) { 5095 vrf_id = ALPM_VRF_TO_VRFID(u, vrf); 5096 ipt = (flags & BCM_L3_IP6) ? ALPM_IPT_V6 : ALPM_IPT_V4; 5097 5098 /* Direct routes is always Full mode */ 5099 if (!ALPM_VRF_ID_HAS_BKT(u, vrf_id)) { 5100 if (mode == bcmL3VrfRouteDataModeFull) { 5101 ALPM_INFO(("Direct route is always Full mode (VRF:%d)\n", vrf_id)); 5102 return BCM_E_NONE; 5103 } else { 5104 ALPM_ERR(("Direct route should be always Full mode (VRF:%d)\n", vrf_id)); 5105 return BCM_E_FAIL; 5106 } 5107 } 5108 5109 for (i = 0; i < ACB_CNT(u); i++) { 5110 acb = ACB(u, i); 5111 cur_mode = (bcm_l3_vrf_route_data_mode_t) 5112 ACB_VRF_DB_TYPE(u, acb, vrf_id, ipt); 5113 if (mode == cur_mode) { 5114 return BCM_E_NONE; /* no change */ 5115 } 5116 5117 /* ALPMTBD: initial implementation - 5118 not allow to change once VRF initialized */ 5119 if (ACB_VRF_INITED(u, acb, vrf_id, ipt)) { 5120 ALPM_ERR(("VRF:%d IPT:%d ALPM route data mode unable to change once" 5121 " VRF initialized\n", vrf_id, ipt)); 5122 return BCM_E_FAIL; 5123 } 5124 5125 ACB_VRF_DB_TYPE_SET(u, acb, vrf_id, ipt, (uint8) mode); 5126 alpm_vrf_spl_len_calc(u, acb, vrf_id, (uint8) mode, 5127 &ACB_VRF_SPLEN_DIFF1(u, acb, vrf_id, ipt), 5128 &ACB_VRF_SPLEN_DIFF2(u, acb, vrf_id, ipt)); 5129 5130 } 5131 5132 ALPM_INFO(("bcm_esw_alpm_vrf_data_mode_set(VRF:%d) = %d\n", vrf_id, mode)); 5133 return BCM_E_NONE; 5134 } else { 5135 return BCM_E_UNAVAIL; 5136 } 5137 } 5138 5139 static int 5140 bcm_esw_alpm_pvt_trav_int_cb(alpm_lib_trie_node_t *trie, void *datum) 5141 { 5142 int rv = BCM_E_NONE; 5143 _alpm_pvt_trav_t *trav_st; 5144 _alpm_pvt_node_t *pvt_node; 5145 5146 trav_st = (_alpm_pvt_trav_t *)datum; 5147 if (trie->type == trieNodeTypePayload) { 5148 pvt_node = (_alpm_pvt_node_t *)trie; 5149 rv = trav_st->user_cb(trav_st->acb->unit, trav_st->acb, 5150 pvt_node, trav_st->user_data); 5151 } 5152 5153 return rv; 5154 } 5155 5156 /* Traverse a given pivot trie-tree 5157 */ 5158 int 5159 bcm_esw_alpm_pvt_traverse(int u, int acb_idx, int vrf_id, int ipt, 5160 bcm_esw_alpm_pvt_trav_cb trav_fn, void *user_data) 5161 { 5162 int rv = BCM_E_NONE; 5163 _alpm_cb_t *acb; 5164 _alpm_pvt_trav_t trav_st; 5165 5166 if (!trav_fn) { 5167 return (BCM_E_PARAM); 5168 } 5169 5170 acb = ACB(u, acb_idx); 5171 5172 sal_memset(&trav_st, 0, sizeof(trav_st)); 5173 5174 trav_st.acb = acb; 5175 trav_st.user_cb = trav_fn; 5176 trav_st.user_data = user_data; 5177 5178 rv = alpm_lib_trie_traverse(ACB_PVT_TRIE(acb, vrf_id, ipt), bcm_esw_alpm_pvt_trav_int_cb, 5179 (void *)&trav_st, trieTraverseOrderIn); 5180 return rv; 5181 } 5182 5183 STATIC int 5184 bcm_esw_alpm_pfx_trav_int_cb(alpm_lib_trie_node_t *ptrie, alpm_lib_trie_node_t *trie, 5185 alpm_lib_trie_traverse_state_t *state, void *info) 5186 { 5187 int rv = BCM_E_NONE; 5188 _alpm_pfx_trav_t *trav_st; 5189 _alpm_pfx_node_t *pfx_node; 5190 5191 /* Reset state everytime */ 5192 *state = trieTraverseStateNone; 5193 5194 trav_st = (_alpm_pfx_trav_t *)info; 5195 if (trie->type == trieNodeTypePayload) { 5196 pfx_node = (_alpm_pfx_node_t *)trie; 5197 rv = trav_st->user_cb(pfx_node, trav_st->user_data); 5198 } 5199 5200 return rv; 5201 } 5202 5203 /* Traverse a given prefix trie-tree 5204 */ 5205 int 5206 bcm_esw_alpm_pfx_traverse(int u, int vrf_id, int ipt, 5207 bcm_esw_alpm_pfx_trav_cb trav_fn, void *user_data) 5208 { 5209 _alpm_pfx_trav_t trav_st; 5210 5211 if (!trav_fn) { 5212 return (BCM_E_PARAM); 5213 } 5214 5215 sal_memset(&trav_st, 0, sizeof(trav_st)); 5216 5217 trav_st.user_cb = trav_fn; 5218 trav_st.user_data = user_data; 5219 5220 /* Use delete safe _trie_postorder_traverse2() for update_match */ 5221 alpm_lib_trie_traverse2(ALPM_VRF_TRIE(u, vrf_id, ipt), bcm_esw_alpm_pfx_trav_int_cb, 5222 (void *)&trav_st, trieTraverseOrderPost); 5223 5224 return BCM_E_NONE; 5225 } 5226 5227 STATIC int 5228 bcm_esw_alpm_bkt_trav_int_cb(alpm_lib_trie_node_t *trie, void *datum) 5229 { 5230 int rv = BCM_E_NONE; 5231 _alpm_bkt_trav_t *trav_st; 5232 _alpm_bkt_node_t *bkt_node; 5233 5234 trav_st = (_alpm_bkt_trav_t *)datum; 5235 if (trie->type == trieNodeTypePayload) { 5236 bkt_node = (_alpm_bkt_node_t *)trie; 5237 rv = trav_st->user_cb(bkt_node, trav_st->user_data); 5238 } 5239 5240 return rv; 5241 } 5242 5243 /* Traverse a given bkt trie-tree 5244 */ 5245 int 5246 bcm_esw_alpm_bkt_traverse(alpm_lib_trie_t *bkt_trie, 5247 bcm_esw_alpm_bkt_trav_cb trav_fn, void *user_data) 5248 { 5249 _alpm_bkt_trav_t trav_st; 5250 5251 if (!trav_fn) { 5252 return (BCM_E_PARAM); 5253 } 5254 5255 sal_memset(&trav_st, 0, sizeof(trav_st)); 5256 5257 trav_st.user_cb = trav_fn; 5258 trav_st.user_data = user_data; 5259 5260 alpm_lib_trie_traverse(bkt_trie, bcm_esw_alpm_bkt_trav_int_cb, 5261 (void *)&trav_st, trieTraverseOrderIn); 5262 5263 return BCM_E_NONE; 5264 } 5265 5266 /* Get count for given pivot trie-tree */ 5267 int 5268 bcm_esw_alpm_pvt_count_get(int u, _alpm_pvt_node_t *pvt_node, int *count) 5269 { 5270 int rv = BCM_E_NONE; 5271 if (count && PVT_BKT_TRIE(pvt_node) && PVT_BKT_TRIE(pvt_node)->trie) { 5272 *count = PVT_BKT_TRIE(pvt_node)->trie->count; 5273 } else { 5274 rv = BCM_E_PARAM; 5275 } 5276 5277 return rv; 5278 } 5279 5280 5281 /* Trouble-shooting helper functions */ 5282 5283 static int 5284 alpm_cb_pvt_dump_cb(int u, _alpm_cb_t *acb, 5285 _alpm_pvt_node_t *pvt_node, void *datum) 5286 { 5287 int i, j, count = 0; 5288 int index; /* for next level bkt index */ 5289 int idx, sub_idx; 5290 _alpm_bkt_info_t *bkt_info; 5291 char vet_str[ALPM_BPB_MAX*2+2] = {0}; 5292 alpm_pvt_trav_cb_data_t *cb_data; 5293 5294 cb_data = (alpm_pvt_trav_cb_data_t *)datum; 5295 (void)bcm_esw_alpm_pvt_count_get(u, pvt_node, &count); 5296 5297 bkt_info = &PVT_BKT_INFO(pvt_node); 5298 if (cb_data->bkt_idx == -1 || 5299 cb_data->bkt_idx == PVT_BKT_IDX(pvt_node)) { 5300 ALPM_IER(alpm_util_pvt_idx_get(u, acb, pvt_node, &idx, &sub_idx)); 5301 cli_out("Level%d pvt_idx:%d.%d | bkt_info rofs:%d idx:%d total %d\n", 5302 acb->acb_idx + 1, idx, sub_idx, 5303 PVT_ROFS(pvt_node), PVT_BKT_IDX(pvt_node), count); 5304 for (i = 0; i < ACB_BNK_PER_BKT(acb, PVT_BKT_VRF(pvt_node)); i++) { 5305 for (j = 0; j < 16; j++) { 5306 if (bkt_info->vet_bmp[i] & (1 << j)) { 5307 vet_str[j] = '*'; 5308 } else { 5309 vet_str[j] = '_'; 5310 } 5311 } 5312 index = ALPM_TAB_IDX_GET_BKT_BNK(acb, PVT_ROFS(pvt_node), 5313 PVT_BKT_IDX(pvt_node), i); 5314 if (bkt_info->bnk_fmt[i] != 0) { 5315 cli_out("----> Bank %d: FMT%d[%s] index:%5d\n", i, 5316 bkt_info->bnk_fmt[i], vet_str, index); 5317 } 5318 } 5319 } 5320 5321 return 0; 5322 } 5323 5324 void 5325 alpm_cb_pvt_dump(int u, int acb_bmp, int bkt_idx) 5326 { 5327 int i, vrf_id, ipt; 5328 _alpm_cb_t *acb; 5329 alpm_pvt_trav_cb_data_t *cb_data; 5330 5331 if (ALPMC(u) == NULL) { 5332 return ; 5333 } 5334 5335 cb_data = sal_alloc(sizeof(alpm_pvt_trav_cb_data_t), "cb_data"); 5336 if (cb_data == NULL) { 5337 return ; 5338 } 5339 5340 for (i = 0; i < ACB_CNT(u); i++) { 5341 if (!(acb_bmp & (1 << i))) { 5342 continue; 5343 } 5344 acb = ACB(u, i); 5345 cb_data->unit = u; 5346 cb_data->acb = acb; 5347 cb_data->bkt_idx = bkt_idx; 5348 for (ipt = 0; ipt < ALPM_IPT_CNT; ipt ++) { 5349 for (vrf_id = 0; vrf_id < ALPM_VRF_ID_CNT(u); vrf_id ++) { 5350 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt)) { 5351 continue; 5352 } 5353 cli_out("ALPM CB[%d] Dumping Pivot vrf_id %d, ipt %s\n", i, 5354 vrf_id, alpm_util_ipt_str[ipt]); 5355 (void)bcm_esw_alpm_pvt_traverse(u, i, vrf_id, ipt, 5356 alpm_cb_pvt_dump_cb, cb_data); 5357 } 5358 } 5359 } 5360 5361 sal_free(cb_data); 5362 5363 return ; 5364 } 5365 5366 static int 5367 alpm_cb_bkt_dump_cb(int u, _alpm_cb_t *acb, 5368 _alpm_pvt_node_t *pvt_node, void *datum) 5369 { 5370 int rv = BCM_E_NONE; 5371 int i, j, ent_bit, ent_shift; 5372 uint8 bnk_fmt; 5373 5374 _alpm_bkt_info_t *bkt_info; 5375 alpm_pvt_trav_cb_data_t *cb_data; 5376 5377 #define _ENT_BITS 5 5378 5379 cb_data = (alpm_pvt_trav_cb_data_t *)datum; 5380 ent_shift = _shr_popcount(ALPM_BPB_MAX - 1) + _ENT_BITS; 5381 bkt_info = &PVT_BKT_INFO(pvt_node); 5382 SHR_BITSET(cb_data->bkt, PVT_BKT_IDX(pvt_node)); 5383 5384 for (i = 0; i < ALPM_BPB_MAX; i++) { 5385 bnk_fmt = bkt_info->bnk_fmt[i]; 5386 if (BI_BNK_IS_USED(bkt_info, i)) { 5387 int bnk_idx; 5388 if (i < PVT_ROFS(pvt_node)) { 5389 bnk_idx = 5390 ((PVT_BKT_IDX(pvt_node) + 1) << 5391 _shr_popcount(ALPM_BPB_MAX - 1) | i); 5392 } else { 5393 bnk_idx = 5394 (PVT_BKT_IDX(pvt_node) << 5395 _shr_popcount(ALPM_BPB_MAX - 1) | i); 5396 } 5397 SHR_BITSET(cb_data->bnk, bnk_idx); 5398 cb_data->bnkfmt[bnk_idx] = bnk_fmt; 5399 } 5400 for (j = 0; j < sizeof(bkt_info->vet_bmp[0]) * 8; j++) { 5401 if (SHR_BITGET(&bkt_info->vet_bmp[i], j)) { 5402 ent_bit = (i << _ENT_BITS) | j; 5403 if (i < PVT_ROFS(pvt_node)) { 5404 ent_bit = ((PVT_BKT_IDX(pvt_node) + 1) << ent_shift) | ent_bit; 5405 } else { 5406 ent_bit = (PVT_BKT_IDX(pvt_node) << ent_shift) | ent_bit; 5407 } 5408 SHR_BITSET(cb_data->ent, ent_bit); 5409 } 5410 } 5411 } 5412 5413 return rv; 5414 } 5415 5416 static void 5417 alpm_cb_bkt_pool_dump(int u, int ipt, _alpm_cb_t *acb, 5418 _alpm_bkt_pool_conf_t *bp_conf, 5419 char *prefix) 5420 { 5421 int j, k; 5422 int bnk_cnt, total_bnk_cnt, bkt_cnt; 5423 SHR_BITDCL *bnk_bmp = BPC_BNK_BMP(bp_conf, ipt); 5424 5425 #define BKT_PER_BLK 64 5426 5427 bkt_cnt = ACB_BKT_CNT(acb); 5428 5429 cli_out(" %s %s BANK POOL USAGE\n", prefix, alpm_util_ipt_str[ipt]); 5430 cli_out("------------------------------------------------------------" 5431 "-------------------------------\n"); 5432 for (j = 0; j < bkt_cnt / BKT_PER_BLK; j++) { 5433 int tmp_bnk = 0; 5434 total_bnk_cnt = 0; 5435 cli_out("BKT%04d-%04d [", j * BKT_PER_BLK, (j+1) * BKT_PER_BLK - 1); 5436 for (k = j * BKT_PER_BLK; k < (j+1) * BKT_PER_BLK; k++) { 5437 SHR_BITCOUNT_RANGE(bnk_bmp, bnk_cnt, 5438 k * BPC_BNK_PER_BKT(bp_conf), BPC_BNK_PER_BKT(bp_conf)); 5439 total_bnk_cnt += bnk_cnt; 5440 if (bnk_cnt >= 16) { 5441 cli_out("@"); 5442 } else { 5443 cli_out("%x", bnk_cnt); 5444 } 5445 } 5446 tmp_bnk = 5447 total_bnk_cnt * 1000 / (BPC_BNK_PER_BKT(bp_conf) * BKT_PER_BLK); 5448 cli_out("] %2d.%d%%\n", tmp_bnk / 10, tmp_bnk % 10); 5449 } 5450 } 5451 5452 static void 5453 alpm_cb_bkt_bnk_dump(int u, int ipt, _alpm_cb_t *acb, 5454 _alpm_bkt_pool_conf_t *bp_conf, char *prefix) 5455 { 5456 int rv = BCM_E_NONE, j, k, bnk, vrf_id, ipt1; 5457 int vrf_min, vrf_max; 5458 int bnk_cnt, total_bnk_cnt; 5459 int ent_cnt, total_ent_cnt, max_ent_cnt; 5460 int bkt_cnt; 5461 5462 alpm_pvt_trav_cb_data_t *cdata = NULL; 5463 5464 #define BKT_PER_BLK 64 5465 #define _ENT_BITS 5 5466 5467 bkt_cnt = ACB_BKT_CNT(acb); 5468 5469 ALPM_ALLOC_EG(cdata, sizeof(*cdata), "bktusage"); 5470 5471 if (ACB_BKT_VRF_POOL(acb, ALPM_VRF_ID_GLO(u)) == 5472 ACB_BKT_VRF_POOL(acb, 1)) { 5473 vrf_min = 0; 5474 vrf_max = ALPM_VRF_ID_GLO(u); 5475 } else if (bp_conf == ACB_BKT_VRF_POOL(acb, ALPM_VRF_ID_GLO(u))) { 5476 vrf_min = ALPM_VRF_ID_GLO(u); 5477 vrf_max = ALPM_VRF_ID_GLO(u); 5478 } else { 5479 vrf_min = 0; 5480 vrf_max = ALPMC(u)->_alpm_max_vrf_id; 5481 } 5482 5483 for (ipt1 = ipt; ipt1 < ALPM_IPT_CNT; ipt1++) { 5484 if ((ipt1 == ipt) || 5485 (ipt1 > ipt && /* same pool case (V4/V6) */ 5486 BPC_BNK_INFO(bp_conf, ipt1) == 5487 BPC_BNK_INFO(bp_conf, ipt1 - 1))) { 5488 5489 for (vrf_id = vrf_min; vrf_id <= vrf_max; vrf_id++) { 5490 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt1)) { 5491 continue; 5492 } 5493 (void)bcm_esw_alpm_pvt_traverse(u, acb->acb_idx, vrf_id, ipt1, 5494 alpm_cb_bkt_dump_cb, cdata); 5495 } 5496 } 5497 } 5498 5499 cli_out(" BKT RANGE |[---------------- banks used per bucket(%7s %3s) -" 5500 "-----------] AVGBK AVGET\n", prefix, alpm_util_ipt_str[ipt]); 5501 cli_out("------------------------------------------------------------" 5502 "-------------------------------\n"); 5503 for (j = 0; j < bkt_cnt / BKT_PER_BLK; j++) { 5504 int tmp_bnk, tmp_ent; 5505 total_bnk_cnt = 0; 5506 total_ent_cnt = 0; 5507 max_ent_cnt = 0; 5508 cli_out("BKT%04d-%04d [", j * BKT_PER_BLK, (j+1) * BKT_PER_BLK - 1); 5509 for (k = j * BKT_PER_BLK; k < (j+1) * BKT_PER_BLK; k++) { 5510 if (SHR_BITGET(cdata->bkt, k)) { 5511 SHR_BITCOUNT_RANGE(cdata->bnk, bnk_cnt, 5512 k << _shr_popcount(ALPM_BPB_MAX - 1), ALPM_BPB_MAX); 5513 total_bnk_cnt += bnk_cnt; 5514 if (bnk_cnt >= 16) { 5515 cli_out("@"); 5516 } else { 5517 cli_out("%x", bnk_cnt); 5518 } 5519 } else { 5520 cli_out("%s", "_"); 5521 } 5522 for (bnk = 0; bnk < BPC_BNK_PER_BKT(bp_conf); bnk++) { 5523 int bnk_idx = 5524 (k << _shr_popcount(ALPM_BPB_MAX - 1) | bnk); 5525 SHR_BITCOUNT_RANGE(cdata->ent, ent_cnt, bnk_idx << _ENT_BITS, (2 << (_ENT_BITS - 1))); 5526 total_ent_cnt += ent_cnt; 5527 max_ent_cnt += BPC_FMT_ENT_MAX(bp_conf, cdata->bnkfmt[bnk_idx]); 5528 } 5529 } 5530 tmp_bnk = 5531 total_bnk_cnt * 1000 / (BPC_BNK_PER_BKT(bp_conf) * BKT_PER_BLK); 5532 tmp_ent = (max_ent_cnt > 0) 5533 ? total_ent_cnt * 1000 / max_ent_cnt 5534 : 0; 5535 cli_out("] %2d.%d%% %2d.%d%%\n", tmp_bnk / 10, tmp_bnk % 10, 5536 tmp_ent / 10, tmp_ent % 10); 5537 } 5538 5539 alpm_util_free(cdata); 5540 5541 bad: 5542 if (BCM_FAILURE(rv)) { 5543 ALPM_ERR(("alpm_cb_bkt_bnk_dump error %d\n", rv)); 5544 } 5545 return; 5546 5547 } 5548 5549 /* 5550 * 0-8/0-5 : count of occupied banks) 5551 * _ : free bucket 5552 * 30% : average bank percentage per 64 bucket 5553 * 40% : average entry percentage per 64 bucket 5554 * 5555 * BKT0000-0063 [32458___________] 30% 40% 5556 * BKT0064-0127 [_3133___________] 30% 40% 5557 */ 5558 void 5559 alpm_cb_bkt_dump(int u, int acb_bmp) 5560 { 5561 int i, ipt; 5562 _alpm_cb_t *acb; 5563 _alpm_bkt_pool_conf_t *gbl_bp = NULL; 5564 _alpm_bkt_pool_conf_t *prt_bp = NULL; 5565 5566 #define BKT_PER_BLK 64 5567 5568 if (ALPMC(u) == NULL) { 5569 return ; 5570 } 5571 5572 for (i = 0; i < ACB_CNT(u); i++) { 5573 if (!(acb_bmp & (1 << i))) { 5574 continue; 5575 } 5576 cli_out("ALPM CB[%d] Dumping BUCKET usage:\n", i); 5577 5578 acb = ACB(u, i); 5579 gbl_bp = ACB_BKT_VRF_POOL(acb, ALPM_VRF_ID_GLO(u)); 5580 prt_bp = ACB_BKT_VRF_POOL(acb, 1); 5581 5582 for (ipt = ALPM_IPT_V4; ipt < ALPM_IPT_CNT; ipt++) { 5583 if (ipt > ALPM_IPT_V4 && 5584 BPC_BNK_INFO(gbl_bp, ipt) == 5585 BPC_BNK_INFO(gbl_bp, ipt - 1)) { 5586 continue; 5587 } 5588 alpm_cb_bkt_pool_dump(u, ipt, acb, gbl_bp, 5589 gbl_bp == prt_bp ? "GLOBAL/PRIVATE" : "GLOBAL"); 5590 alpm_cb_bkt_bnk_dump(u, ipt, acb, gbl_bp, 5591 gbl_bp == prt_bp ? "GLO/PRI" : "GLOBAL"); 5592 } 5593 5594 if (gbl_bp == prt_bp) { 5595 continue; 5596 } 5597 5598 for (ipt = ALPM_IPT_V4; ipt < ALPM_IPT_CNT; ipt++) { 5599 if (ipt > ALPM_IPT_V4 && 5600 BPC_BNK_INFO(prt_bp, ipt) == 5601 BPC_BNK_INFO(prt_bp, ipt - 1)) { 5602 continue; 5603 } 5604 5605 alpm_cb_bkt_pool_dump(u, ipt, acb, prt_bp, "PRIVATE"); 5606 alpm_cb_bkt_bnk_dump(u, ipt, acb, prt_bp, "PRIVATE"); 5607 } 5608 } 5609 5610 return ; 5611 } 5612 5613 static int 5614 alpm_cb_fmt_dump_cb(int u, _alpm_cb_t *acb, 5615 _alpm_pvt_node_t *pvt_node, void *datum) 5616 { 5617 int i; 5618 _alpm_bkt_info_t *bkt_info; 5619 uint32 *fmt = (uint32 *)datum; 5620 uint8 bnk_fmt; 5621 5622 bkt_info = &PVT_BKT_INFO(pvt_node); 5623 for (i = 0; i < ALPM_BPB_MAX; i++) { 5624 bnk_fmt = bkt_info->bnk_fmt[i]; 5625 if (BI_BNK_IS_USED(bkt_info, i)) { 5626 fmt[bnk_fmt] ++; 5627 } 5628 } 5629 5630 return 0; 5631 } 5632 5633 /* 5634 * Pivot CB: 5635 * FMT 1: 10% (1) 5636 * FMT 2: 0% 5637 * FMT 3: 83% 5638 * FMT 4: 5639 * FMT 5: 5640 * FMT 6: 5641 * FMT 7: 5642 * FMT 8: 5643 * 5644 * Route CB: 5645 * FMT 1: 2O% 5646 * FMT 2: 5647 * ... 5648 * FMT 12: 5649 */ 5650 void 5651 alpm_cb_fmt_dump(int u, int acb_bmp) 5652 { 5653 int i, j, pid, vrf_id, ipt, fmt_sum; 5654 _alpm_cb_t *acb; 5655 uint32 fmt[2][16]; 5656 5657 if (ALPMC(u) == NULL) { 5658 return ; 5659 } 5660 5661 sal_memset(fmt, 0, sizeof(fmt)); 5662 for (i = 0; i < ACB_CNT(u); i++) { 5663 if (!(acb_bmp & (1 << i))) { 5664 continue; 5665 } 5666 5667 acb = ACB(u, i); 5668 5669 for (pid = 0; pid < ALPM_BKT_PID_CNT; pid++) { 5670 _alpm_bkt_pool_conf_t *bp_conf; 5671 bp_conf = ACB_BKT_POOL(acb, pid); 5672 5673 if (pid > 0 && 5674 ACB_BKT_POOL(acb, pid-1) == ACB_BKT_POOL(acb, pid)) { 5675 continue; 5676 } 5677 5678 cli_out("ALPM CB[%d.%d %s] Dumping FMT distribution:\n", i, pid, 5679 BPC_FMT_TYPE(bp_conf) == ALPM_FMT_RTE ? "Route" : "Pivot"); 5680 for (ipt = 0; ipt < ALPM_IPT_CNT; ipt ++) { 5681 for (vrf_id = 0; vrf_id < ALPM_VRF_ID_CNT(u); vrf_id ++) { 5682 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt)) { 5683 continue; 5684 } 5685 (void)bcm_esw_alpm_pvt_traverse(u, i, vrf_id, ipt, 5686 alpm_cb_fmt_dump_cb, fmt[i]); 5687 } 5688 } 5689 5690 fmt_sum = 0; 5691 for (j = 1; j <= BPC_FMT_CNT(bp_conf); j++) { 5692 fmt_sum += fmt[i][j]; 5693 } 5694 5695 /* Avoid Floating point exception */ 5696 if (fmt_sum == 0) { 5697 fmt_sum = 0xdeadbee; 5698 } 5699 5700 if (fmt_sum == 0xdeadbee) { 5701 cli_out("\tAll ZERO\n\n"); 5702 continue; 5703 } 5704 5705 for (j = 1; j <= BPC_FMT_CNT(bp_conf); j++) { 5706 if (fmt[i][j] != 0) { 5707 cli_out("\tFMT %2d(Len %3d): %2d.%d%% (Count %d)\n", j, 5708 BPC_FMT_PFX_LEN(bp_conf, j), 5709 fmt[i][j] * 100 / fmt_sum, 5710 (fmt[i][j] * 1000 / fmt_sum) % 10, 5711 fmt[i][j]); 5712 } 5713 } 5714 } 5715 } 5716 5717 return ; 5718 } 5719 5720 static int 5721 alpm_cb_pvtlen_dump_cb(int u, _alpm_cb_t *acb, 5722 _alpm_pvt_node_t *pvt_node, void *datum) 5723 { 5724 uint32 *pvt_len = (uint32 *)datum; 5725 5726 if (pvt_node && PVT_KEY_LEN(pvt_node) <= 128) { 5727 pvt_len[PVT_KEY_LEN(pvt_node)]++; 5728 } 5729 5730 return 0; 5731 } 5732 5733 /* 5734 * Pivot CB: 5735 * Pivot Len 0: 10% (1) 5736 * ...... 5737 * Pivot Len 128: 20% (2) 5738 * 5739 * Route CB: 5740 * ...... 5741 */ 5742 void 5743 alpm_cb_pvtlen_dump(int u, int acb_bmp) 5744 { 5745 int i, j, k, vrf_id, ipt, pvt_len_sum[2]; 5746 _alpm_cb_t *acb; 5747 uint32 pvt_len[2][129]; 5748 5749 if (ALPMC(u) == NULL) { 5750 return ; 5751 } 5752 5753 for (i = 0; i < ACB_CNT(u); i++) { 5754 if (!(acb_bmp & (1 << i))) { 5755 continue; 5756 } 5757 5758 acb = ACB(u, i); 5759 sal_memset(pvt_len, 0, sizeof(pvt_len)); 5760 for (ipt = 0; ipt < ALPM_IPT_CNT; ipt ++) { 5761 for (vrf_id = 0; vrf_id < ALPM_VRF_ID_CNT(u); vrf_id ++) { 5762 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt)) { 5763 continue; 5764 } 5765 (void)bcm_esw_alpm_pvt_traverse(u, i, vrf_id, ipt, 5766 alpm_cb_pvtlen_dump_cb, 5767 pvt_len[ACB_FMT_TYPE(acb, vrf_id)]); 5768 } 5769 } 5770 5771 for (k = 0; k < 2; k++) { 5772 pvt_len_sum[k] = 0; 5773 for (j = 0; j <= 128; j++) { 5774 pvt_len_sum[k] += pvt_len[k][j]; 5775 } 5776 /* Avoid Floating point exception */ 5777 if (pvt_len_sum[k] == 0) { 5778 pvt_len_sum[k] = 0xdeadbee; 5779 } 5780 if (pvt_len_sum[k] == 0xdeadbee) { 5781 continue; 5782 } 5783 5784 cli_out("ALPM CB[%d %s] Dumping Pivot Length distribution:\n", i, 5785 k == 0 ? "Pivot" : "Route"); 5786 for (j = 0; j <= 128; j++) { 5787 if (pvt_len[k][j] != 0) { 5788 cli_out("\tPVT_LEN %3d: %2d.%d%% (Count %d)\n", j, 5789 pvt_len[k][j] * 100 / pvt_len_sum[k], 5790 (pvt_len[k][j] * 1000 / pvt_len_sum[k]) % 10, 5791 pvt_len[k][j]); 5792 } 5793 } 5794 } 5795 } 5796 5797 return ; 5798 } 5799 5800 /* BCM.0>alpm stat show <1|2|3> */ 5801 void 5802 alpm_cb_stat_dump(int u, int acb_bmp) 5803 { 5804 int i, j, p, ipt; 5805 uint32 alloc_cnt, free_cnt, dbg_bmp, dbg_on = 0; 5806 _alpm_cb_t *acb; 5807 _alpm_bkt_pool_conf_t *bp_conf = NULL; 5808 5809 #define _DBG_BMP_STR_CNT 10 5810 char *dbg_bmp_str[_DBG_BMP_STR_CNT] = { 5811 "PvtSanity", 5812 "PvtSanityLen", 5813 "PvtDefrag", 5814 "PvtSanityNode", 5815 "PvtSanityCount", 5816 "WriteCacheOnly", 5817 "BnkConf", 5818 "PvtUpdateSkip", 5819 "HitBit", 5820 "" 5821 }; 5822 5823 if (ALPMC(u) == NULL) { 5824 return ; 5825 } 5826 5827 dbg_bmp = ALPMC(u)->_alpm_dbg_bmp; 5828 5829 cli_out("ALPM debug:\n"); 5830 for (i = 0; i < _DBG_BMP_STR_CNT; i++) { 5831 if (dbg_bmp & (1 << i)) { 5832 cli_out("\tbit %d %s\n", i, dbg_bmp_str[i]); 5833 dbg_on = 1; 5834 } 5835 } 5836 if (!dbg_on) { 5837 cli_out("\toff\n"); 5838 } 5839 5840 cli_out("ALPM recorded error messages:\n"); 5841 for (i = 0; i < _ALPM_ERR_MSG_CUR_IDX(u); i++) { 5842 cli_out("%3d: %s", i, _ALPM_ERR_MSG_ENT(u, i)); 5843 } 5844 cli_out("\n"); 5845 5846 alpm_util_mem_stat_get(&alloc_cnt, &free_cnt); 5847 cli_out("ALPM Host mem: alloc %8d free %8d\n", alloc_cnt, free_cnt); 5848 for (i = 0; i < ACB_CNT(u); i++) { 5849 if (!(acb_bmp & (1 << i))) { 5850 continue; 5851 } 5852 cli_out("ALPM CB[%d] Statistics:\n\n", i); 5853 acb = ACB(u, i); 5854 5855 if (ACB_HAS_TCAM(acb)) { 5856 bcm_esw_alpm_tcam_zone_dump(u, "\t"); 5857 cli_out("\n"); 5858 } 5859 5860 #define _BKT_POOL_USAGE_PRINT(acb_idx, pid, bp_conf, ipt) \ 5861 cli_out("\tBucket Pool %d(%s) Usage(Level%d): %6d/%6d = %d.%d%%\n", \ 5862 pid, alpm_util_ipt_str[ipt], acb_idx + 2, \ 5863 BPC_BNK_USED(bp_conf, ipt), \ 5864 BPC_BNK_CNT(bp_conf), \ 5865 BPC_BNK_CNT(bp_conf) ? \ 5866 (BPC_BNK_USED(bp_conf, ipt) * 100 / BPC_BNK_CNT(bp_conf)) : 0, \ 5867 BPC_BNK_CNT(bp_conf) ? \ 5868 ((BPC_BNK_USED(bp_conf, ipt) * 1000 / BPC_BNK_CNT(bp_conf)) % 10) : 0); 5869 for (p = 0; p < ALPM_BKT_PID_CNT; p++) { 5870 bp_conf = ACB_BKT_POOL(acb, p); 5871 if (p > 0 && bp_conf == ACB_BKT_POOL(acb, p-1)) { 5872 continue; 5873 } 5874 for (ipt = ALPM_IPT_V4; ipt < ALPM_IPT_CNT; ipt++) { 5875 if (ipt > ALPM_IPT_V4 && 5876 BPC_BNK_INFO(bp_conf, ipt) == 5877 BPC_BNK_INFO(bp_conf, ipt - 1)) { 5878 continue; 5879 } 5880 _BKT_POOL_USAGE_PRINT(acb->acb_idx, p, bp_conf, ipt) 5881 } 5882 } 5883 5884 cli_out("\tMemory Stats: \n"); 5885 for (j = 0; j < alpmTblCount; j++) { 5886 if (acb->acb_cnt.c_mem[j][0] != 0 || acb->acb_cnt.c_mem[j][1] != 0) { 5887 cli_out("\t %22s: RD %10d WR %10d\n", alpm_tbl_str[j], 5888 acb->acb_cnt.c_mem[j][0], 5889 acb->acb_cnt.c_mem[j][1]); 5890 } 5891 } 5892 cli_out("\tDefrag : %8d\n", acb->acb_cnt.c_defrag); 5893 cli_out("\tMerge : %8d\n", acb->acb_cnt.c_merge); 5894 cli_out("\tExpand : %8d\n", acb->acb_cnt.c_expand); 5895 cli_out("\tSplit : %8d\n", acb->acb_cnt.c_split); 5896 cli_out("\tRipple : %8d\n", acb->acb_cnt.c_ripple); 5897 cli_out("\tBNKshrk: %8d\n", acb->acb_cnt.c_bnkshrk); 5898 cli_out("\tBNKfree: %8d\n", acb->acb_cnt.c_bnkfree); 5899 cli_out("\tSMCS1 : %8d\n", acb->acb_cnt.c_spl_mp_cs1); 5900 cli_out("\tSMCS21 : %8d\n", acb->acb_cnt.c_spl_mp_cs21); 5901 cli_out("\tSMCS221: %8d\n", acb->acb_cnt.c_spl_mp_cs221); 5902 cli_out("\tSMCS222: %8d\n", acb->acb_cnt.c_spl_mp_cs222); 5903 cli_out("\tFULL: %8d\n", acb->acb_cnt.c_full); 5904 cli_out("\n"); 5905 } 5906 } 5907 5908 /* BCM.0>alpm config show <1|2|3> */ 5909 void 5910 alpm_cb_conf_dump(int u, int acb_bmp) 5911 { 5912 int i, pid, ipt, fmt; 5913 _alpm_cb_t *acb; 5914 5915 if (ALPMC(u) == NULL) { 5916 return ; 5917 } 5918 5919 for (i = 0; i < ACB_CNT(u); i++) { 5920 if (!(acb_bmp & (1 << i))) { 5921 continue; 5922 } 5923 cli_out("ALPM CB[%d] Bank Config:\n", i); 5924 acb = ACB(u, i); 5925 5926 cli_out("\t bkt_bits: %d\n", ACB_BKT_BITS(acb)); 5927 cli_out("\t bkt_cnt: %d\n", ACB_BKT_CNT(acb)); 5928 5929 for (pid = 0; pid < ALPM_BKT_PID_CNT; pid++) { 5930 _alpm_bkt_pool_conf_t *bp_conf; 5931 5932 if (pid > 0 && 5933 ACB_BKT_POOL(acb, pid-1) == ACB_BKT_POOL(acb, pid)) { 5934 continue; 5935 } 5936 5937 bp_conf = ACB_BKT_POOL(acb, pid); 5938 for (ipt = ALPM_IPT_V4; ipt < ALPM_IPT_CNT; ipt++) { 5939 if (ipt > ALPM_IPT_V4 && 5940 BPC_BNK_INFO(bp_conf, ipt) == 5941 BPC_BNK_INFO(bp_conf, ipt - 1)) { 5942 continue; 5943 } 5944 cli_out("\t%d.bnk_pool.%d: %p\n", ipt, pid, BPC_BNK_BMP(bp_conf, ipt)); 5945 cli_out("\t%d.bnk_used.%d: %d\n", ipt, pid, BPC_BNK_USED(bp_conf, ipt)); 5946 cli_out("\t%d.bnk_rsvd.%d: %d\n", ipt, pid, BPC_BNK_RSVD(bp_conf, ipt)); 5947 } 5948 5949 cli_out("\t bnk_total.%d: %d\n", pid, BPC_BNK_CNT(bp_conf)); 5950 cli_out("\t bnk_pbkt.%d: %d\n", pid, BPC_BNK_PER_BKT(bp_conf)); 5951 cli_out("\t wrap_arnd.%d: %d\n", pid, BPC_BKT_WRA(bp_conf)); 5952 cli_out("\t fixed_fmt.%d: %d\n", pid, BPC_BKT_FIXED_FMT(bp_conf)); 5953 cli_out("\t fmt_cnt.%d: %d\n", pid, BPC_FMT_CNT(bp_conf)); 5954 5955 cli_out("\t----------------------------------------------------\n"); 5956 cli_out("\tFV |"); 5957 for (fmt = 0; fmt <= BPC_FMT_CNT(bp_conf); fmt++) { 5958 cli_out("%3d|", fmt); 5959 } 5960 cli_out("\n"); 5961 cli_out("\t----------------------------------------------------\n"); 5962 cli_out("\tCAP|"); 5963 for (fmt = 0; fmt <= BPC_FMT_CNT(bp_conf); fmt++) { 5964 cli_out("%3d|", BPC_FMT_ENT_MAX(bp_conf, fmt)); 5965 } 5966 cli_out("\n"); 5967 cli_out("\t----------------------------------------------------\n"); 5968 cli_out("\tPfL|"); 5969 for (fmt = 0; fmt <= BPC_FMT_CNT(bp_conf); fmt++) { 5970 cli_out("%3d|", BPC_FMT_PFX_LEN(bp_conf, fmt)); 5971 } 5972 cli_out("\n"); 5973 cli_out("\t----------------------------------------------------\n"); 5974 5975 } 5976 } 5977 } 5978 5979 int alpm_table_dump(int u, int vrf_id, soc_mem_t mem, int copyno, int index, 5980 int fmt, int ent_idx, int flags) 5981 { 5982 return ALPM_DRV(u)->alpm_table_dump(u, vrf_id, mem, copyno, index, fmt, ent_idx, flags); 5983 } 5984 5985 static int 5986 alpm_cb_ent_pfx_len_get(int u, _alpm_cb_t *acb, 5987 _alpm_pvt_node_t *pvt_node, int ent_idx) 5988 { 5989 return ALPM_DRV(u)->alpm_ent_pfx_len_get(u, acb, pvt_node, ent_idx); 5990 } 5991 5992 int 5993 alpm_cb_pvt_sanity_cb(int u, _alpm_cb_t *acb, 5994 _alpm_pvt_node_t *pvt_node, void *datum) 5995 { 5996 int a, i, rv = BCM_E_NONE; 5997 int bkt_node_cnt, bkt_info_cnt; 5998 int vrf_id, ipt, err = 0; 5999 int end_bnk, bnkpb, bnk_cnt; 6000 6001 char *pfx_str = datum; 6002 alpm_lib_trie_t *bkt_trie = NULL; 6003 _alpm_cb_t *acb_tmp = NULL; 6004 _alpm_bkt_info_t *bkt_info; 6005 _alpm_bkt_pfx_arr_t *pfx_arr = NULL; 6006 _alpm_bkt_node_t *bkt_node; 6007 6008 bkt_info = &PVT_BKT_INFO(pvt_node); 6009 bkt_trie = PVT_BKT_TRIE(pvt_node); 6010 vrf_id = PVT_BKT_VRF(pvt_node); 6011 ipt = PVT_BKT_IPT(pvt_node); 6012 bnkpb = ACB_BNK_PER_BKT(acb, vrf_id); 6013 6014 if (ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_PTR_CHK) { 6015 #define CORRUPT(p) \ 6016 (p[-1] != 0xaaaaaaaa || \ 6017 p[p[-2]] != 0xbbbbbbbb) 6018 6019 int pid, pvt_cnt; 6020 for (a = 0; a < ACB_CNT(u); a++) { 6021 acb_tmp = ACB(u, a); 6022 for (pid = 0; pid < ALPM_BKT_PID_CNT; pid++) { 6023 _alpm_bkt_pool_conf_t *bp_conf; 6024 uint32 *pvt_ptr; 6025 6026 if (pid > 0 && 6027 ACB_BKT_POOL(acb_tmp, pid-1) == 6028 ACB_BKT_POOL(acb_tmp, pid)) { 6029 continue; 6030 } 6031 6032 bp_conf = ACB_BKT_POOL(acb_tmp, pid); 6033 pvt_cnt = BPC_BNK_CNT(bp_conf); 6034 6035 for (i = 0; i < pvt_cnt; i++) { 6036 pvt_ptr = bp_conf->pvt_ptr[i]; 6037 if (pvt_ptr == NULL) { 6038 continue; 6039 } 6040 6041 if (CORRUPT(pvt_ptr)) { 6042 cli_out("acb %d: pvt_ptr %p in pool %d bkt %d " 6043 "bnk %d is corrupted\n", 6044 a, pvt_ptr, pid, ALPM_IDX_TO_BKT(acb_tmp, i), 6045 ALPM_IDX_TO_BNK(acb_tmp, i)); 6046 err++; 6047 goto bad; 6048 } 6049 6050 pvt_ptr = 6051 (uint32 *)PVT_BKT_TRIE((_alpm_pvt_node_t *)pvt_ptr); 6052 if (CORRUPT(pvt_ptr)) { 6053 cli_out("acb %d: pvt_bkt_trie %p in pool %d bkt %d " 6054 "bnk %d is corrupted\n", 6055 a, pvt_ptr, pid, ALPM_IDX_TO_BKT(acb_tmp, i), 6056 ALPM_IDX_TO_BNK(acb_tmp, i)); 6057 err++; 6058 goto bad; 6059 } 6060 } 6061 } 6062 } 6063 } 6064 6065 /* Check Global bank usage and pvt_ptr */ 6066 if ((sal_strcmp(pfx_str, "CBInsert") == 0 || 6067 sal_strcmp(pfx_str, "CBDelete") == 0 || 6068 sal_strcmp(pfx_str, "SanityAll") == 0) && 6069 ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_BNK_CONF_NULL_PVT) { 6070 int tab_idx; 6071 SHR_BITDCL *bnk_bmp; 6072 6073 /* Private VRFs */ 6074 bnk_bmp = ACB_BNK_BMP(acb, vrf_id, ipt); 6075 bnk_cnt = ACB_BNK_CNT(acb, vrf_id); 6076 6077 for (i = 0; i < bnk_cnt; i++) { 6078 if (SHR_BITGET(bnk_bmp, i)) { 6079 tab_idx = ALPM_TAB_IDX_GET_BKT_BNK(acb, 0, i/bnkpb, i%bnkpb); 6080 /* If bank is occupied but pvt_ptr is not set, report error 6081 * Skip examing bkt 0 6082 */ 6083 if ((i/bnkpb) != 0 && 6084 ACB_PVT_PTR(acb, pvt_node, tab_idx) == NULL) { 6085 cli_out("\n[%s]PVT-SANITY(CB%d): bkt %d bnk %d was used " 6086 "by NULL pvt_ptr\n", pfx_str, acb->acb_idx, 6087 i/bnkpb, i%bnkpb); 6088 err++; 6089 goto bad; 6090 } 6091 } 6092 } 6093 } 6094 6095 /* Check Global bank usage and pvt_ptr */ 6096 if ((sal_strcmp(pfx_str, "CBInsert") == 0 || 6097 sal_strcmp(pfx_str, "CBDelete") == 0 || 6098 sal_strcmp(pfx_str, "SanityAll") == 0) && 6099 ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_BNK_CONF) { 6100 SHR_BITDCL *bnk_bmp; 6101 6102 /* Private VRFs */ 6103 bnk_bmp = ACB_BNK_BMP(acb, vrf_id, ipt); 6104 6105 for (i = 0; i < bnkpb; i++) { 6106 if (BI_BNK_IS_USED(bkt_info, i)) { 6107 int gbl_bnk = 6108 BI_BKT_IDX(bkt_info) * ACB_BNK_PER_BKT(acb, vrf_id) + i; 6109 if (BI_ROFS(bkt_info) > i) { 6110 gbl_bnk += ACB_BNK_PER_BKT(acb, vrf_id); 6111 } 6112 6113 if (!SHR_BITGET(bnk_bmp, gbl_bnk)) { 6114 cli_out("\n[%s]PVT-SANITY(CB%d): bkt %d bnk %d was used " 6115 "but global bit %d is not SET\n", pfx_str, acb->acb_idx, 6116 BI_BKT_IDX(bkt_info), i, gbl_bnk); 6117 err++; 6118 goto bad; 6119 } 6120 } 6121 } 6122 } 6123 6124 /* Check if used banks are coutinuous */ 6125 if (!ACB_BKT_FIXED_FMT(acb, 1)) { 6126 end_bnk = -1; 6127 for (i = PVT_ROFS(pvt_node); i < PVT_ROFS(pvt_node) + bnkpb; i++) { 6128 if (bkt_info->bnk_fmt[i % bnkpb] == 0) { 6129 end_bnk = i; 6130 } else if (end_bnk != -1) { 6131 /* Once end_bnk is settled, the rest bnks FMT should be 0 */ 6132 cli_out("[%s]PVT-SANITY(CB%d): Used banks are not cont. rofs %d: ", 6133 pfx_str, acb->acb_idx, PVT_ROFS(pvt_node)); 6134 for (i = 0; i < bnkpb; i++) { 6135 if (PVT_ROFS(pvt_node) == i) { 6136 cli_out("^"); 6137 } 6138 cli_out("%d ", bkt_info->bnk_fmt[i]); 6139 } 6140 cli_out("\n"); 6141 err++; 6142 goto bad; 6143 } 6144 } 6145 } 6146 6147 /* trie-tree count & vet_bmp count, 6148 * SHOULD NOT be used in the middle of process, e.g. bucket split 6149 */ 6150 if ((sal_strcmp(pfx_str, "CBInsert") == 0 || 6151 sal_strcmp(pfx_str, "CBDelete") == 0 || 6152 sal_strcmp(pfx_str, "SanityAll") == 0 || 6153 sal_strcmp(pfx_str, "SplitOpvt") == 0 || 6154 sal_strcmp(pfx_str, "SplitNpvt") == 0) && 6155 bkt_trie->trie && 6156 ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_SANITY_COUNT) { 6157 bkt_node_cnt = bkt_trie->trie->count; 6158 bkt_info_cnt = 0; 6159 for (i = 0; i < ALPM_BPB_MAX; i++) { 6160 uint32 vet_bmp; 6161 if (bkt_info->bnk_fmt[i] == 0) { 6162 continue; 6163 } 6164 6165 vet_bmp = bkt_info->vet_bmp[i]; 6166 bkt_info_cnt += _shr_popcount(vet_bmp); 6167 } 6168 6169 if (bkt_node_cnt != bkt_info_cnt) { 6170 cli_out("\n[%s]PVT-SANITY(CB%d): entry cnt mismatch in trie %d, bkt_info %d\n", 6171 pfx_str, acb->acb_idx, bkt_node_cnt, bkt_info_cnt); 6172 err++; 6173 goto bad; 6174 } 6175 } 6176 6177 /* bkt_info & ent_idx, tab_idx & pvt_node pointer 6178 * SW prefix length & HW prefix length 6179 * 6180 * Contruct: 6181 * - ALPM_IDX_MAKE 6182 * - ALPM_TAB_IDX_GET(ent_idx) 6183 * 6184 * Resolve: 6185 * - ALPM_IDX_TO_ENT 6186 * - ALPM_IDX_TO_BNK 6187 * - ALPM_IDX_TO_BKT 6188 */ 6189 ALPM_ALLOC_EG(pfx_arr, sizeof(*pfx_arr), "pfx_arr"); 6190 rv = alpm_lib_trie_traverse(bkt_trie, alpm_trie_pfx_cb, pfx_arr, 6191 trieTraverseOrderIn); 6192 ALPM_IEG(rv); 6193 6194 for (i = 0; i < pfx_arr->pfx_cnt; i++) { 6195 uint32 ent, bnk, bkt; 6196 uint32 tab_idx; 6197 uint32 vet_bmp; 6198 int sw_len, hw_len; 6199 6200 bkt_node = pfx_arr->pfx[i]; 6201 6202 /* SW Prefix Length & HW Prefix Length check */ 6203 if (ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_SANITY_LEN) { 6204 sw_len = bkt_node->key_len; 6205 hw_len = alpm_cb_ent_pfx_len_get(u, acb, pvt_node, 6206 bkt_node->ent_idx); 6207 if (!ACB_BKT_FIXED_FMT(acb, 1)) { 6208 hw_len += PVT_KEY_LEN(pvt_node); 6209 } 6210 if (sw_len != hw_len) { 6211 cli_out("\n[%s]PVT-SANITY(CB%d): Prefix Length mismatch sw %d " 6212 "hw %d ent_idx 0x%x\n", pfx_str, acb->acb_idx, sw_len, hw_len, 6213 bkt_node->ent_idx); 6214 err++; 6215 goto bad; 6216 } 6217 } 6218 6219 ent = ALPM_IDX_TO_ENT(bkt_node->ent_idx); 6220 bnk = ALPM_IDX_TO_BNK(acb, bkt_node->ent_idx); 6221 bkt = ALPM_IDX_TO_BKT(acb, bkt_node->ent_idx); 6222 if (bnk < PVT_ROFS(pvt_node)) { 6223 bkt -= 1; 6224 } 6225 6226 /* Bucket mismatch */ 6227 if (BI_BKT_IDX(bkt_info) != bkt) { 6228 cli_out("\n[%s]PVT-SANITY(CB%d): Bucket idx mismatch in bkt-node %d, " 6229 "pvt_node %d\n", pfx_str, acb->acb_idx, bkt, BI_BKT_IDX(bkt_info)); 6230 err++; 6231 goto bad; 6232 } 6233 6234 /* Ent, bnk mismatch */ 6235 vet_bmp = bkt_info->vet_bmp[bnk]; 6236 if (bkt_info->bnk_fmt[bnk] == 0 || 6237 !SHR_BITGET(&vet_bmp, ent)) { 6238 cli_out("\n[%s]PVT-SANITY(CB%d): (ent,bnk) mismatch in trie-node (%d,%d)" 6239 ", but related valid in bkt_info is (%d, bnk%d-fmt%d)\n", 6240 pfx_str, acb->acb_idx, ent, bnk, 6241 SHR_BITGET(&vet_bmp, ent), 6242 bnk, bkt_info->bnk_fmt[bnk]); 6243 err++; 6244 goto bad; 6245 } 6246 6247 /* tab_idx and pvt_node pointer */ 6248 tab_idx = ALPM_TAB_IDX_GET(bkt_node->ent_idx); 6249 if (tab_idx >= ACB_BNK_CNT(acb, PVT_BKT_VRF(pvt_node))) { 6250 cli_out("\n[%s]PVT-SANITY(CB%d): Invalid tab_idx value %d " 6251 "(ent %d, bnk %d, bkt %d)\n", pfx_str, acb->acb_idx, 6252 tab_idx, ent, bnk, bkt); 6253 err++; 6254 goto bad; 6255 } else if (ACB_PVT_PTR(acb, pvt_node, tab_idx) != pvt_node) { 6256 _alpm_pvt_node_t *acb_pvt_node; 6257 acb_pvt_node = (_alpm_pvt_node_t *)ACB_PVT_PTR(acb, pvt_node, tab_idx); 6258 6259 cli_out("\n[%s]PVT-SANITY(CB%d): pvt_ptr of tab_idx %d mismatch " 6260 "in acb %p, trie-tree %p\n", pfx_str, acb->acb_idx, tab_idx, 6261 acb_pvt_node, pvt_node); 6262 if (acb_pvt_node != NULL) { 6263 cli_out("\t- acb %p key_len %d, bkt_info(rofs %d, bkt %d)\n", 6264 acb_pvt_node, PVT_KEY_LEN(acb_pvt_node), 6265 PVT_ROFS(acb_pvt_node), 6266 PVT_BKT_IDX(acb_pvt_node)); 6267 cli_out("\t-trie %p key_len %d, bkt_info(rofs %d, bkt %d)\n", 6268 pvt_node, PVT_KEY_LEN(pvt_node), 6269 PVT_ROFS(pvt_node), 6270 PVT_BKT_IDX(pvt_node)); 6271 } 6272 err++; 6273 goto bad; 6274 } 6275 } 6276 6277 bad: 6278 if (err > 0) { 6279 rv = BCM_E_FAIL; 6280 } 6281 6282 if (pfx_arr != NULL) { 6283 alpm_util_free(pfx_arr); 6284 } 6285 6286 return rv; 6287 } 6288 6289 /* 6290 * Check software status 6291 * 6292 * - trie-tree count & vet_bmp count 6293 * - bkt_info & ent_idx 6294 */ 6295 int 6296 alpm_cb_sanity(int u, int acb_bmp, int vrf_id, int ipt) 6297 { 6298 int rv = BCM_E_NONE; 6299 int acb_idx; 6300 _alpm_cb_t *acb = NULL; 6301 6302 if (!(ALPMC(u)->_alpm_dbg_bmp & _ALPM_DBG_PVT_SANITY)) { 6303 return rv; 6304 } 6305 6306 for (acb_idx = 0; acb_idx < ACB_CNT(u); acb_idx++) { 6307 if (!(acb_bmp & (1 << acb_idx))) { 6308 continue; 6309 } 6310 6311 acb = ACB(u, acb_idx); 6312 if (!ACB_VRF_INITED(u, acb, vrf_id, ipt)) { 6313 continue; 6314 } 6315 6316 rv = bcm_esw_alpm_pvt_traverse(u, acb->acb_idx, vrf_id, ipt, 6317 alpm_cb_pvt_sanity_cb, "SanityAll"); 6318 BCM_IF_ERROR_RETURN(rv); 6319 } 6320 6321 return rv; 6322 } 6323 6324 #endif /* ALPM_ENABLE */ 6325