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