external_lpm.c (73000B)
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 * Triumph LPM TCAM table insert/delete/lookup routines 7 * _bcm_tr_ext_lpm_init - Called from bcm_l3_init 8 * _bcm_tr_ext_lpm_insert - Insert/Update an IPv4/IPV6 route entry into LPM table 9 * _bcm_tr_ext_lpm_delete - Delete an IPv4/IPV6 route entry from LPM table 10 * _bcm_tr_ext_lpm_match - (Exact match for the key. Will match both IP address 11 * and mask) 12 * 13 * Hit bit preservation - May loose HIT bit state when entries are moved 14 * around due to race condition. This happens if the HIT bit gets set in 15 * hardware after reading the entry to be moved and before the move is 16 * completed. If the HIT bit for an entry is already set when the move is 17 * initiated then it is preserved. 18 */ 19 20 #include <soc/defs.h> 21 22 #include <assert.h> 23 #include <shared/bsl.h> 24 #include <sal/core/libc.h> 25 #if defined(BCM_TRIUMPH_SUPPORT) && defined(INCLUDE_L3) 26 27 #include <shared/util.h> 28 #include <soc/mem.h> 29 #include <soc/cm.h> 30 #include <soc/drv.h> 31 #include <soc/register.h> 32 #include <soc/memory.h> 33 #include <soc/l3x.h> 34 #include <soc/er_tcam.h> 35 36 #include <bcm/l3.h> 37 #include <bcm/tunnel.h> 38 #include <bcm/debug.h> 39 #include <bcm/error.h> 40 #include <bcm/stack.h> 41 42 #include <bcm_int/esw/mbcm.h> 43 #include <bcm_int/esw/firebolt.h> 44 #include <bcm_int/esw/triumph.h> 45 #include <bcm_int/esw/l3.h> 46 #include <bcm_int/esw/xgs3.h> 47 #include <bcm_int/esw_dispatch.h> 48 49 /* 50 * TCAM based LPM implementation. Each table entry can hold two IPV4 entries or 51 * one IPV6 entry. VRF independent routes placed at the beginning or 52 * at the end of table based on application provided entry vrf id 53 * (BCM_L3_VRF_OVERRIDE/BCM_L3_VRF_GLOBAL). 54 * 55 * _TR_LPM_PREFIX_MAX 56 * 57 * lpm_prefix_index[96].begin ---> =============================== 58 * == == 59 * == IPV4 Prefix Len = 32 == 60 * == VRF OVERRIDE ROUTES == 61 * lpm_prefix_index[95].end ---> =============================== 62 * 63 * 64 * 65 * lpm_prefix_index[64].begin ---> =============================== 66 * == == 67 * == IPV4 Prefix Len = 0 == 68 * == VRF OVERRIDE ROUTES == 69 * lpm_prefix_index[64].end ---> =============================== 70 * 71 * 72 * 73 * lpm_prefix_index[63].begin ---> =============================== 74 * == == 75 * == IPV4 Prefix Len = 32 == 76 * == VRF SPECIFIC ROUTES == 77 * lpm_prefix_index[63].end ---> =============================== 78 * 79 * 80 * 81 * lpm_prefix_index[32].begin ---> =============================== 82 * == == 83 * == IPV4 Prefix Len = 0 == 84 * == VRF SPECIFIC ROUTES == 85 * lpm_prefix_index[32].end ---> =============================== 86 * 87 * 88 * 89 * lpm_prefix_index[31].begin ---> =============================== 90 * == == 91 * == IPV4 Prefix Len = 32 == 92 * == VRF GLOBAL ROUTES == 93 * lpm_prefix_index[31].end ---> =============================== 94 * 95 * 96 * 97 * lpm_prefix_index[0].begin ---> =============================== 98 * == == 99 * == IPV4 Prefix Len = 0 == 100 * == VRF GLOBAL ROUTES == 101 * lpm_prefix_index[0].end ---> =============================== 102 */ 103 104 typedef struct _tr_ext_lpm_state_s { 105 int start; /* start index for this prefix length */ 106 int end; /* End index for this prefix length */ 107 int prev; /* Previous (Lo to Hi) prefix length with non zero entry count*/ 108 int next; /* Next (Hi to Lo) prefix length with non zero entry count */ 109 int vent; /* valid entries */ 110 int fent; /* free entries */ 111 } _tr_ext_lpm_state_t, *_tr_ext_lpm_state_p; 112 113 #define SOC_MEM_COMPARE_RETURN(a, b) { \ 114 if ((a) < (b)) { return -1; } \ 115 if ((a) > (b)) { return 1; } \ 116 } 117 118 #define _TR_LPM_IPV4 (0) 119 #define _TR_LPM_IPV6 (1) 120 #define _TR_LPM_IP_VERSIONS (2) 121 122 #define _TR_LPM_BLOCK_SZ (0x200) 123 124 #define _TR_LPM_ROUTE_IS_V6(_entry_) \ 125 (((_entry_)->defip_flags & BCM_L3_IP6) ? _TR_LPM_IPV6 : _TR_LPM_IPV4) 126 127 128 static _tr_ext_lpm_state_p _tr_lpm_state[_TR_LPM_IP_VERSIONS][SOC_MAX_NUM_DEVICES]; 129 130 #define _TR_LPM_INIT_CHECK(_u_, _v_) \ 131 (_tr_lpm_state[(_v_)][(_u_)] != NULL) 132 #define _TR_LPM_STATE(_u_, _v_) \ 133 (_tr_lpm_state[(_v_)][(_u_)]) 134 #define _TR_LPM_STATE_START(_u_, _v_, _pfx_) \ 135 (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).start 136 #define _TR_LPM_STATE_END(_u_, _v_, _pfx_) \ 137 (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).end 138 #define _TR_LPM_STATE_PREV(_u_, _v_, _pfx_) \ 139 (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).prev 140 #define _TR_LPM_STATE_NEXT(_u_, _v_, _pfx_) \ 141 (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).next 142 #define _TR_LPM_STATE_VENT(_u_, _v_, _pfx_) \ 143 (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).vent 144 #define _TR_LPM_STATE_FENT(_u_, _v_, _pfx_) \ 145 (_tr_lpm_state[(_v_)][(_u_)][(_pfx_)]).fent 146 #define _TR_LPM_PREFIX_COUNT(_mem_) \ 147 (((_mem_) == EXT_IPV4_DEFIPm) ? 33 : \ 148 ((_mem_) == EXT_IPV6_64_DEFIPm) ? 65 : 129) 149 /* 1 set for VRF_OVERRIDE, 1 set for VRF DEPENDENT, 1 set for VRF_GLOBAL */ 150 #define _TR_LPM_PREFIX_MAX(_mem_) (3 * _TR_LPM_PREFIX_COUNT(_mem_)) 151 152 #define _TR_LPM_PREFIX_MAX_INDEX(_mem_) (_TR_LPM_PREFIX_MAX(_mem_) - 1) 153 154 /* IPv4 tcam software entry. */ 155 typedef struct _tr_lpm_v4_key_s { 156 uint32 addr; /* IPv4 address. */ 157 uint32 vrf; /* Vrf id. */ 158 uint32 next_entry:21; /* Next entry producing identical hash.*/ 159 } _tr_lpm_v4_key_t; 160 161 /* IPv6 tcam software entry. */ 162 typedef struct _tr_lpm_v6_key_s { 163 uint8 addr[16]; /* IPv6 address. */ 164 uint32 vrf; /* VRF id. */ 165 uint32 next_entry:21; /* Next entry producing identical hash. */ 166 } _tr_lpm_v6_key_t; 167 168 /* IPv6 tcam software image. */ 169 typedef struct _tr_lpm_sw_image_s { 170 int unit; 171 int hash_size; /* Number entries in hash table */ 172 int *hash_table; /* Hash table with 16 bit index. */ 173 soc_mem_t mem; /* Combined route table view memory. */ 174 soc_mem_t data_mem; /* Memory route data resides in. */ 175 soc_mem_t hit_bit_mem; /* Memory route hit_bit resides in. */ 176 _tr_lpm_v4_key_t *fib4; /* Sw image of ipv4 route table. */ 177 _tr_lpm_v6_key_t *fib6; /* Sw image of ipv6 route table. */ 178 } _tr_lpm_sw_image_t, *_tr_lpm_sw_image_p; 179 180 181 static _tr_lpm_sw_image_p _lpm_sw_image[_TR_LPM_IP_VERSIONS][SOC_MAX_NUM_DEVICES]; 182 183 #define _TR_LPM_SW_IMAGE(_u_, _v_) (_lpm_sw_image[(_v_)][(_u_)]) 184 #define _TR_LPM_MEM(_u_, _v_) (_TR_LPM_SW_IMAGE((_u_), (_v_))->mem) 185 #define _TR_LPM_DATA_MEM(_u_, _v_) (_TR_LPM_SW_IMAGE((_u_), (_v_))->data_mem) 186 #define _TR_LPM_HIT_BIT_MEM(_u_, _v_) \ 187 (_TR_LPM_SW_IMAGE((_u_), (_v_))->hit_bit_mem) 188 #define _TR_LPM_FIB4(_u_) (_TR_LPM_SW_IMAGE((_u_), (_TR_LPM_IPV4))->fib4) 189 #define _TR_LPM_FIB6(_u_) (_TR_LPM_SW_IMAGE((_u_), (_TR_LPM_IPV6))->fib6) 190 191 192 #define _TR_LPM_HASH_INDEX_NULL (0x1FFFFF) 193 #define _TR_LPM_HASH_SZ (5) 194 typedef uint32 _tr_ext_lpm_hash_entry_t[_TR_LPM_HASH_SZ]; 195 #define _TR_LPM_HASH_ENTRY_IPV6_GET(_entry_, _odata_) \ 196 sal_memcpy((_odata_), (_entry_)->defip_ip6_addr, sizeof(bcm_ip6_t)); \ 197 _odata_[4] = (_entry_)->defip_vrf 198 199 #define _TR_LPM_HASH_ENTRY_IPV4_GET(_entry_, _odata_) \ 200 sal_memset((_odata_), 0, _TR_LPM_HASH_SZ * sizeof(uint32)); \ 201 sal_memcpy((_odata_), &(_entry_)->defip_ip_addr, sizeof(bcm_ip_t)); \ 202 _odata_[4] = (_entry_)->defip_vrf 203 204 205 /* 206 * Function: 207 * _tr_lpm_sw_image_create 208 * Purpose: 209 * Create an sw image of external lpm table. 210 * Parameters: 211 * unit - (IN) Device unit 212 * v6 - (IN) IPv6 sw image indicator. 213 * mem - (IN) Memory route table resides in. 214 * Returns: 215 * BCM_E_XXX 216 */ 217 218 STATIC int 219 _tr_lpm_sw_image_create(int unit, int v6, soc_mem_t mem) 220 { 221 _tr_lpm_sw_image_p sw_image; /* Allocated sw image. */ 222 int index; /* Sw image iteration index. */ 223 int mem_size; /* Allocate memory size. */ 224 225 /* 226 * Allocate software image. 227 */ 228 sw_image = sal_alloc(sizeof(_tr_lpm_sw_image_t), "External lpm sw image"); 229 if (sw_image == NULL) { 230 return (BCM_E_MEMORY); 231 } 232 233 sal_memset(sw_image, 0, sizeof(_tr_lpm_sw_image_t)); 234 235 /* 236 * Initialize sw image properties (unit, hash size, memory size). 237 */ 238 sw_image->unit = unit; 239 sw_image->hash_size = (1 << BYTES2BITS(sizeof(uint16))); 240 switch(mem) { 241 case EXT_IPV4_DEFIPm: 242 sw_image->mem = EXT_IPV4_DEFIPm; 243 sw_image->data_mem = EXT_DEFIP_DATA_IPV4m; 244 sw_image->hit_bit_mem = EXT_DST_HIT_BITS_IPV4m; 245 break; 246 case EXT_IPV6_64_DEFIPm: 247 sw_image->mem = EXT_IPV6_64_DEFIPm; 248 sw_image->data_mem = EXT_DEFIP_DATA_IPV6_64m; 249 sw_image->hit_bit_mem = EXT_DST_HIT_BITS_IPV6_64m; 250 break; 251 case EXT_IPV6_128_DEFIPm: 252 sw_image->mem = EXT_IPV6_128_DEFIPm; 253 sw_image->data_mem = EXT_DEFIP_DATA_IPV6_128m; 254 sw_image->hit_bit_mem = EXT_DST_HIT_BITS_IPV6_128m; 255 break; 256 default: 257 sal_free(sw_image); 258 return (BCM_E_PARAM); 259 } 260 261 /* 262 * Pre-allocate the hash table storage. 263 */ 264 mem_size = sw_image->hash_size * sizeof(int); 265 sw_image->hash_table = sal_alloc(mem_size, "External lpm hash table"); 266 if (NULL == sw_image->hash_table) { 267 sal_free(sw_image); 268 return (BCM_E_MEMORY); 269 } 270 271 /* 272 * Pre-allocate a complete sw view of installed entries. 273 */ 274 if (v6) { 275 mem_size = soc_mem_index_count(unit, sw_image->mem) * \ 276 sizeof(_tr_lpm_v6_key_t); 277 sw_image->fib6 = sal_alloc(mem_size, "External lpm fib"); 278 if (NULL == sw_image->fib6) { 279 sal_free(sw_image->hash_table); 280 sal_free(sw_image); 281 return (BCM_E_MEMORY); 282 } 283 sal_memset(sw_image->fib6, 0, mem_size); 284 } else { 285 mem_size = soc_mem_index_count(unit, sw_image->mem) * \ 286 sizeof(_tr_lpm_v4_key_t); 287 sw_image->fib4 = sal_alloc(mem_size, "External lpm fib"); 288 if (NULL == sw_image->fib4) { 289 sal_free(sw_image->hash_table); 290 sal_free(sw_image); 291 return (BCM_E_MEMORY); 292 } 293 sal_memset(sw_image->fib4, 0, mem_size); 294 } 295 296 297 /* 298 * Set the entries in the hash table to _TR_LPM_HASH_INDEX_NULL 299 * Link the entries beyond hash->index_max for handling collisions 300 */ 301 for(index = 0; index < sw_image->hash_size; index++) { 302 sw_image->hash_table[index] = _TR_LPM_HASH_INDEX_NULL; 303 } 304 305 for(index = 0; index < soc_mem_index_count(unit,sw_image->mem); index++) { 306 if (v6) { 307 sw_image->fib6[index].next_entry = _TR_LPM_HASH_INDEX_NULL; 308 } else { 309 sw_image->fib4[index].next_entry = _TR_LPM_HASH_INDEX_NULL; 310 } 311 } 312 313 _TR_LPM_SW_IMAGE(unit, v6) = sw_image; 314 315 return (BCM_E_NONE); 316 } 317 318 /* 319 * Function: 320 * _tr_lpm_sw_image_destroy 321 * Purpose: 322 * Destroy the sw image table 323 * Parameters: 324 * unit - (IN) BCM device nu 325 * v6 - (IN) IP version. 326 * Returns: 327 * BCM_E_XXX 328 */ 329 STATIC int 330 _tr_lpm_sw_image_destroy(int unit, int v6) 331 { 332 if (NULL != _TR_LPM_SW_IMAGE(unit, v6)) { 333 if (NULL != _TR_LPM_SW_IMAGE(unit, v6)->hash_table) { 334 sal_free(_TR_LPM_SW_IMAGE(unit, v6)->hash_table); 335 } 336 337 if ((v6) && (NULL != _TR_LPM_FIB6(unit))) { 338 sal_free(_TR_LPM_FIB6(unit)); 339 } 340 341 if ((!v6) && (NULL != _TR_LPM_FIB4(unit))) { 342 sal_free(_TR_LPM_FIB4(unit)); 343 } 344 sal_free(_TR_LPM_SW_IMAGE(unit, v6)); 345 } 346 347 _TR_LPM_SW_IMAGE(unit, v6) = NULL; 348 return (BCM_E_NONE); 349 } 350 351 352 /* 353 * Function: 354 * _tr_ext_lpm_hash_compute 355 * Purpose: 356 * Compute CRC hash for key data. 357 * Parameters: 358 * data - (IN) Key data 359 * hash - (OUT)Computed 16 bit hash 360 * Returns: 361 * BCM_E_XXX 362 */ 363 STATIC int 364 _tr_ext_lpm_hash_compute(_bcm_defip_cfg_t *data, uint16 *hash) 365 { 366 bcm_ip6_t v6_mask; /* IPv6 subnet mask. */ 367 uint32 v4_mask; /* IPv4 subnet mask. */ 368 _tr_ext_lpm_hash_entry_t buf; /* Scratch buffer. */ 369 370 if ((NULL == data) || (NULL == hash)) { 371 return (BCM_E_PARAM); 372 } 373 374 if (_TR_LPM_ROUTE_IS_V6(data)) { 375 /* Create mask from prefix length. */ 376 bcm_ip6_mask_create(v6_mask, data->defip_sub_len); 377 /* Apply prefix mask. */ 378 bcm_xgs3_l3_mask6_apply(v6_mask, data->defip_ip6_addr); 379 /* Extract buffer for hash */ 380 _TR_LPM_HASH_ENTRY_IPV6_GET(data, buf); 381 382 } else { 383 /* Create mask from prefix length. */ 384 v4_mask = BCM_IP4_MASKLEN_TO_ADDR(data->defip_sub_len); 385 /* Apply prefix mask. */ 386 data->defip_ip_addr &= v4_mask; 387 /* Extract buffer for hash */ 388 _TR_LPM_HASH_ENTRY_IPV4_GET(data, buf); 389 } 390 391 /* Calculate hash value. */ 392 *hash = _shr_crc16b(0, (void *)buf, BYTES2BITS(_TR_LPM_HASH_SZ * sizeof(uint32))); 393 394 return (BCM_E_NONE); 395 } 396 397 /* 398 * Function: 399 * _tr_ext_lpm_sw_entry_reset 400 * Purpose: 401 * Reset software entry. 402 * Parameters: 403 * unit - (IN) BCM device number. 404 * v6 - (IN) IPv6 entry flag. 405 * index - (IN) SW entry index. 406 * Returns: 407 * BCM_E_XXX 408 */ 409 static INLINE int 410 _tr_ext_lpm_sw_entry_reset(int unit, int v6, int index) 411 { 412 if (v6) { 413 sal_memset(_TR_LPM_FIB6(unit) + index, 0, sizeof (_tr_lpm_v6_key_t)); 414 _TR_LPM_FIB6(unit)[index].next_entry = _TR_LPM_HASH_INDEX_NULL; 415 } else { 416 sal_memset(_TR_LPM_FIB4(unit) + index, 0, sizeof (_tr_lpm_v4_key_t)); 417 _TR_LPM_FIB4(unit)[index].next_entry = _TR_LPM_HASH_INDEX_NULL; 418 } 419 return (BCM_E_NONE); 420 } 421 422 /* 423 * Function: 424 * _tr_ext_lpm_key_compare 425 * Purpose: 426 * Compare API provided route entry with entry in sw image. 427 * Parameters: 428 * unit - (IN) Bcm device number. 429 * index - (IN) SW image entry index. 430 * data - (IN) Route entry. 431 * Returns: 432 * BCM_E_XXX 433 */ 434 STATIC int 435 _tr_ext_lpm_key_compare(int unit, int index, _bcm_defip_cfg_t *data) 436 { 437 bcm_ip6_t v6_mask; /* IPv6 subnet mask. */ 438 int result; /* Comparison result. */ 439 int v6; /* IPv6 route indicator.*/ 440 441 if (NULL == data) { 442 return (BCM_E_PARAM); 443 } 444 445 v6 = _TR_LPM_ROUTE_IS_V6(data); 446 447 /* Perform index range sanity check. */ 448 if ((index < 0) || 449 (index >= soc_mem_index_count(unit, _TR_LPM_MEM(unit, v6)))) { 450 return (BCM_E_PARAM); 451 } 452 453 454 /* Prefix comparison. */ 455 if (v6) { 456 /* Vrf comparison. */ 457 if (data->defip_vrf != _TR_LPM_FIB6(unit)[index].vrf) { 458 return (-1); 459 } 460 /* IPv6 Create mask from prefix length. */ 461 bcm_ip6_mask_create(v6_mask, data->defip_sub_len); 462 /* Apply prefix mask. */ 463 bcm_xgs3_l3_mask6_apply(v6_mask, data->defip_ip6_addr); 464 /* Compare prefixes */ 465 result = sal_memcmp(data->defip_ip6_addr, 466 _TR_LPM_FIB6(unit)[index].addr, 467 sizeof(bcm_ip6_t)); 468 } else { 469 /* Vrf comparison. */ 470 if (data->defip_vrf != _TR_LPM_FIB4(unit)[index].vrf) { 471 return (-1); 472 } 473 /* Apply prefix mask. */ 474 data->defip_ip_addr &= BCM_IP4_MASKLEN_TO_ADDR(data->defip_sub_len); 475 /* Compare prefixes */ 476 result = sal_memcmp(&data->defip_ip_addr, 477 &_TR_LPM_FIB4(unit)[index].addr, sizeof(bcm_ip_t)); 478 } 479 480 return (result); 481 } 482 /* 483 * Function: 484 * _tr_ext_lpm_prefix_length_get 485 * Purpose: 486 * Extract vrf weighted prefix length from the route entry. 487 * Parameters: 488 * unit - (IN)BCM device number. 489 * entry - (IN)Lookup key. 490 * pfx_len - (OUT)Prefix length. 491 * Returns: 492 * BCM_E_XXX 493 */ 494 STATIC int 495 _tr_ext_lpm_prefix_length_get(int unit, _bcm_defip_cfg_t *entry, int *pfx_len) 496 { 497 soc_mem_t mem; /* Route table memory. */ 498 int v6; /* IPv6 entry indicator. */ 499 500 /* Input parameters check. */ 501 if ((NULL == entry) || (NULL == pfx_len)) { 502 return (BCM_E_PARAM); 503 } 504 505 v6 = _TR_LPM_ROUTE_IS_V6(entry); 506 mem = _TR_LPM_MEM(unit, v6); 507 508 switch (entry->defip_vrf) { 509 case BCM_L3_VRF_GLOBAL: 510 *pfx_len = entry->defip_sub_len; 511 break; 512 case BCM_L3_VRF_OVERRIDE: 513 *pfx_len = entry->defip_sub_len + 2 * _TR_LPM_PREFIX_COUNT(mem); 514 break; 515 default: 516 *pfx_len = entry->defip_sub_len + _TR_LPM_PREFIX_COUNT(mem); 517 break; 518 } 519 return (BCM_E_NONE); 520 } 521 522 523 /* 524 * Function: 525 * _tr_ext_lpm_reset 526 * Purpose: 527 * Flush an entry from external route table. 528 * Parameters: 529 * unit - (IN) BCM unit number. 530 * v6 - (IN) IPv6 entry indicator. 531 * index - (IN) Entry index. 532 * Returns: 533 * BCM_E_XXX 534 */ 535 STATIC int 536 _tr_ext_lpm_reset(int unit, int v6, int index) 537 { 538 soc_mem_t mem; /* Route table memory. */ 539 540 /* Get memory name. */ 541 mem = _TR_LPM_MEM(unit, v6); 542 543 /* Check index range. */ 544 if ((index > soc_mem_index_max(unit, mem)) || 545 (index < soc_mem_index_min(unit, mem))) { 546 return (BCM_E_PARAM); 547 } 548 549 return soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, 550 &soc_mem_entry_null(unit, mem)); 551 } 552 553 554 /* 555 * Function: 556 * _tr_ext_lpm_write 557 * Purpose: 558 * Get an entry from external route table. 559 * Parameters: 560 * unit - (IN) BCM unit number. 561 * data - (IN) Entry data. 562 * nh_ecmp_idx - (IN) Next hop ecmp group index. 563 * Returns: 564 * BCM_E_XXX 565 */ 566 STATIC int 567 _tr_ext_lpm_write(int unit, _bcm_defip_cfg_t *data, int nh_ecmp_idx) 568 569 { 570 uint32 buf[SOC_MAX_MEM_FIELD_WORDS]; /* Buffer for HW entry. */ 571 soc_mem_t mem; /* Route table memory. */ 572 bcm_ip6_t v6_mask; /* IPv6 route mask. */ 573 int vrf_id; /* VRF id. */ 574 int vrf_mask; /* VRF mask. */ 575 int field_len; /* Vrf field length. */ 576 uint32 field_mask; /* Vrf field mask. */ 577 int v6; /* IPv6 route indicator. */ 578 579 /* Input parameters check. */ 580 if (NULL == data) { 581 return (BCM_E_PARAM); 582 } 583 584 v6 = _TR_LPM_ROUTE_IS_V6(data); 585 mem = _TR_LPM_MEM(unit, v6); 586 587 /* Entry index sanity check. */ 588 if ((data->defip_index > soc_mem_index_max(unit, mem)) || 589 (data->defip_index < soc_mem_index_min(unit, mem))) { 590 return (BCM_E_PARAM); 591 } 592 593 /* Extract entry vrf id & vrf mask. */ 594 BCM_IF_ERROR_RETURN 595 (bcm_xgs3_internal_lpm_vrf_calc(unit, data, &vrf_id, &vrf_mask)); 596 597 /* Reset hw buffer first. */ 598 sal_memset(buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 599 600 /* Set valid bit. */ 601 soc_mem_field32_set(unit, mem, buf, VALIDf, 0x1); 602 603 /* Check if entry points to ecmp group. */ 604 if (data->defip_flags & BCM_L3_MULTIPATH) { 605 /* Mark entry as ECMP & set ecmp group id. */ 606 soc_mem_field32_set(unit, mem, buf, ECMPf, 0x1); 607 soc_mem_field32_set(unit, mem, buf, ECMP_PTRf, nh_ecmp_idx); 608 } else { 609 soc_mem_field32_set(unit, mem, buf, NEXT_HOP_INDEXf, nh_ecmp_idx); 610 } 611 612 /* Set priority override bit & entry priority. */ 613 if (data->defip_flags & BCM_L3_RPE) { 614 soc_mem_field32_set(unit, mem, buf, RPEf, 0x1); 615 /* Set entry priority. */ 616 soc_mem_field32_set(unit, mem, buf, PRIf, data->defip_prio); 617 } 618 619 /* Set destination discard flag. */ 620 if (data->defip_flags & BCM_L3_DST_DISCARD) { 621 soc_mem_field32_set(unit, mem, buf, DST_DISCARDf, 0x1); 622 } 623 624 /* Set classification group id. */ 625 soc_mem_field32_set(unit, mem, buf, CLASS_IDf, 626 data->defip_lookup_class); 627 628 /* Set hit bit . */ 629 if (data->defip_flags & BCM_L3_HIT) { 630 soc_mem_field32_set(unit, mem, buf, DST_HITf, 0x1); 631 } 632 633 /* Set default route indication. */ 634 if (0 == data->defip_sub_len) { 635 soc_mem_field32_set(unit, mem, buf, DEFAULTROUTEf, 0x1); 636 } 637 638 /* Set Global route flag. */ 639 if (BCM_L3_VRF_GLOBAL == data->defip_vrf) { 640 soc_mem_field32_set(unit, mem, buf, GLOBAL_ROUTEf, 0x1); 641 } 642 643 /* Set vrf id. */ 644 field_len = soc_mem_field_length(unit, mem, VRF_LOf); 645 field_mask = (1 << field_len) - 1; 646 647 soc_mem_field32_set(unit, mem, buf, VRF_LOf, vrf_id & field_mask); 648 soc_mem_mask_field32_set(unit, mem, buf, MASK_VRF_LOf, 649 vrf_mask & field_mask); 650 651 if (SOC_MEM_FIELD_VALID(unit, mem, VRF_HIf)) { 652 soc_mem_field32_set(unit, mem, buf, VRF_HIf, vrf_id >> field_len); 653 soc_mem_mask_field32_set(unit, mem, buf, MASK_VRF_HIf, 654 vrf_mask >> field_len); 655 } 656 657 /* Set ip address. */ 658 if (v6) { 659 bcm_ip6_mask_create(v6_mask, data->defip_sub_len); 660 bcm_xgs3_l3_mask6_apply(v6_mask, data->defip_ip6_addr); 661 662 if (SOC_MEM_FIELD_VALID(unit, mem, IP_ADDRf)) { 663 /* Set address upper part (0-63). */ 664 soc_mem_ip6_addr_set(unit, mem, buf, IP_ADDRf, 665 data->defip_ip6_addr, SOC_MEM_IP6_UPPER_ONLY); 666 /* Set address mask upper part (0-63). */ 667 soc_mem_ip6_addr_mask_set(unit, mem, buf, MASK_IP_ADDRf, 668 v6_mask, SOC_MEM_IP6_UPPER_ONLY); 669 } else { 670 /* Set address upper part (0-63). */ 671 soc_mem_ip6_addr_set(unit, mem, buf, IP_ADDR_HIf, 672 data->defip_ip6_addr, SOC_MEM_IP6_UPPER_ONLY); 673 /* Set address mask upper part (0-63). */ 674 soc_mem_ip6_addr_mask_set(unit, mem, buf, MASK_IP_ADDR_HIf, 675 v6_mask, SOC_MEM_IP6_UPPER_ONLY); 676 677 /* Set address lower part (64-127). */ 678 soc_mem_ip6_addr_set(unit, mem, buf, IP_ADDR_LOf, 679 data->defip_ip6_addr, SOC_MEM_IP6_LOWER_ONLY); 680 /* Set address mask upper part (64-127). */ 681 soc_mem_ip6_addr_mask_set(unit, mem, buf, MASK_IP_ADDR_LOf, 682 v6_mask, SOC_MEM_IP6_LOWER_ONLY); 683 } 684 } else { 685 /* Set ip address. */ 686 soc_mem_field32_set(unit, mem, buf, IP_ADDRf, data->defip_ip_addr); 687 /* Set ip address mask. */ 688 soc_mem_mask_field32_set(unit, mem, buf, MASK_IP_ADDRf, 689 BCM_IP4_MASKLEN_TO_ADDR(data->defip_sub_len)); 690 } 691 692 /* Mask reserved bits as "don't compare" */ 693 if (SOC_MEM_FIELD_VALID(unit, mem, MASK_RESERVEDf)) { 694 soc_mem_mask_field32_set(unit, mem, buf, MASK_RESERVEDf, 0); 695 } 696 697 /* Write entry to the hardware. */ 698 BCM_IF_ERROR_RETURN (soc_mem_write(unit, mem, MEM_BLOCK_ALL, 699 data->defip_index, buf)); 700 701 return (BCM_E_NONE); 702 } 703 704 /* 705 * Function: 706 * _tr_ext_lpm_parse_route_data 707 * Purpose: 708 * Parse an entry from external route table. 709 * Parameters: 710 * unit - (IN) SOC unit number. 711 * v6 - (IN) IPv6 route indicator. 712 * index - (IN) Entry index to read. 713 * sub_net_length - (IN) Subnet prefix length. 714 * data_buf - (IN) filled EXT_DATA_MEMORY buffer. 715 * data - (OUT) Entry data. 716 * nh_ecmp_idx - (OUT) Next hop ecmp group index. 717 * Returns: 718 * BCM_E_XXX 719 */ 720 STATIC int 721 _tr_ext_lpm_parse_route_data(int unit, int v6, int index, 722 int sub_net_length, uint32 *buf, 723 uint32 *usage_buf, _bcm_defip_cfg_t *data, 724 int *nh_ecmp_idx) 725 { 726 soc_mem_t data_mem; /* Route data memory. */ 727 soc_mem_t hit_bit_mem; /* Route data memory. */ 728 uint32 hit_bit_word; /* Hit bit for 32 entries. */ 729 int clear_hit; /* Clear hit bit. */ 730 731 /* Input parameters check. */ 732 if ((NULL == data) || (NULL == buf) || (NULL == usage_buf)) { 733 return (BCM_E_PARAM); 734 } 735 736 /* Get data/hit_bit memory . */ 737 data_mem = _TR_LPM_DATA_MEM(unit, v6); 738 hit_bit_mem = _TR_LPM_HIT_BIT_MEM(unit, v6); 739 clear_hit = data->defip_flags & BCM_L3_HIT_CLEAR; 740 741 /* Reset destination buffer. */ 742 sal_memset(data, 0, sizeof(_bcm_defip_cfg_t)); 743 744 /* Set route index in the tcam. */ 745 data->defip_index = index; 746 747 /* Parse buffer fields. */ 748 data->defip_flags = (v6) ? BCM_L3_IP6 : 0; 749 750 /* Check if entry points to ecmp group. */ 751 if (soc_mem_field32_get(unit, data_mem, buf, ECMPf)) { 752 /* Mark entry as ecmp */ 753 data->defip_ecmp = 1; 754 data->defip_flags |= BCM_L3_MULTIPATH; 755 756 /* Get ecmp group id. */ 757 if (nh_ecmp_idx) { 758 *nh_ecmp_idx = 759 soc_mem_field32_get(unit, data_mem, buf, ECMP_PTRf); 760 } 761 } else { 762 /* Mark entry as non-ecmp. */ 763 data->defip_ecmp = 0; 764 765 /* Reset ecmp group next hop count. */ 766 data->defip_ecmp_count = 0; 767 768 /* Get next hop index. */ 769 if (nh_ecmp_idx) { 770 *nh_ecmp_idx = soc_mem_field32_get(unit, data_mem, buf, 771 NEXT_HOP_INDEXf); 772 } 773 } 774 /* Get entry priority. */ 775 data->defip_prio = soc_mem_field32_get(unit, data_mem, buf, PRIf); 776 777 /* Get priority override bit. */ 778 if (soc_mem_field32_get(unit, data_mem, buf, RPEf)) { 779 data->defip_flags |= BCM_L3_RPE; 780 } 781 782 /* Get destination discard flag. */ 783 if(soc_mem_field32_get(unit, data_mem, buf, DST_DISCARDf)) { 784 data->defip_flags |= BCM_L3_DST_DISCARD; 785 } 786 787 /* Set classification group id. */ 788 data->defip_lookup_class = 789 soc_mem_field32_get(unit, data_mem, buf, CLASS_IDf); 790 791 /* Vrf id. */ 792 793 /* Subnet address */ 794 if (v6) { 795 data->defip_vrf = _TR_LPM_FIB6(unit)[index].vrf; 796 sal_memcpy(data->defip_ip6_addr, 797 _TR_LPM_FIB6(unit)[index].addr, sizeof(bcm_ip6_t)); 798 } else { 799 data->defip_vrf = _TR_LPM_FIB4(unit)[index].vrf; 800 data->defip_ip_addr = _TR_LPM_FIB4(unit)[index].addr; 801 } 802 803 /* Sub net prefix length. */ 804 data->defip_sub_len = sub_net_length; 805 806 /* Get hit bit. */ 807 hit_bit_word = soc_mem_field32_get(unit, hit_bit_mem, 808 usage_buf, DST_HITf); 809 if ((hit_bit_word >> (index % 32)) & 0x1) { 810 data->defip_flags |= BCM_L3_HIT; 811 } 812 /* Clear hit bit if required. */ 813 if (clear_hit) { 814 hit_bit_word &= ~(0x1 << (index % 32)); 815 soc_mem_field32_set(unit, hit_bit_mem, usage_buf, DST_HITf, hit_bit_word); 816 BCM_IF_ERROR_RETURN 817 (soc_mem_write(unit, hit_bit_mem, MEM_BLOCK_ALL, 818 (index >> 5), usage_buf)); 819 } 820 return (BCM_E_NONE); 821 } 822 823 /* 824 * Function: 825 * _tr_ext_lpm_read_route_data 826 * Purpose: 827 * Get an entry from external route table. 828 * Parameters: 829 * unit - (IN) SOC unit number. 830 * v6 - (IN) IPv6 route indicator. 831 * index - (IN) Entry index to read. 832 * sub_net_length - (IN) Subnet prefix length. 833 * data - (OUT) Entry data. 834 * nh_ecmp_idx - (OUT) Next hop ecmp group index. 835 * Returns: 836 * BCM_E_XXX 837 */ 838 STATIC int 839 _tr_ext_lpm_read_route_data(int unit, int v6, int index, int sub_net_length, 840 _bcm_defip_cfg_t *data, int *nh_ecmp_idx) 841 { 842 soc_mem_t data_mem; /* Route data memory. */ 843 soc_mem_t hit_bit_mem; /* Route data memory. */ 844 uint32 buf[SOC_MAX_MEM_FIELD_WORDS]; /* Buffer for HW entry. */ 845 uint32 usage_buf[2]; /* Buffer for hit bit. */ 846 847 /* Input parameters check. */ 848 if (NULL == data) { 849 return (BCM_E_PARAM); 850 } 851 852 /* Get data/hit_bit memory . */ 853 data_mem = _TR_LPM_DATA_MEM(unit, v6); 854 hit_bit_mem = _TR_LPM_HIT_BIT_MEM(unit, v6); 855 856 /* Read buffer from HW. */ 857 BCM_IF_ERROR_RETURN 858 (soc_mem_read(unit, data_mem, MEM_BLOCK_ANY, index, buf)); 859 860 /* Read hit bit buffer from HW. */ 861 BCM_IF_ERROR_RETURN 862 (soc_mem_read(unit, hit_bit_mem, MEM_BLOCK_ANY, (index >> 5), 863 usage_buf)); 864 865 return _tr_ext_lpm_parse_route_data(unit, v6, index, sub_net_length, 866 buf, usage_buf, data, nh_ecmp_idx); 867 868 } 869 870 /* 871 * Function: 872 * _tr_ext_lpm_match 873 * Purpose: 874 * Get an entry from external route table. 875 * Parameters: 876 * unit - (IN) SOC unit number. 877 * key - (IN) Lookup key. 878 * pfx - (IN) VRF weighted prefix length. 879 * result - (OUT) Matching entry index. 880 * Returns: 881 * BCM_E_XXX 882 */ 883 STATIC int 884 _tr_ext_lpm_match(int unit, _bcm_defip_cfg_t *key, int pfx, int *result) 885 886 { 887 uint16 hash_val; /* Entry lookup hash. */ 888 int v6; /* Entry is IPv6 flag. */ 889 int index; /* Same hash linked list iteration index. */ 890 891 892 /* Input parameters check. */ 893 if ((NULL == key) || (NULL == result)) { 894 return (BCM_E_PARAM); 895 } 896 897 v6 = _TR_LPM_ROUTE_IS_V6(key); 898 899 /* Check if any entry with this prefix length present in sw table. */ 900 if (0 == _TR_LPM_STATE_VENT(unit, v6, pfx)) { 901 return (BCM_E_NOT_FOUND); 902 } 903 904 /* Compute route entry hash value. */ 905 BCM_IF_ERROR_RETURN(_tr_ext_lpm_hash_compute(key, &hash_val)); 906 hash_val %= _TR_LPM_SW_IMAGE(unit, v6)->hash_size; 907 908 /* Get first route table entry matching the hash. */ 909 index = _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val]; 910 911 while(index != _TR_LPM_HASH_INDEX_NULL) { 912 913 /* Skip indexes with not matching prefix length. */ 914 if ((index < _TR_LPM_STATE_START(unit, v6, pfx)) || 915 (index > _TR_LPM_STATE_END(unit, v6, pfx))) { 916 if (v6) { 917 index = _TR_LPM_FIB6(unit)[index].next_entry; 918 } else { 919 index = _TR_LPM_FIB4(unit)[index].next_entry; 920 } 921 continue; 922 } 923 924 /* Compare entry itself. */ 925 if (!_tr_ext_lpm_key_compare(unit, index, key)) { 926 break; 927 } 928 929 /* Continue to the next entry if no match found. */ 930 if (v6) { 931 index = _TR_LPM_FIB6(unit)[index].next_entry; 932 } else { 933 index = _TR_LPM_FIB4(unit)[index].next_entry; 934 } 935 } 936 937 /* Check lookup result. */ 938 if (_TR_LPM_HASH_INDEX_NULL == index) { 939 return (BCM_E_NOT_FOUND); 940 } 941 942 *result = index; 943 return (BCM_E_NONE); 944 } 945 946 947 /* 948 * Function: 949 * _tr_ext_lpm_sw_entry_delete 950 * Purpose: 951 * Remove a route entry from sw image. 952 * Parameters: 953 * unit - (IN) BCM device number. 954 * key - (IN) Route entry. 955 * Returns: 956 * BCM_E_XXX 957 */ 958 STATIC int 959 _tr_ext_lpm_sw_entry_delete(int unit, _bcm_defip_cfg_t *key) 960 { 961 int v6; /* Entry is IPv6 flag. */ 962 int index; /* Same hash linked list iteration index. */ 963 uint16 hash_val; /* Entry lookup hash. */ 964 int prev_index; /* Same hash linked list iteration index. */ 965 966 967 /* Input parameters check */ 968 if (NULL == key) { 969 return (BCM_E_PARAM); 970 } 971 972 v6 = _TR_LPM_ROUTE_IS_V6(key); 973 974 /* Compute route entry hash value. */ 975 BCM_IF_ERROR_RETURN(_tr_ext_lpm_hash_compute(key, &hash_val)); 976 hash_val %= _TR_LPM_SW_IMAGE(unit, v6)->hash_size; 977 978 /* Linked list deletion procedure. */ 979 index = _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val]; 980 prev_index = _TR_LPM_HASH_INDEX_NULL; 981 982 while(index != _TR_LPM_HASH_INDEX_NULL) { 983 if (key->defip_index == index) { 984 if (prev_index == _TR_LPM_HASH_INDEX_NULL) { 985 /* Delete from head of the list. */ 986 if (v6) { 987 _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val] = \ 988 _TR_LPM_FIB6(unit)[index].next_entry; 989 } else { 990 _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val] = \ 991 _TR_LPM_FIB4(unit)[index].next_entry; 992 } 993 } else { 994 /* Delete from the middle/end of the list. */ 995 if (v6) { 996 _TR_LPM_FIB6(unit)[prev_index].next_entry = \ 997 _TR_LPM_FIB6(unit)[index].next_entry; 998 } else { 999 _TR_LPM_FIB4(unit)[prev_index].next_entry = \ 1000 _TR_LPM_FIB4(unit)[index].next_entry; 1001 } 1002 } 1003 break; 1004 } 1005 /* Check next entry in the linked list. */ 1006 prev_index = index; 1007 if (v6) { 1008 index = _TR_LPM_FIB6(unit)[index].next_entry; 1009 } else { 1010 index = _TR_LPM_FIB4(unit)[index].next_entry; 1011 } 1012 } 1013 1014 /* Check if index was found. */ 1015 if (_TR_LPM_HASH_INDEX_NULL == index) { 1016 return(BCM_E_NOT_FOUND); 1017 } 1018 1019 /* Reset original sw entry. */ 1020 BCM_IF_ERROR_RETURN (_tr_ext_lpm_sw_entry_reset(unit, v6, index)); 1021 return (BCM_E_NONE); 1022 } 1023 1024 /* 1025 * Function: 1026 * _tr_ext_lpm_sw_entry_insert 1027 * Purpose: 1028 * Insert a route entry to sw image. 1029 * Parameters: 1030 * unit - (IN) BCM device number. 1031 * key - (IN) Route entry. 1032 * Returns: 1033 * BCM_E_XXX 1034 */ 1035 STATIC int 1036 _tr_ext_lpm_sw_entry_insert(int unit, _bcm_defip_cfg_t *key) 1037 { 1038 int v6; /* Entry is IPv6 flag. */ 1039 int index; /* Same hash linked list iteration index. */ 1040 uint16 hash_val; /* Entry lookup hash. */ 1041 1042 1043 /* Input parameters check */ 1044 if (NULL == key) { 1045 return (BCM_E_PARAM); 1046 } 1047 1048 v6 = _TR_LPM_ROUTE_IS_V6(key); 1049 index = key->defip_index; 1050 1051 /* Compute route entry hash value. */ 1052 BCM_IF_ERROR_RETURN(_tr_ext_lpm_hash_compute(key, &hash_val)); 1053 hash_val %= _TR_LPM_SW_IMAGE(unit, v6)->hash_size; 1054 1055 if (v6) { 1056 /* Point entry next to the head of linked list. */ 1057 _TR_LPM_FIB6(unit)[index].next_entry = \ 1058 _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val]; 1059 /* Set prefix subnet ip. */ 1060 sal_memcpy(_TR_LPM_FIB6(unit)[index].addr, 1061 key->defip_ip6_addr, sizeof(bcm_ip6_t)); 1062 /* Set prefix vrf. */ 1063 _TR_LPM_FIB6(unit)[index].vrf = key->defip_vrf; 1064 } else { 1065 /* Point entry next to the head of linked list. */ 1066 _TR_LPM_FIB4(unit)[index].next_entry = \ 1067 _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val]; 1068 /* Set prefix subnet ip. */ 1069 _TR_LPM_FIB4(unit)[index].addr = key->defip_ip_addr; 1070 /* Set prefix vrf. */ 1071 _TR_LPM_FIB4(unit)[index].vrf = key->defip_vrf; 1072 } 1073 1074 /* Point hash linked list head to the entry. */ 1075 _TR_LPM_SW_IMAGE(unit, v6)->hash_table[hash_val] = index; 1076 1077 return (BCM_E_NONE); 1078 } 1079 1080 1081 /* 1082 * Function: 1083 * _tr_lpm_ext_entry_shift 1084 * Purpose: 1085 * Move an entry in external route table 1086 * Parameters: 1087 * unit - (IN) BCM device number. 1088 * v6 - (IN) IPv6 indicator. 1089 * from_ent - (IN) Source entry index. 1090 * to_ent - (IN) Destination entry index. 1091 * Returns: 1092 * BCM_E_XXX 1093 */ 1094 STATIC int 1095 _tr_lpm_ext_entry_shift(int unit, int v6, int pfx, int from_ent, int to_ent) 1096 { 1097 int nh_ecmp_idx; /* Next hop/ecmp group index. */ 1098 _bcm_defip_cfg_t data; /* Route data. */ 1099 1100 sal_memset(&data, 0, sizeof(_bcm_defip_cfg_t)); 1101 1102 pfx %= _TR_LPM_PREFIX_COUNT(_TR_LPM_MEM(unit, v6)); 1103 1104 if (to_ent != from_ent) { 1105 BCM_IF_ERROR_RETURN 1106 (_tr_ext_lpm_read_route_data(unit, v6, from_ent, pfx, 1107 &data, &nh_ecmp_idx)); 1108 1109 BCM_IF_ERROR_RETURN(_tr_ext_lpm_sw_entry_delete(unit, &data)); 1110 data.defip_index = to_ent; 1111 1112 BCM_IF_ERROR_RETURN(_tr_ext_lpm_write(unit, &data, nh_ecmp_idx)); 1113 BCM_IF_ERROR_RETURN(_tr_ext_lpm_sw_entry_insert(unit, &data)); 1114 } 1115 1116 return (BCM_E_NONE); 1117 } 1118 1119 1120 1121 /* 1122 * Function: 1123 * _tr_lpm_ext_shift_pfx_up 1124 * Purpose: 1125 * Ripple prefixes 1 entry up. 1126 * Parameters: 1127 * unit - (IN) BCM device number. 1128 * v6 - (IN) IPv6 indicator. 1129 * pfx - (IN) Prefix subnet length. 1130 * Returns: 1131 * BCM_E_XXX 1132 */ 1133 STATIC int 1134 _tr_lpm_ext_shift_pfx_up(int unit, int v6, int pfx) 1135 { 1136 int from_ent; 1137 int to_ent; 1138 1139 to_ent = _TR_LPM_STATE_END(unit, v6, pfx) + 1; 1140 1141 from_ent = _TR_LPM_STATE_START(unit, v6, pfx); 1142 if(from_ent != to_ent) { 1143 BCM_IF_ERROR_RETURN 1144 (_tr_lpm_ext_entry_shift(unit, v6, pfx, from_ent, to_ent)); 1145 } 1146 _TR_LPM_STATE_START(unit, v6, pfx) += 1; 1147 _TR_LPM_STATE_END(unit, v6, pfx) += 1; 1148 return (BCM_E_NONE); 1149 } 1150 1151 1152 /* 1153 * Function: 1154 * _tr_lpm_ext_shift_pfx_down 1155 * Purpose: 1156 * Ripple prefixes 1 entry down. 1157 * Parameters: 1158 * unit - (IN) BCM device number. 1159 * v6 - (IN) IPv6 indicator. 1160 * pfx - (IN) Prefix subnet length. 1161 * Returns: 1162 * BCM_E_XXX 1163 */ 1164 STATIC int 1165 _tr_lpm_ext_shift_pfx_down(int unit, int v6, int pfx) 1166 { 1167 int from_ent; 1168 int to_ent; 1169 1170 to_ent = _TR_LPM_STATE_START(unit, v6, pfx) - 1; 1171 1172 /* Don't move empty prefix . */ 1173 if (_TR_LPM_STATE_VENT(unit, v6, pfx) == 0) { 1174 _TR_LPM_STATE_START(unit, v6, pfx) = to_ent; 1175 _TR_LPM_STATE_END(unit, v6, pfx) = to_ent - 1; 1176 return (BCM_E_NONE); 1177 } 1178 1179 to_ent = _TR_LPM_STATE_START(unit, v6, pfx) - 1; 1180 from_ent = _TR_LPM_STATE_END(unit, v6, pfx); 1181 BCM_IF_ERROR_RETURN 1182 (_tr_lpm_ext_entry_shift(unit, v6, pfx, from_ent, to_ent)); 1183 1184 _TR_LPM_STATE_START(unit, v6, pfx) -= 1; 1185 _TR_LPM_STATE_END(unit, v6, pfx) -= 1; 1186 1187 return (BCM_E_NONE); 1188 } 1189 1190 /* 1191 * Function: 1192 * _tr_ext_lpm_free_slot_create 1193 * Purpose: 1194 * Create a slot for the new entry rippling the entries if required. 1195 * Parameters: 1196 * unit - (IN) BCM device number. 1197 * v6 - (IN) IPv6 indicator. 1198 * pfx - (IN) Prefix subnet length. 1199 * free_slot - (OUT) Free slot index. 1200 * Returns: 1201 * BCM_E_XXX 1202 */ 1203 STATIC int 1204 _tr_ext_lpm_free_slot_create(int unit, int v6, int pfx, int *free_slot) 1205 { 1206 int prev_pfx; /* Prefixes iteration index. */ 1207 int next_pfx; /* Prefixes iteration index. */ 1208 int free_pfx; /* Prefix that has free entries. */ 1209 int curr_pfx; /* Prefixes iteration index. */ 1210 soc_mem_t mem; /* Route table entry. */ 1211 1212 mem = _TR_LPM_MEM(unit, v6); 1213 1214 if (_TR_LPM_STATE_VENT(unit, v6, pfx) == 0) { 1215 /* 1216 * Find the prefix position. Only prefix with valid 1217 * entries are in the list. 1218 * next -> high to low prefix. low to high index 1219 * prev -> low to high prefix. high to low index 1220 * Unused prefix length MAX_PFX_INDEX is the head of the 1221 * list and is node corresponding to this is always 1222 * present. 1223 */ 1224 curr_pfx = _TR_LPM_PREFIX_MAX_INDEX(mem); 1225 while (_TR_LPM_STATE_NEXT(unit, v6, curr_pfx) > pfx) { 1226 curr_pfx = _TR_LPM_STATE_NEXT(unit, v6, curr_pfx); 1227 } 1228 /* Insert the new prefix */ 1229 next_pfx = _TR_LPM_STATE_NEXT(unit, v6, curr_pfx); 1230 if (next_pfx != -1) { 1231 _TR_LPM_STATE_PREV(unit, v6, next_pfx) = pfx; 1232 } 1233 _TR_LPM_STATE_NEXT(unit, v6, pfx) = _TR_LPM_STATE_NEXT(unit, v6, curr_pfx); 1234 _TR_LPM_STATE_PREV(unit, v6, pfx) = curr_pfx; 1235 _TR_LPM_STATE_NEXT(unit, v6, curr_pfx) = pfx; 1236 1237 _TR_LPM_STATE_FENT(unit, v6, pfx) = (_TR_LPM_STATE_FENT(unit, v6, curr_pfx) + 1) / 2; 1238 _TR_LPM_STATE_FENT(unit, v6, curr_pfx) -= _TR_LPM_STATE_FENT(unit, v6, pfx); 1239 _TR_LPM_STATE_START(unit, v6, pfx) = _TR_LPM_STATE_END(unit, v6, curr_pfx) + 1240 _TR_LPM_STATE_FENT(unit, v6, curr_pfx) + 1; 1241 _TR_LPM_STATE_END(unit, v6, pfx) = _TR_LPM_STATE_START(unit, v6, pfx) - 1; 1242 _TR_LPM_STATE_VENT(unit, v6, pfx) = 0; 1243 } 1244 1245 free_pfx = pfx; 1246 while(_TR_LPM_STATE_FENT(unit, v6, free_pfx) == 0) { 1247 free_pfx = _TR_LPM_STATE_NEXT(unit, v6, free_pfx); 1248 if (free_pfx == -1) { 1249 /* No free entries on this side try the other side */ 1250 free_pfx = pfx; 1251 break; 1252 } 1253 } 1254 1255 while(_TR_LPM_STATE_FENT(unit, v6, free_pfx) == 0) { 1256 free_pfx = _TR_LPM_STATE_PREV(unit, v6, free_pfx); 1257 if (free_pfx == -1) { 1258 if (_TR_LPM_STATE_VENT(unit, v6, pfx) == 0) { 1259 /* We failed to allocate entries for a newly allocated prefix.*/ 1260 prev_pfx = _TR_LPM_STATE_PREV(unit, v6, pfx); 1261 next_pfx = _TR_LPM_STATE_NEXT(unit, v6, pfx); 1262 if (-1 != prev_pfx) { 1263 _TR_LPM_STATE_NEXT(unit, v6, prev_pfx) = next_pfx; 1264 } 1265 if (-1 != next_pfx) { 1266 _TR_LPM_STATE_PREV(unit, v6, next_pfx) = prev_pfx; 1267 } 1268 } 1269 return(BCM_E_FULL); 1270 } 1271 } 1272 1273 /* 1274 * Ripple entries to create free space 1275 */ 1276 while (free_pfx > pfx) { 1277 next_pfx = _TR_LPM_STATE_NEXT(unit, v6, free_pfx); 1278 BCM_IF_ERROR_RETURN(_tr_lpm_ext_shift_pfx_down(unit, v6, next_pfx)); 1279 _TR_LPM_STATE_FENT(unit, v6, free_pfx) -= 1; 1280 _TR_LPM_STATE_FENT(unit, v6, next_pfx) += 1; 1281 free_pfx = next_pfx; 1282 } 1283 1284 while (free_pfx < pfx) { 1285 BCM_IF_ERROR_RETURN(_tr_lpm_ext_shift_pfx_up(unit, v6, free_pfx)); 1286 _TR_LPM_STATE_FENT(unit, v6, free_pfx) -= 1; 1287 prev_pfx = _TR_LPM_STATE_PREV(unit, v6, free_pfx); 1288 _TR_LPM_STATE_FENT(unit, v6, prev_pfx) += 1; 1289 free_pfx = prev_pfx; 1290 } 1291 1292 _TR_LPM_STATE_VENT(unit, v6, pfx) += 1; 1293 _TR_LPM_STATE_FENT(unit, v6, pfx) -= 1; 1294 _TR_LPM_STATE_END(unit, v6, pfx) += 1; 1295 1296 *free_slot = _TR_LPM_STATE_END(unit, v6, pfx); 1297 return(BCM_E_NONE); 1298 } 1299 1300 /* 1301 * Function: 1302 * _tr_ext_lpm_free_slot_delete 1303 * Purpose: 1304 * Delete entry matching prefix, vrf in external route table. 1305 * Parameters: 1306 * unit - (IN) BCM device number. 1307 * v6 - (IN) IPv6 indicator. 1308 * pfx - (IN) Prefix subnet length. 1309 * slot - (IN) Deleted entry index. 1310 * Returns: 1311 * BCM_E_XXX 1312 */ 1313 STATIC int 1314 _tr_ext_lpm_free_slot_delete (int unit, int v6, int pfx, int slot) 1315 { 1316 int prev_pfx; /* Prefixes iteration index. */ 1317 int next_pfx; /* Prefixes iteration index. */ 1318 int from_ent; /* Entry source index. */ 1319 int to_ent; /* Entry destination index. */ 1320 1321 from_ent = _TR_LPM_STATE_END(unit, v6, pfx); 1322 to_ent = slot; 1323 1324 _TR_LPM_STATE_VENT(unit, v6, pfx) -= 1; 1325 _TR_LPM_STATE_FENT(unit, v6, pfx) += 1; 1326 _TR_LPM_STATE_END(unit, v6, pfx) -= 1; 1327 1328 if (to_ent != from_ent) { 1329 BCM_IF_ERROR_RETURN 1330 (_tr_lpm_ext_entry_shift(unit, v6, pfx, from_ent, to_ent)); 1331 } 1332 1333 BCM_IF_ERROR_RETURN(_tr_ext_lpm_reset(unit, v6, from_ent)); 1334 1335 if (_TR_LPM_STATE_VENT(unit, v6, pfx) == 0) { 1336 /* remove from the list */ 1337 prev_pfx = _TR_LPM_STATE_PREV(unit, v6, pfx); /* Always present */ 1338 next_pfx = _TR_LPM_STATE_NEXT(unit, v6, pfx); 1339 _TR_LPM_STATE_NEXT(unit, v6, prev_pfx) = next_pfx; 1340 _TR_LPM_STATE_FENT(unit, v6, prev_pfx) += _TR_LPM_STATE_FENT(unit, v6, pfx); 1341 _TR_LPM_STATE_FENT(unit, v6, pfx) = 0; 1342 if (next_pfx != -1) { 1343 _TR_LPM_STATE_PREV(unit, v6, next_pfx) = prev_pfx; 1344 } 1345 _TR_LPM_STATE_NEXT(unit, v6, pfx) = -1; 1346 _TR_LPM_STATE_PREV(unit, v6, pfx) = -1; 1347 _TR_LPM_STATE_START(unit, v6, pfx) = -1; 1348 _TR_LPM_STATE_END(unit, v6, pfx) = -1; 1349 } 1350 1351 return(BCM_E_NONE); 1352 } 1353 1354 1355 1356 /* 1357 * Function: 1358 * _bcm_tr_ext_lpm_init 1359 * Purpose: 1360 * Initialize external route table sw image. 1361 * Parameters: 1362 * unit - (IN)SOC unit number. 1363 * mem - (IN)External route table memory name. 1364 * Returns: 1365 * BCM_E_XXX 1366 */ 1367 int 1368 _bcm_tr_ext_lpm_init(int unit, soc_mem_t mem) 1369 { 1370 int num_prefixes; /* Number of different prefixes. */ 1371 int pfx_state_size; /* Prefix state tracking array size. */ 1372 int defip_table_size; /* Route table size. */ 1373 int index; /* Iteration index. */ 1374 int v6; /* IP version. */ 1375 1376 /* Calculate sw image type & number of prefixes based on memory name. */ 1377 v6 = (EXT_IPV4_DEFIPm == mem) ? _TR_LPM_IPV4 : _TR_LPM_IPV6; 1378 num_prefixes = _TR_LPM_PREFIX_MAX(mem); 1379 1380 /* Allocate prefix tracking table. */ 1381 pfx_state_size = sizeof(_tr_ext_lpm_state_t) * (num_prefixes); 1382 if (!_TR_LPM_INIT_CHECK(unit, v6)) { 1383 _TR_LPM_STATE(unit, v6) = (_tr_ext_lpm_state_t *)sal_alloc(pfx_state_size, "LPM prefix info"); 1384 if (NULL == _TR_LPM_STATE(unit, v6)) { 1385 return (BCM_E_MEMORY); 1386 } 1387 } 1388 1389 /* Initialize prefix tracking table. */ 1390 sal_memset(_TR_LPM_STATE(unit, v6), 0, pfx_state_size); 1391 1392 for(index = 0; index < num_prefixes; index++) { 1393 _TR_LPM_STATE_START(unit, v6, index) = -1; 1394 _TR_LPM_STATE_END(unit, v6, index) = -1; 1395 _TR_LPM_STATE_PREV(unit, v6, index) = -1; 1396 _TR_LPM_STATE_NEXT(unit, v6, index) = -1; 1397 _TR_LPM_STATE_VENT(unit, v6, index) = 0; 1398 _TR_LPM_STATE_FENT(unit, v6, index) = 0; 1399 } 1400 1401 /* Allocate sw image based on number of entries in the memory. */ 1402 defip_table_size = soc_mem_index_count(unit, mem); 1403 _TR_LPM_STATE_FENT(unit, v6, num_prefixes - 1) = defip_table_size; 1404 1405 /* If image was previously allocated free it. */ 1406 if (_TR_LPM_SW_IMAGE(unit, v6) != NULL) { 1407 if (BCM_FAILURE(_tr_lpm_sw_image_destroy(unit, v6))) { 1408 return (BCM_E_INTERNAL); 1409 } 1410 } 1411 1412 /* Allocate sw image. */ 1413 if (_tr_lpm_sw_image_create(unit, v6, mem)) { 1414 return (BCM_E_MEMORY); 1415 } 1416 1417 return(BCM_E_NONE); 1418 } 1419 1420 /* 1421 * Function: 1422 * _bcm_tr_ext_lpm_deinit 1423 * Purpose: 1424 * De-initialize external route table sw image. 1425 * Parameters: 1426 * unit - (IN)SOC unit number. 1427 * mem - (IN)External route table memory name. 1428 * Returns: 1429 * BCM_E_XXX 1430 */ 1431 int 1432 _bcm_tr_ext_lpm_deinit(int unit, soc_mem_t mem) 1433 { 1434 int rv; /* Operation return status. */ 1435 int v6; /* IP version. */ 1436 1437 v6 = (EXT_IPV4_DEFIPm == mem) ? _TR_LPM_IPV4 : _TR_LPM_IPV6; 1438 1439 rv = _tr_lpm_sw_image_destroy(unit, v6); 1440 1441 if (_TR_LPM_STATE(unit, v6) != NULL) { 1442 sal_free(_TR_LPM_STATE(unit, v6)); 1443 _TR_LPM_STATE(unit, v6) = NULL; 1444 } 1445 return(rv); 1446 } 1447 1448 #if defined(BCM_WARM_BOOT_SUPPORT) 1449 /* 1450 * Function: 1451 * _bcm_tr_ext_lpm_reinit_done 1452 * Purpose: 1453 * Re-initialize external route table sw image 1454 * prefix ranges completion call. 1455 * Parameters: 1456 * unit - (IN)SOC unit number. 1457 * mem - (IN)External route table memory name. 1458 * Returns: 1459 * BCM_E_XXX 1460 */ 1461 STATIC int 1462 _bcm_tr_ext_lpm_reinit_done(int unit, soc_mem_t mem) 1463 { 1464 int idx; /* Prefix length iteration index. */ 1465 int num_prefixes; /* Number of different prefixes. */ 1466 int prev_idx; /* Prefix length iteration index. */ 1467 int defip_table_size; /* Entry count in route table. */ 1468 int v6; /* IPv6 route indicator. */ 1469 1470 num_prefixes = _TR_LPM_PREFIX_MAX_INDEX(mem); 1471 prev_idx = num_prefixes; 1472 defip_table_size = soc_mem_index_count(unit, mem); 1473 v6 = (EXT_IPV4_DEFIPm != mem); 1474 1475 _TR_LPM_STATE_PREV(unit, v6, num_prefixes) = -1; 1476 1477 for (idx = num_prefixes; idx > 0 ; idx--) { 1478 if (-1 == _TR_LPM_STATE_START(unit, v6, idx)) { 1479 continue; 1480 } 1481 1482 _TR_LPM_STATE_PREV(unit, v6, idx) = prev_idx; 1483 _TR_LPM_STATE_NEXT(unit, v6, prev_idx) = idx; 1484 1485 _TR_LPM_STATE_FENT(unit, v6, prev_idx) = \ 1486 _TR_LPM_STATE_START(unit, v6, idx) - \ 1487 _TR_LPM_STATE_END(unit, v6, prev_idx) - 1; 1488 prev_idx = idx; 1489 1490 } 1491 1492 _TR_LPM_STATE_NEXT(unit, v6, prev_idx) = -1; 1493 _TR_LPM_STATE_FENT(unit, v6, prev_idx) = \ 1494 defip_table_size - \ 1495 _TR_LPM_STATE_END(unit, v6, prev_idx) - 1; 1496 1497 return (BCM_E_NONE); 1498 } 1499 1500 /* 1501 * Function: 1502 * _bcm_tr_ext_lpm_reinit 1503 * Purpose: 1504 * Re-initialize external route table sw image. 1505 * Parameters: 1506 * unit - (IN)SOC unit number. 1507 * mem - (IN)External route table memory name. 1508 * idx - (IN)Entry index. 1509 * lpm_cfg - (IN)Entry index. 1510 * Returns: 1511 * BCM_E_XXX 1512 */ 1513 STATIC int 1514 _bcm_tr_ext_lpm_reinit(int unit, soc_mem_t mem, 1515 int idx, _bcm_defip_cfg_t *lpm_cfg) 1516 { 1517 int pfx_len; 1518 int v6; 1519 1520 if (NULL == lpm_cfg) { 1521 return (BCM_E_PARAM); 1522 } 1523 1524 v6 = (lpm_cfg->defip_flags & BCM_L3_IP6) ? 1 : 0; 1525 1526 BCM_IF_ERROR_RETURN 1527 (_tr_ext_lpm_prefix_length_get(unit, lpm_cfg, &pfx_len)); 1528 1529 if (_TR_LPM_STATE_VENT(unit, v6, pfx_len) == 0) { 1530 _TR_LPM_STATE_START(unit, v6, pfx_len) = idx; 1531 _TR_LPM_STATE_END(unit, v6, pfx_len) = idx; 1532 } else { 1533 _TR_LPM_STATE_END(unit, v6, pfx_len) = idx; 1534 } 1535 1536 _TR_LPM_STATE_VENT(unit, v6, pfx_len)++; 1537 1538 return (BCM_E_NONE); 1539 } 1540 #endif /* BCM_WARM_BOOT_SUPPORT */ 1541 1542 /* 1543 * Function: 1544 * _bcm_tr_ext_lpm_add 1545 * Purpose: 1546 * Insert prefix, vrf in external route table. 1547 * Parameters: 1548 * unit - (IN) BCM device number. 1549 * data - (IN) Inserted entry. 1550 * nh_ecmp_idx - (IN) Next hop ecmp index. 1551 * Returns: 1552 * BCM_E_XXX 1553 */ 1554 int 1555 _bcm_tr_ext_lpm_add(int unit, _bcm_defip_cfg_t *data, int nh_ecmp_idx) 1556 { 1557 int rv; /* Operation return status. */ 1558 int v6; /* IP protocol version. */ 1559 int pfx; /* VRF weighted prefix length.*/ 1560 1561 /* Input parameters sanitcy check */ 1562 if (NULL == data) { 1563 return (BCM_E_PARAM); 1564 } 1565 1566 v6 = _TR_LPM_ROUTE_IS_V6(data); 1567 1568 /* Calculate vrf weighted prefix lengh. */ 1569 _tr_ext_lpm_prefix_length_get(unit, data, &pfx); 1570 1571 rv = _tr_ext_lpm_match(unit, data, pfx, &data->defip_index); 1572 if (BCM_SUCCESS(rv)) { 1573 /* Entry already present. Update the entry */ 1574 rv = _tr_ext_lpm_write(unit, data, nh_ecmp_idx); 1575 } else if (rv == BCM_E_NOT_FOUND) { 1576 1577 1578 /* Allocate free slot for entry. */ 1579 rv = _tr_ext_lpm_free_slot_create(unit, v6, pfx, 1580 &data->defip_index); 1581 if (BCM_SUCCESS(rv)) { 1582 rv = _tr_ext_lpm_write(unit, data, nh_ecmp_idx); 1583 if (BCM_SUCCESS(rv)) { 1584 rv = _tr_ext_lpm_sw_entry_insert(unit, data); 1585 } 1586 if (BCM_SUCCESS(rv)) { 1587 BCM_XGS3_L3_DEFIP_CNT_INC(unit, v6); 1588 } 1589 } 1590 } 1591 return(rv); 1592 } 1593 1594 /* 1595 * Function: 1596 * _bcm_tr_ext_lpm_delete 1597 * Purpose: 1598 * Delete entry matching prefix, vrf in external route table. 1599 * Parameters: 1600 * unit - (IN) BCM device number. 1601 * key - (IN) Lookup key. 1602 * Returns: 1603 * BCM_E_XXX 1604 */ 1605 int 1606 _bcm_tr_ext_lpm_delete(int unit, _bcm_defip_cfg_t *key) 1607 { 1608 int rv; /* Operation return status. */ 1609 int v6; /* IP protocol version. */ 1610 int pfx; /* VRF weighted prefix length.*/ 1611 1612 /* Input parameters sanitcy check */ 1613 if (NULL == key) { 1614 return (BCM_E_PARAM); 1615 } 1616 1617 v6 = _TR_LPM_ROUTE_IS_V6(key); 1618 /* Calculate vrf weighted prefix lengh. */ 1619 _tr_ext_lpm_prefix_length_get(unit, key, &pfx); 1620 1621 rv = _tr_ext_lpm_match(unit, key, pfx, &key->defip_index); 1622 1623 if (BCM_SUCCESS(rv)) { 1624 _tr_ext_lpm_sw_entry_delete(unit, key); 1625 1626 rv = _tr_ext_lpm_free_slot_delete(unit, v6, pfx, key->defip_index); 1627 1628 if (BCM_SUCCESS(rv)) { 1629 BCM_XGS3_L3_DEFIP_CNT_DEC(unit, v6); 1630 } 1631 } 1632 return(rv); 1633 } 1634 1635 /* 1636 * Function: 1637 * _bcm_tr_ext_lpm_match 1638 * Purpose: 1639 * Find entry matching prefix, vrf in external route table. 1640 * Parameters: 1641 * unit - (IN) BCM device number. 1642 * key - (IN/OUT) (IN)Lookup key (OUT) Entry data if found. 1643 * index - (OUT) Next hop index. 1644 * Returns: 1645 * BCM_E_XXX 1646 */ 1647 int 1648 _bcm_tr_ext_lpm_match(int unit, _bcm_defip_cfg_t *key, int *next_hop_index) 1649 { 1650 int rv; /* Operation return status. */ 1651 int v6; /* IP protocol version. */ 1652 int index; /* Entry index if found. */ 1653 int pfx; /* VRF weighted prefix length.*/ 1654 1655 1656 /* Input parameters sanitcy check */ 1657 if (NULL == key) { 1658 return (BCM_E_PARAM); 1659 } 1660 1661 v6 = _TR_LPM_ROUTE_IS_V6(key); 1662 /* Calculate vrf weighted prefix lengh. */ 1663 _tr_ext_lpm_prefix_length_get(unit, key, &pfx); 1664 1665 rv = _tr_ext_lpm_match(unit, key, pfx, &index); 1666 if (BCM_SUCCESS(rv)) { 1667 rv = _tr_ext_lpm_read_route_data(unit, v6, index, key->defip_sub_len, 1668 key, next_hop_index); 1669 } 1670 return(rv); 1671 } 1672 1673 #ifdef BCM_WARM_BOOT_SUPPORT 1674 /* 1675 * Function: 1676 * _tr_ext_lpm_ip6_mask_len 1677 * Purpose: 1678 * Return ipv6 mask length given ipv6 mask. 1679 * Parameters: 1680 * bcm_ip6_t: ip6mask 1681 * Returns: 1682 * int: ipv6 mask length 1683 */ 1684 STATIC int 1685 _tr_ext_lpm_ip6_mask_len(bcm_ip6_t ip6mask) 1686 { 1687 int idx, tempcount, masklen = 0; 1688 uint32 maskbits; 1689 1690 for (idx = 0; idx < 16; idx++) { 1691 maskbits = ip6mask[idx]; 1692 for( tempcount = 0; maskbits; tempcount++) { 1693 maskbits &= (maskbits - 1); 1694 } 1695 masklen += tempcount; 1696 } 1697 return masklen; 1698 } 1699 1700 /* 1701 * Function: 1702 * _bcm_tr_ext_lpm_state_recover 1703 * Purpose: 1704 * Reconstruct LPM s/w state from ESM. 1705 * Reconstruct s/w FIB4 and FIB6 state from ESM. 1706 * Parameters: 1707 * unit - (IN) BCM device number. 1708 * v6 - Flag to indicate entry is ipv4/ipv6. 1709 * Returns: 1710 * BCM_E_XXX 1711 */ 1712 STATIC int 1713 _bcm_tr_ext_lpm_state_recover(int unit, int v6) 1714 { 1715 int rv, idx; 1716 int nh_ecmp_idx, vrf_fld_len; 1717 uint32 usage_buf[2]; 1718 uint32 v4_mask, vrf_fld_mask, prfx = 0; 1719 soc_mem_t mem, data_mem, hit_bit_mem; 1720 uint32 buf[SOC_MAX_MEM_FIELD_WORDS]; 1721 uint32 data_buf[SOC_MAX_MEM_FIELD_WORDS]; 1722 bcm_ip6_t v6_64_mask, v6_128_mask; 1723 ip6_addr_t v6_addr; 1724 bcm_vrf_t vrf, vrf_hi, vrf_mask, vrf_mask_hi; 1725 _bcm_defip_cfg_t *lpm_cfg; 1726 1727 lpm_cfg = sal_alloc(sizeof(_bcm_defip_cfg_t), "TR route table"); 1728 if (NULL == lpm_cfg) { 1729 return (BCM_E_MEMORY); 1730 } 1731 sal_memset(lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 1732 1733 /* Get table memory. */ 1734 mem = _TR_LPM_MEM(unit, v6); 1735 data_mem = _TR_LPM_DATA_MEM(unit, v6); 1736 hit_bit_mem = _TR_LPM_HIT_BIT_MEM(unit, v6); 1737 1738 for (idx = 0; idx < soc_mem_index_count(unit, mem); idx++) { 1739 1740 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx, buf); 1741 if (!BCM_SUCCESS(rv)) { 1742 sal_free(lpm_cfg); 1743 return rv; 1744 } 1745 1746 if (soc_mem_field32_get(unit, mem, buf, VALIDf) == 0) { 1747 continue; 1748 } 1749 1750 if (v6) { /*Ipv6 entries */ 1751 1752 if (SOC_MEM_FIELD_VALID(unit, mem, IP_ADDRf)) { 1753 /* EXT_IPV6_64_DEFIPm */ 1754 soc_mem_ip6_addr_get(unit, mem, buf, IP_ADDRf, v6_addr, 1755 SOC_MEM_IP6_UPPER_ONLY); 1756 sal_memcpy(_TR_LPM_FIB6(unit)[idx].addr, v6_addr, 1757 sizeof(ip6_addr_t)); 1758 bcm_ip6_mask_create(v6_64_mask, 0); 1759 soc_mem_ip6_addr_mask_get(unit, mem, buf, MASK_IP_ADDRf, 1760 v6_64_mask, SOC_MEM_IP6_UPPER_ONLY); 1761 prfx = _tr_ext_lpm_ip6_mask_len(v6_64_mask); 1762 } else { /* EXT_IPV6_128_DEFIPm */ 1763 soc_mem_ip6_addr_get(unit, mem, buf, IP_ADDR_HIf, v6_addr, 1764 SOC_MEM_IP6_UPPER_ONLY); 1765 soc_mem_ip6_addr_get(unit, mem, buf, IP_ADDR_LOf, v6_addr, 1766 SOC_MEM_IP6_LOWER_ONLY); 1767 sal_memcpy(_TR_LPM_FIB6(unit)[idx].addr, v6_addr, 1768 sizeof(ip6_addr_t)); 1769 1770 bcm_ip6_mask_create(v6_128_mask, 0); 1771 soc_mem_ip6_addr_mask_get(unit, mem, buf, MASK_IP_ADDR_HIf, 1772 v6_128_mask, SOC_MEM_IP6_UPPER_ONLY); 1773 soc_mem_ip6_addr_mask_get(unit, mem, buf, MASK_IP_ADDR_LOf, 1774 v6_128_mask, SOC_MEM_IP6_LOWER_ONLY); 1775 prfx = _tr_ext_lpm_ip6_mask_len(v6_128_mask); 1776 } 1777 } else { /* Ipv4 entries - EXT_IPV4_DEFIPm */ 1778 1779 _TR_LPM_FIB4(unit)[idx].addr = 1780 soc_mem_field32_get(unit, mem, buf, IP_ADDRf); 1781 v4_mask = soc_mem_field32_get(unit, mem, buf, MASK_IP_ADDRf); 1782 for( prfx = 0; v4_mask; prfx++) { 1783 v4_mask &= (v4_mask - 1); 1784 } 1785 prfx = _TR_LPM_PREFIX_COUNT(mem) - prfx - 1; 1786 } 1787 1788 /* Common to IPv4 and IPv6 */ 1789 vrf_fld_len = soc_mem_field_length(unit, mem, VRF_LOf); 1790 vrf_fld_mask = (1 << vrf_fld_len) - 1; 1791 vrf = vrf_fld_mask & soc_mem_field32_get(unit, mem, buf, VRF_LOf); 1792 if (SOC_MEM_FIELD_VALID(unit, mem, VRF_HIf)) { 1793 vrf_hi = soc_mem_field32_get(unit, mem, buf, VRF_HIf); 1794 vrf |= vrf_hi << vrf_fld_len; 1795 } 1796 1797 vrf_mask = vrf_fld_mask & soc_mem_mask_field32_get(unit, mem, buf, 1798 MASK_VRF_LOf); 1799 if (SOC_MEM_FIELD_VALID(unit, mem, VRF_HIf)) { 1800 vrf_mask_hi = soc_mem_field32_get(unit, mem, buf, 1801 MASK_VRF_HIf); 1802 vrf_mask |= vrf_mask_hi << vrf_fld_len; 1803 } 1804 1805 1806 if (v6) { 1807 _TR_LPM_FIB6(unit)[idx].vrf = bcm_ext_lpm_vrf_get( unit, vrf, 1808 vrf_mask, soc_mem_field32_get(unit, mem, buf, 1809 GLOBAL_ROUTEf)); 1810 } else { 1811 _TR_LPM_FIB4(unit)[idx].vrf = bcm_ext_lpm_vrf_get( unit, vrf, 1812 vrf_mask, soc_mem_field32_get(unit, mem, buf, 1813 GLOBAL_ROUTEf)); 1814 } 1815 1816 rv = soc_mem_read(unit, data_mem, MEM_BLOCK_ANY, idx, data_buf); 1817 if (!BCM_SUCCESS(rv)) { 1818 sal_free(lpm_cfg); 1819 return rv; 1820 } 1821 1822 rv = soc_mem_read(unit, hit_bit_mem, MEM_BLOCK_ANY, 1823 (idx >> 5), usage_buf); 1824 if (!BCM_SUCCESS(rv)) { 1825 sal_free(lpm_cfg); 1826 return rv; 1827 } 1828 1829 _tr_ext_lpm_parse_route_data(unit, v6, idx, prfx, data_buf, 1830 usage_buf, lpm_cfg, &nh_ecmp_idx); 1831 _tr_ext_lpm_sw_entry_insert(unit, lpm_cfg); 1832 _bcm_tr_ext_lpm_reinit(unit, mem, idx, lpm_cfg); 1833 } 1834 1835 _bcm_tr_ext_lpm_reinit_done(unit, mem); 1836 1837 sal_free(lpm_cfg); 1838 return BCM_E_NONE; 1839 } 1840 #endif /* BCM_WARM_BOOT_SUPPORT */ 1841 1842 /* 1843 * Function: 1844 * _bcm_tr_ext_defip_traverse 1845 * Purpose: 1846 * Traverse all LPM entries, call back the test 1847 * function and save entries which pass. After a configuration number 1848 * of entries are saved, call back the operation function on each. 1849 * Repeat from beginning of table after operations are complete. 1850 * Continue until the no entries test TRUE. 1851 * Parameters: 1852 * unit - BCM device number. 1853 * trv_data - (IN)Delete pattern + compare,act,notify routines. 1854 * Notes: 1855 * The test function must not perform any changes to the 1856 * table. Also, it must know how to exclude entries which have 1857 * already been processed by the operation function. Otherwise, the 1858 * loop may never terminate. 1859 * The operation function may update the table. 1860 * We require to pass table index so caller can acccess entry hit 1861 * information for traverse & aging functionalities. 1862 * Table index is not available during op callback and should be ignored. 1863 */ 1864 int 1865 _bcm_tr_defip_traverse(int unit, _bcm_l3_trvrs_data_t *trv_data) 1866 { 1867 _bcm_defip_cfg_t *search_data_array; 1868 int *nh_array; 1869 uint32 *lpm_data; 1870 uint32 *usage_data; 1871 int dma_start; 1872 int alloc_sz; 1873 char *dma_ptr; 1874 char *usage_dma_ptr; 1875 int dma_end; 1876 int idx; 1877 soc_mem_t mem; 1878 int curr_pfx; 1879 int v6; 1880 int array_index; 1881 int rv=SOC_E_NONE; 1882 int cmp_result = BCM_L3_CMP_NOT_EQUAL; 1883 1884 1885 v6 = (trv_data->flags & BCM_L3_IP6) ? 1 : 0 ; 1886 1887 alloc_sz = _TR_LPM_BLOCK_SZ * sizeof(_bcm_defip_cfg_t); 1888 search_data_array = sal_alloc(alloc_sz, "TR route table"); 1889 if (NULL == search_data_array) { 1890 return (BCM_E_MEMORY); 1891 } 1892 sal_memset(search_data_array, 0, alloc_sz); 1893 1894 alloc_sz = _TR_LPM_BLOCK_SZ * sizeof(int); 1895 nh_array = sal_alloc(alloc_sz, "TR route table"); 1896 if (NULL == nh_array) { 1897 sal_free(search_data_array); 1898 return (BCM_E_MEMORY); 1899 } 1900 sal_memset(nh_array, 0, alloc_sz); 1901 1902 alloc_sz = _TR_LPM_BLOCK_SZ * sizeof(ext_defip_data_entry_t); 1903 dma_ptr = soc_cm_salloc(unit, alloc_sz, "TR route table dma"); 1904 if (NULL == dma_ptr) { 1905 sal_free(nh_array); 1906 sal_free(search_data_array); 1907 return (BCM_E_MEMORY); 1908 } 1909 1910 alloc_sz = _TR_LPM_BLOCK_SZ * sizeof(ext_dst_hit_bits_entry_t); 1911 usage_dma_ptr = soc_cm_salloc(unit, alloc_sz, "TR route table hit bits"); 1912 if (NULL == usage_dma_ptr) { 1913 sal_free(nh_array); 1914 sal_free(search_data_array); 1915 soc_cm_sfree(unit, dma_ptr); 1916 return (BCM_E_MEMORY); 1917 } 1918 1919 /* Get table memory. */ 1920 mem = _TR_LPM_MEM(unit, v6); 1921 1922 #ifdef BCM_WARM_BOOT_SUPPORT 1923 /* Reconstruct EXT LPM s/w state */ 1924 if (SOC_WARM_BOOT(unit)) { 1925 _bcm_tr_ext_lpm_state_recover(unit, v6); 1926 } 1927 #endif /* BCM_WARM_BOOT_SUPPORT */ 1928 1929 while (1) { 1930 array_index = 0; 1931 curr_pfx = _TR_LPM_PREFIX_MAX_INDEX(mem); 1932 1933 /* Iterate over prefixes to fill search data. */ 1934 while (curr_pfx != -1) { 1935 1936 /* Skip empty prefixes. */ 1937 if (0 == _TR_LPM_STATE_VENT(unit, v6, curr_pfx)) { 1938 curr_pfx = _TR_LPM_STATE_NEXT(unit, v6, curr_pfx); 1939 continue; 1940 } 1941 1942 /* Read entries for current prefix. */ 1943 for(dma_start = _TR_LPM_STATE_START(unit, v6, curr_pfx); 1944 dma_start <= _TR_LPM_STATE_END(unit, v6, curr_pfx); 1945 dma_start += _TR_LPM_BLOCK_SZ) { 1946 1947 dma_end = dma_start + _TR_LPM_BLOCK_SZ - 1; 1948 if (dma_end > _TR_LPM_STATE_END(unit, v6, curr_pfx)) { 1949 dma_end = _TR_LPM_STATE_END(unit, v6, curr_pfx); 1950 } 1951 rv = soc_mem_read_range(unit, _TR_LPM_DATA_MEM(unit, v6), 1952 MEM_BLOCK_ANY, dma_start, dma_end, 1953 dma_ptr); 1954 if (rv < 0) { 1955 soc_cm_sfree(unit, dma_ptr); 1956 soc_cm_sfree(unit, usage_dma_ptr); 1957 sal_free(search_data_array); 1958 sal_free(nh_array); 1959 return (rv); 1960 } 1961 1962 rv = soc_mem_read_range(unit, _TR_LPM_HIT_BIT_MEM(unit, v6), 1963 MEM_BLOCK_ANY, (dma_start >> 5), 1964 (dma_end >> 5), usage_dma_ptr); 1965 if (BCM_FAILURE(rv)) { 1966 soc_cm_sfree(unit, dma_ptr); 1967 soc_cm_sfree(unit, usage_dma_ptr); 1968 sal_free(search_data_array); 1969 sal_free(nh_array); 1970 return (rv); 1971 } 1972 1973 for(idx = (dma_end - dma_start); idx >= 0; idx--) { 1974 /* Calculate entry offset. */ 1975 lpm_data = soc_mem_table_idx_to_pointer 1976 (unit, _TR_LPM_DATA_MEM(unit, v6), 1977 uint32 *, dma_ptr, idx); 1978 1979 /* Calculate hit bit entry offset. */ 1980 usage_data = soc_mem_table_idx_to_pointer 1981 (unit, _TR_LPM_HIT_BIT_MEM(unit, v6), 1982 uint32 *, usage_dma_ptr, (idx >> 5)); 1983 1984 /* Parse route entry. */ 1985 _tr_ext_lpm_parse_route_data(unit, v6, 1986 dma_start + idx, 1987 (curr_pfx % _TR_LPM_PREFIX_COUNT(mem)), 1988 lpm_data, usage_data, 1989 (search_data_array + array_index), 1990 (nh_array + array_index)); 1991 1992 /* Execute test routine if any. */ 1993 if (NULL != trv_data->cmp_cb) { 1994 rv = (*trv_data->cmp_cb) (unit, (void *)trv_data, 1995 (void *)(search_data_array + array_index), 1996 (void *)(nh_array + array_index), 1997 &cmp_result); 1998 if (BCM_FAILURE(rv)) { 1999 soc_cm_sfree(unit, dma_ptr); 2000 soc_cm_sfree(unit, usage_dma_ptr); 2001 sal_free(nh_array); 2002 sal_free(search_data_array); 2003 return rv; 2004 } 2005 } 2006 2007 if ((BCM_L3_CMP_EQUAL == cmp_result) || 2008 (NULL == trv_data->cmp_cb)) { 2009 array_index++; 2010 if (array_index >= _TR_LPM_BLOCK_SZ) { 2011 break; 2012 } 2013 } 2014 } 2015 if (array_index >= _TR_LPM_BLOCK_SZ) { 2016 break; 2017 } 2018 } 2019 if (array_index >= _TR_LPM_BLOCK_SZ) { 2020 break; 2021 } 2022 curr_pfx = _TR_LPM_STATE_NEXT(unit, v6, curr_pfx); 2023 } 2024 2025 for (idx = 0; idx < array_index; idx++) { 2026 /* Execute operation routine if any. */ 2027 if (NULL != trv_data->op_cb) { 2028 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 2029 (void *)(search_data_array + idx), 2030 (void *)(nh_array + idx), &cmp_result); 2031 if (rv < 0) { 2032 soc_cm_sfree(unit, dma_ptr); 2033 soc_cm_sfree(unit, usage_dma_ptr); 2034 sal_free(nh_array); 2035 sal_free(search_data_array); 2036 return (rv); 2037 } 2038 } 2039 } 2040 2041 if (0 == array_index) { 2042 break; 2043 } 2044 } 2045 2046 soc_cm_sfree(unit, dma_ptr); 2047 soc_cm_sfree(unit, usage_dma_ptr); 2048 sal_free(search_data_array); 2049 sal_free(nh_array); 2050 return (rv); 2051 } 2052 2053 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP 2054 /* 2055 * Function: 2056 * tr_ext_lpm_sw_dump 2057 * Purpose: 2058 * Displays ESM LPM information maintained by software. 2059 * Parameters: 2060 * unit - Device unit number 2061 * Returns: 2062 * None 2063 */ 2064 void 2065 _bcm_tr_ext_lpm_sw_dump(int unit) 2066 { 2067 soc_mem_t mem; 2068 int i; 2069 _tr_lpm_sw_image_p v4, v6; 2070 2071 v4 = _TR_LPM_SW_IMAGE(unit, _TR_LPM_IPV4); 2072 v6 = _TR_LPM_SW_IMAGE(unit, _TR_LPM_IPV6); 2073 2074 LOG_CLI((BSL_META_U(unit, 2075 "\n TRIUMPH External LPM State -\n"))); 2076 if ((NULL == v4) && (NULL == v6)) { 2077 LOG_CLI((BSL_META_U(unit, 2078 " ESM not present!\n"))); 2079 return; 2080 } 2081 2082 if (NULL != v4) { 2083 LOG_CLI((BSL_META_U(unit, 2084 " IPv4 Prefix entries:\n"))); 2085 mem = _TR_LPM_MEM(unit, _TR_LPM_IPV4); 2086 2087 for (i = 0; i < _TR_LPM_PREFIX_MAX(mem); i++) { 2088 if (_TR_LPM_STATE_VENT(unit, _TR_LPM_IPV4, i) != 0) { 2089 LOG_CLI((BSL_META_U(unit, 2090 " Prefix length (bits): %d\n"), 2091 (i%_TR_LPM_PREFIX_COUNT(mem)))); 2092 LOG_CLI((BSL_META_U(unit, 2093 " Start : %d\n"), 2094 _TR_LPM_STATE_START(unit, _TR_LPM_IPV4, i))); 2095 LOG_CLI((BSL_META_U(unit, 2096 " End : %d\n"), 2097 _TR_LPM_STATE_END(unit, _TR_LPM_IPV4, i))); 2098 LOG_CLI((BSL_META_U(unit, 2099 " Prev : %d\n"), 2100 _TR_LPM_STATE_PREV(unit, _TR_LPM_IPV4, i))); 2101 LOG_CLI((BSL_META_U(unit, 2102 " Next : %d\n"), 2103 _TR_LPM_STATE_NEXT(unit, _TR_LPM_IPV4, i))); 2104 LOG_CLI((BSL_META_U(unit, 2105 " Valid Entries : %d\n"), 2106 _TR_LPM_STATE_VENT(unit, _TR_LPM_IPV4, i))); 2107 LOG_CLI((BSL_META_U(unit, 2108 " Free Entries : %d\n"), 2109 _TR_LPM_STATE_FENT(unit, _TR_LPM_IPV4, i))); 2110 } 2111 } 2112 } 2113 2114 if (NULL != v6) { 2115 LOG_CLI((BSL_META_U(unit, 2116 "\n IPv6 Prefix entries: \n" ))); 2117 mem = _TR_LPM_MEM(unit, _TR_LPM_IPV6); 2118 2119 for (i = 0; i < _TR_LPM_PREFIX_MAX(mem); i++) { 2120 if (_TR_LPM_STATE_VENT(unit, _TR_LPM_IPV6, i) != 0) { 2121 LOG_CLI((BSL_META_U(unit, 2122 " Prefix length (bits): %d\n"), 2123 (i%_TR_LPM_PREFIX_COUNT(mem)))); 2124 LOG_CLI((BSL_META_U(unit, 2125 " Start : %d\n"), 2126 _TR_LPM_STATE_START(unit, _TR_LPM_IPV6, i))); 2127 LOG_CLI((BSL_META_U(unit, 2128 " End : %d\n"), 2129 _TR_LPM_STATE_END(unit, _TR_LPM_IPV6, i))); 2130 LOG_CLI((BSL_META_U(unit, 2131 " Prev : %d\n"), 2132 _TR_LPM_STATE_PREV(unit, _TR_LPM_IPV6, i))); 2133 LOG_CLI((BSL_META_U(unit, 2134 " Next : %d\n"), 2135 _TR_LPM_STATE_NEXT(unit, _TR_LPM_IPV6, i))); 2136 LOG_CLI((BSL_META_U(unit, 2137 " Valid Entries : %d\n"), 2138 _TR_LPM_STATE_VENT(unit, _TR_LPM_IPV6, i))); 2139 LOG_CLI((BSL_META_U(unit, 2140 " Free Entries : %d\n"), 2141 _TR_LPM_STATE_FENT(unit, _TR_LPM_IPV6, i))); 2142 } 2143 } 2144 } 2145 return; 2146 } 2147 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */ 2148 2149 2150 2151 #else /* BCM_TRIUMPH_SUPPORT && INCLUDE_L3 */ 2152 int bcm_esw_triumph_external_lpm_not_empty; 2153 #endif /* BCM_TRIUMPH_SUPPORT && INCLUDE_L3 */ 2154