l3.c (23531B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * Hurricane2 LPM implementation 8 */ 9 10 #include <bcm/types.h> 11 #include <soc/hurricane2.h> 12 #if defined(INCLUDE_L3) 13 #include <bcm_int/esw/hurricane2.h> 14 #include <shared/l3.h> 15 #if defined(BCM_HURRICANE3_SUPPORT) 16 #include <soc/hurricane3.h> 17 #endif /* BCM_HURRICANE3_SUPPORT */ 18 19 #define SOC_HU2_L3_VRF_DEFAULT _SHR_L3_VRF_DEFAULT /* Default vrf id. */ 20 21 /* 22 * Function: 23 * _bcm_hu2_mem_ip6_defip_set 24 * Purpose: 25 * Set an IP6 address field in L3_DEFIPm 26 * Parameters: 27 * unit - (IN) SOC unit number; 28 * lpm_key - (OUT) Buffer to fill. 29 * lpm_cfg - (IN) Route information. 30 * Note: 31 * See soc_mem_ip6_addr_set() 32 */ 33 STATIC void 34 _bcm_hu2_mem_ip6_defip_set(int unit, void *lpm_key, _bcm_defip_cfg_t *lpm_cfg) 35 { 36 uint8 *ip6; /* Ip6 address. */ 37 uint8 mask[BCM_IP6_ADDRLEN]; /* Subnet mask. */ 38 uint32 ip6_word; /* Temp storage. */ 39 int idx; /* Iteration index . */ 40 41 /* Just to keep variable name short. */ 42 ip6 = lpm_cfg->defip_ip6_addr; 43 44 /* Create mask from prefix length. */ 45 bcm_ip6_mask_create(mask, lpm_cfg->defip_sub_len); 46 47 /* Apply subnet mask */ 48 idx = lpm_cfg->defip_sub_len / 8; /* Unchanged byte count. */ 49 ip6[idx] &= mask[idx]; /* Apply mask on next byte. */ 50 for (idx++; idx < BCM_IP6_ADDRLEN; idx++) { 51 ip6[idx] = 0; /* Reset rest of bytes. */ 52 } 53 54 55 ip6_word = ((ip6[0] << 24) | (ip6[1] << 16) | (ip6[2] << 8) | (ip6[3])); 56 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_Uf, (void *)&ip6_word); 57 58 ip6_word = ((ip6[4] << 24) | (ip6[5] << 16) | (ip6[6] << 8) | (ip6[7])); 59 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_Lf, (void *)&ip6_word); 60 61 ip6_word = ((mask[0] << 24) | (mask[1] << 16) | (mask[2] << 8) | (mask[3])); 62 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_U_MASKf, 63 (void *)&ip6_word); 64 65 ip6_word = ((mask[4] << 24) | (mask[5] << 16) | (mask[6] << 8) | (mask[7])); 66 soc_L3_DEFIPm_field_set(unit, lpm_key, IP_ADDR_L_MASKf, 67 (void *)&ip6_word); 68 } 69 70 /* 71 * Function: 72 * _bcm_hu2_mem_ip6_defip_get 73 * Purpose: 74 * Set an IP6 address field in L3_DEFIPm 75 * Note: 76 * See soc_mem_ip6_addr_set() 77 */ 78 STATIC void 79 _bcm_hu2_mem_ip6_defip_get(int unit, const void *lpm_key, 80 _bcm_defip_cfg_t *lpm_cfg) 81 { 82 uint8 *ip6; /* Ip6 address. */ 83 uint8 mask[BCM_IP6_ADDRLEN]; /* Subnet mask. */ 84 uint32 ip6_word; /* Temp storage. */ 85 86 sal_memset(mask, 0, sizeof (bcm_ip6_t)); 87 88 /* Just to keep variable name short. */ 89 ip6 = lpm_cfg->defip_ip6_addr; 90 sal_memset(ip6, 0, sizeof (bcm_ip6_t)); 91 92 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_Uf, &ip6_word); 93 ip6[0] = (uint8) ((ip6_word >> 24) & 0xff); 94 ip6[1] = (uint8) ((ip6_word >> 16) & 0xff); 95 ip6[2] = (uint8) ((ip6_word >> 8) & 0xff); 96 ip6[3] = (uint8) (ip6_word & 0xff); 97 98 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_Lf, &ip6_word); 99 ip6[4] = (uint8) ((ip6_word >> 24) & 0xff); 100 ip6[5] = (uint8) ((ip6_word >> 16) & 0xff); 101 ip6[6] = (uint8) ((ip6_word >> 8) & 0xff); 102 ip6[7] = (uint8) (ip6_word & 0xff); 103 104 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_U_MASKf, &ip6_word); 105 mask[0] = (uint8) ((ip6_word >> 24) & 0xff); 106 mask[1] = (uint8) ((ip6_word >> 16) & 0xff); 107 mask[2] = (uint8) ((ip6_word >> 8) & 0xff); 108 mask[3] = (uint8) (ip6_word & 0xff); 109 110 soc_L3_DEFIPm_field_get(unit, lpm_key, IP_ADDR_L_MASKf, &ip6_word); 111 mask[4] = (uint8) ((ip6_word >> 24) & 0xff); 112 mask[5] = (uint8) ((ip6_word >> 16) & 0xff); 113 mask[6] = (uint8) ((ip6_word >> 8) & 0xff); 114 mask[7] = (uint8) (ip6_word & 0xff); 115 116 lpm_cfg->defip_sub_len = bcm_ip6_mask_length(mask); 117 } 118 119 /* 120 * Function: 121 * _bcm_hu2_lpm_clear_hit 122 * Purpose: 123 * Clear prefix entry hit bit. 124 * Parameters: 125 * unit - (IN)SOC unit number. 126 * lpm_cfg - (IN)Route info. 127 * lpm_entry - (IN)Buffer to write to hw. 128 * Returns: 129 * BCM_E_XXX 130 */ 131 STATIC int 132 _bcm_hu2_lpm_clear_hit(int unit, _bcm_defip_cfg_t *lpm_cfg, 133 uint32 *lpm_entry) 134 { 135 int rv; /* Operation return status. */ 136 int tbl_idx; /* Defip table index. */ 137 soc_field_t hit_field = HITf; /* HIT bit field id. */ 138 139 /* Input parameters check */ 140 if ((NULL == lpm_cfg) || (NULL == lpm_entry)) { 141 return (BCM_E_PARAM); 142 } 143 144 /* If entry was not hit clear "clear hit" and return */ 145 if (!(lpm_cfg->defip_flags & BCM_L3_HIT)) { 146 return (BCM_E_NONE); 147 } 148 149 /* Reset entry hit bit in buffer. */ 150 tbl_idx = lpm_cfg->defip_index; 151 soc_L3_DEFIPm_field32_set(unit, lpm_entry, hit_field, 0); 152 153 /* Write lpm buffer to hardware. */ 154 rv = soc_mem_write(unit, L3_DEFIPm, MEM_BLOCK_ALL, tbl_idx, lpm_entry); 155 return rv; 156 } 157 158 /* 159 * Function: 160 * _bcm_hu2_lpm_ent_init 161 * Purpose: 162 * Service routine used to initialize lkup key for lpm entry. 163 * Parameters: 164 * unit - (IN)SOC unit number. 165 * lpm_cfg - (IN)Prefix info. 166 * lpm_entry - (OUT)Hw buffer to fill. 167 * Returns: 168 * BCM_E_XXX 169 */ 170 STATIC int 171 _bcm_hu2_lpm_ent_init(int unit, _bcm_defip_cfg_t *lpm_cfg, 172 uint32 *lpm_entry) 173 { 174 bcm_ip_t ip4_mask; 175 int vrf_id; 176 int vrf_mask; 177 178 int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 179 180 /* 181 * Extract entry vrf id & vrf mask. 182 * - HR2/HR3/GH : vrf_id = 0 is expected (no VRF feature is supported) 183 * >> VRF=0 as the key for L3 host/route table hit operation. 184 * - GH2 : support 16 VRF_IDs 185 * 186 * Note : E_PARAM is returened once vrf_id is out of valid range. 187 */ 188 BCM_IF_ERROR_RETURN 189 (bcm_xgs3_internal_lpm_vrf_calc(unit, lpm_cfg, &vrf_id, &vrf_mask)); 190 191 /* Set prefix ip address & mask. */ 192 if (ipv6) { 193 _bcm_hu2_mem_ip6_defip_set(unit, lpm_entry, lpm_cfg); 194 } else { 195 ip4_mask = BCM_IP4_MASKLEN_TO_ADDR(lpm_cfg->defip_sub_len); 196 /* Apply subnet mask. */ 197 lpm_cfg->defip_ip_addr &= ip4_mask; 198 199 /* Set address to the buffer. */ 200 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR_Lf, 201 lpm_cfg->defip_ip_addr); 202 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR_L_MASKf, ip4_mask); 203 /* For IPv4 set the IP_ADDR_Uf to 0 */ 204 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR_Uf, 0); 205 soc_L3_DEFIPm_field32_set(unit, lpm_entry, IP_ADDR_U_MASKf, 0); 206 } 207 208 /* Set Virtual Router id if supported. */ 209 if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_IDf)) { 210 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_IDf, vrf_id); 211 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VRF_ID_MASKf, vrf_mask); 212 } else { 213 if (vrf_id != BCM_L3_VRF_DEFAULT) { 214 LOG_CLI((BSL_META_U(unit, 215 "LPM entry init with vrf_id=%d on device." 216 "(will be treated as vrf_id=0)\n"), vrf_id)); 217 } 218 } 219 220 /* Set valid bit. */ 221 soc_L3_DEFIPm_field32_set(unit, lpm_entry, VALIDf, 1); 222 soc_L3_DEFIPm_field32_set(unit, lpm_entry, MODEf, (ipv6) ? 1 : 0); 223 224 if (soc_mem_field_valid(unit,L3_DEFIPm, MODE_MASKf)) { 225 soc_mem_field32_set(unit,L3_DEFIPm, lpm_entry, 226 MODE_MASKf, (1 << soc_mem_field_length(unit, 227 L3_DEFIPm, MODE_MASKf)) - 1); 228 } 229 230 if (soc_mem_field_valid(unit,L3_DEFIPm, 231 RESERVED_MASKf)) { 232 soc_mem_field32_set(unit,L3_DEFIPm, 233 lpm_entry, RESERVED_MASKf, 0); 234 } 235 236 /* 237 * Set the Global route : 238 * - Global Route is meanful on device can support VRF_ID != 0 239 */ 240 if (SOC_MEM_FIELD_VALID(unit, BCM_XGS3_L3_MEM(unit, defip), VRF_IDf)) { 241 if (SOC_MEM_FIELD_VALID(unit, 242 BCM_XGS3_L3_MEM(unit, defip), GLOBAL_ROUTE0f)) { 243 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 244 soc_mem_field32_set(unit, BCM_XGS3_L3_MEM(unit, defip), 245 lpm_entry, GLOBAL_ROUTE0f, 0x1); 246 } 247 } 248 } 249 250 return (BCM_E_NONE); 251 } 252 253 /* 254 * Function: 255 * _bcm_hu2_lpm_ent_get_key 256 * Purpose: 257 * Parse entry key from DEFIP table. 258 * Parameters: 259 * unit - (IN)SOC unit number. 260 * lpm_cfg - (OUT)Buffer to fill defip information. 261 * lpm_entry - (IN) Buffer read from hw. 262 * Returns: 263 * void 264 */ 265 STATIC void 266 _bcm_hu2_lpm_ent_get_key(int unit, _bcm_defip_cfg_t *lpm_cfg, 267 uint32 *lpm_entry) 268 { 269 bcm_ip_t v4_mask; 270 int ipv6 = lpm_cfg->defip_flags & BCM_L3_IP6; 271 272 /* Set prefix ip address & mask. */ 273 if (ipv6) { 274 _bcm_hu2_mem_ip6_defip_get(unit, lpm_entry, lpm_cfg); 275 } else { 276 /* Get ipv4 address. */ 277 lpm_cfg->defip_ip_addr = 278 soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR_Lf); 279 280 /* Get subnet mask. */ 281 v4_mask = soc_L3_DEFIPm_field32_get(unit, lpm_entry, IP_ADDR_L_MASKf); 282 283 /* Fill mask length. */ 284 lpm_cfg->defip_sub_len = bcm_ip_mask_length(v4_mask); 285 } 286 287 /* Get Virtual Router id */ 288 if ((SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, VRF_ID_MASKf)) && 289 (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, VRF_IDf))) { 290 int vrf_id; 291 292 vrf_id = soc_L3_DEFIPm_field32_get(unit, lpm_entry, VRF_IDf); 293 294 /* Special vrf's handling. */ 295 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, VRF_ID_MASKf)) { 296 lpm_cfg->defip_vrf = vrf_id; 297 } else if (SOC_VRF_MAX(unit) == vrf_id) { 298 lpm_cfg->defip_vrf = BCM_L3_VRF_GLOBAL; 299 } else { 300 lpm_cfg->defip_vrf = BCM_L3_VRF_OVERRIDE; 301 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, GLOBAL_ROUTE0f)) { 302 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, GLOBAL_ROUTE0f)) { 303 lpm_cfg->defip_vrf = BCM_L3_VRF_GLOBAL; 304 } 305 } 306 } 307 } else { 308 /* No vrf support on this device. */ 309 lpm_cfg->defip_vrf = BCM_L3_VRF_DEFAULT; 310 } 311 312 return; 313 } 314 315 /* 316 * Function: 317 * _bcm_hu2_lpm_ent_parse 318 * Purpose: 319 * Parse an entry from DEFIP table. 320 * Parameters: 321 * unit - (IN)SOC unit number. 322 * lpm_cfg - (OUT)Buffer to fill defip information. 323 * nh_ecmp_idx - (OUT)Next hop index or ecmp group id. 324 * lpm_entry - (IN) Buffer read from hw. 325 * Returns: 326 * void 327 */ 328 STATIC INLINE void 329 _bcm_hu2_lpm_ent_parse(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx, 330 uint32 *lpm_entry) 331 { 332 /* Reset entry flags first. */ 333 lpm_cfg->defip_flags = 0; 334 335 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, MODEf)) { 336 lpm_cfg->defip_flags |= BCM_L3_IP6; 337 } 338 339 /* Check if entry points to ecmp group. */ 340 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP0f)) { 341 /* Mark entry as ecmp */ 342 lpm_cfg->defip_ecmp = 1; 343 lpm_cfg->defip_flags |= BCM_L3_MULTIPATH; 344 345 /* Get ecmp group id. */ 346 if (nh_ecmp_idx) { 347 *nh_ecmp_idx = 348 soc_L3_DEFIPm_field32_get(unit, lpm_entry, ECMP_PTR0f); 349 } 350 } else { 351 /* Mark entry as non-ecmp. */ 352 lpm_cfg->defip_ecmp = 0; 353 354 /* Reset ecmp group next hop count. */ 355 lpm_cfg->defip_ecmp_count = 0; 356 357 /* Get next hop index. */ 358 if (nh_ecmp_idx) { 359 *nh_ecmp_idx = 360 soc_L3_DEFIPm_field32_get(unit, lpm_entry, NEXT_HOP_INDEX0f); 361 } 362 } 363 /* Get entry priority. */ 364 lpm_cfg->defip_prio = soc_L3_DEFIPm_field32_get(unit, lpm_entry, PRI0f); 365 366 /* Get hit bit. */ 367 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, HITf)) { 368 lpm_cfg->defip_flags |= BCM_L3_HIT; 369 } 370 371 /* Get priority override bit. */ 372 if (soc_L3_DEFIPm_field32_get(unit, lpm_entry, RPE0f)) { 373 lpm_cfg->defip_flags |= BCM_L3_RPE; 374 } 375 376 /* Get destination discard flag. */ 377 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DST_DISCARD0f)) { 378 if(soc_L3_DEFIPm_field32_get(unit, lpm_entry, DST_DISCARD0f)) { 379 lpm_cfg->defip_flags |= BCM_L3_DST_DISCARD; 380 } 381 } 382 383 /* Set classification group id. */ 384 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, CLASS_ID0f)) { 385 lpm_cfg->defip_lookup_class = 386 soc_L3_DEFIPm_field32_get(unit, lpm_entry, CLASS_ID0f); 387 } 388 389 return; 390 } 391 392 /* 393 * Function: 394 * _bcm_hu2_lpm_get 395 * Purpose: 396 * Get an entry from DEFIP table. 397 * Parameters: 398 * unit - (IN)SOC unit number. 399 * lpm_cfg - (IN)Buffer to fill defip information. 400 * nh_ecmp_idx - (IN)Next hop or ecmp group index 401 * Returns: 402 * BCM_E_XXX 403 */ 404 int 405 _bcm_hu2_lpm_get(int unit, _bcm_defip_cfg_t *lpm_cfg, int *nh_ecmp_idx) 406 { 407 uint32 lpm_key[SOC_MAX_MEM_FIELD_WORDS];/* Route lookup key. */ 408 uint32 lpm_entry[SOC_MAX_MEM_FIELD_WORDS];/* Search result buffer. */ 409 int clear_hit; /* Clear hit indicator. */ 410 int rv; /* Operation return status. */ 411 412 /* Input parameters check */ 413 if (NULL == lpm_cfg) { 414 return (BCM_E_PARAM); 415 } 416 417 /* Zero buffers. */ 418 sal_memset(lpm_entry, 0, WORDS2BYTES(SOC_MAX_MEM_FIELD_WORDS)); 419 sal_memset(lpm_key, 0, WORDS2BYTES(SOC_MAX_MEM_FIELD_WORDS)); 420 421 /* Check if clear hit bit required. */ 422 clear_hit = lpm_cfg->defip_flags & BCM_L3_HIT_CLEAR; 423 424 /* Initialize lkup key. */ 425 BCM_IF_ERROR_RETURN(_bcm_hu2_lpm_ent_init(unit, lpm_cfg, lpm_key)); 426 427 /* Perform hw lookup. */ 428 rv = soc_hu2_lpm_match(unit, lpm_key, lpm_entry, &lpm_cfg->defip_index); 429 BCM_IF_ERROR_RETURN(rv); 430 431 /* Parse hw buffer to defip entry. */ 432 _bcm_hu2_lpm_ent_parse(unit, lpm_cfg, nh_ecmp_idx, lpm_entry); 433 434 /* Clear the HIT bit */ 435 if (clear_hit) { 436 BCM_IF_ERROR_RETURN(_bcm_hu2_lpm_clear_hit(unit, lpm_cfg, lpm_entry)); 437 } 438 return (BCM_E_NONE); 439 } 440 441 /* 442 * Function: 443 * _bcm_hu2_lpm_add 444 * Purpose: 445 * Add an entry to DEFIP table. 446 * Parameters: 447 * unit - (IN)SOC unit number. 448 * lpm_cfg - (IN)Buffer to fill defip information. 449 * nh_ecmp_idx - (IN)Next hop or ecmp group index. 450 * Returns: 451 * BCM_E_XXX 452 */ 453 int 454 _bcm_hu2_lpm_add(int unit, _bcm_defip_cfg_t *lpm_cfg, int nh_ecmp_idx) 455 { 456 uint32 lpm_entry[SOC_MAX_MEM_FIELD_WORDS];/* Hw entry buffer.*/ 457 int rv; /* Operation return status. */ 458 int pri_field_len; 459 int max_pri; 460 461 /* Input parameters check */ 462 if (NULL == lpm_cfg) { 463 return (BCM_E_PARAM); 464 } 465 466 /* check if priority is over valid value */ 467 pri_field_len = soc_mem_field_length(unit, L3_DEFIPm, PRI0f); 468 max_pri = (1 << pri_field_len) - 1; 469 if (lpm_cfg->defip_prio > max_pri) { 470 return BCM_E_PARAM; 471 } 472 473 /* Zero buffers. */ 474 sal_memset(lpm_entry, 0, WORDS2BYTES(SOC_MAX_MEM_FIELD_WORDS)); 475 476 /* Set hit bit. */ 477 if (lpm_cfg->defip_flags & BCM_L3_HIT) { 478 soc_L3_DEFIPm_field32_set(unit, lpm_entry, HITf, 1); 479 } 480 481 /* Set priority override bit. */ 482 if (lpm_cfg->defip_flags & BCM_L3_RPE) { 483 soc_L3_DEFIPm_field32_set(unit, lpm_entry, RPE0f, 1); 484 } 485 486 /* Write priority field. */ 487 soc_L3_DEFIPm_field32_set(unit, lpm_entry, PRI0f, lpm_cfg->defip_prio); 488 489 /* Fill next hop information. */ 490 if (lpm_cfg->defip_flags & BCM_L3_MULTIPATH) { 491 soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP0f, 1); 492 /* NOTE: Order is important set next hop index before ECMP_COUNT. 493 * If device doesn't have ECMP_COUNT: ECMP_PTR field is shorter than 494 * next hop -> we must ensure that write resets high bits of next hop 495 * field. 496 */ 497 soc_L3_DEFIPm_field32_set(unit, lpm_entry, NEXT_HOP_INDEX0f, nh_ecmp_idx); 498 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, ECMP_COUNT0f)) { 499 soc_L3_DEFIPm_field32_set(unit, lpm_entry, ECMP_COUNT0f, 500 lpm_cfg->defip_ecmp_count); 501 } 502 } else { 503 soc_L3_DEFIPm_field32_set(unit, lpm_entry, NEXT_HOP_INDEX0f, 504 nh_ecmp_idx); 505 } 506 507 /* Set destination discard flag. */ 508 if (lpm_cfg->defip_flags & BCM_L3_DST_DISCARD) { 509 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, DST_DISCARD0f)) { 510 soc_L3_DEFIPm_field32_set(unit, lpm_entry, DST_DISCARD0f, 1); 511 } else { 512 return (BCM_E_UNAVAIL); 513 } 514 } 515 516 /* Set classification group id. */ 517 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, CLASS_ID0f)) { 518 soc_L3_DEFIPm_field32_set(unit, lpm_entry, CLASS_ID0f, 519 lpm_cfg->defip_lookup_class); 520 } 521 522 /* Set Global route flag. */ 523 if (SOC_MEM_FIELD_VALID(unit, L3_DEFIPm, GLOBAL_ROUTE0f)) { 524 if (BCM_L3_VRF_GLOBAL == lpm_cfg->defip_vrf) { 525 soc_mem_field32_set(unit, L3_DEFIPm, lpm_entry, 526 GLOBAL_ROUTE0f, 0x1); 527 } 528 } 529 530 /* 531 * Initialize hw buffer from lpm configuration. 532 * NOTE: DON'T MOVE _bcm_hu2_defip_ent_init CALL UP, 533 * We want to copy flags & nh info, avoid ipv6 mask & address corruption. 534 */ 535 BCM_IF_ERROR_RETURN(_bcm_hu2_lpm_ent_init(unit, lpm_cfg, lpm_entry)); 536 537 /* Write buffer to hw. */ 538 rv = soc_hu2_lpm_insert(unit, lpm_entry); 539 540 /* If new route added increment total number of routes. */ 541 /* Lack of index indicates a new route. */ 542 if ((rv >= 0) && (BCM_XGS3_L3_INVALID_INDEX == lpm_cfg->defip_index)) { 543 BCM_XGS3_L3_DEFIP_CNT_INC(unit, (lpm_cfg->defip_flags & BCM_L3_IP6)); 544 } 545 return rv; 546 } 547 548 /* 549 * Function: 550 * _bcm_hu2_lpm_del 551 * Purpose: 552 * Delete an entry from DEFIP table. 553 * Parameters: 554 * unit - (IN)SOC unit number. 555 * lpm_cfg - (IN)Buffer to fill defip information. 556 * Returns: 557 * BCM_E_XXX 558 */ 559 int 560 _bcm_hu2_lpm_del(int unit, _bcm_defip_cfg_t *lpm_cfg) 561 { 562 int rv; /* Operation return status. */ 563 uint32 lpm_entry[SOC_MAX_MEM_FIELD_WORDS];/* Hw entry buffer.*/ 564 565 /* Input parameters check */ 566 if (NULL == lpm_cfg) { 567 return (BCM_E_PARAM); 568 } 569 570 /* Zero buffers. */ 571 sal_memset(lpm_entry, 0, WORDS2BYTES(SOC_MAX_MEM_FIELD_WORDS)); 572 573 /* Initialize hw buffer deletion key. */ 574 BCM_IF_ERROR_RETURN(_bcm_hu2_lpm_ent_init(unit, lpm_cfg, lpm_entry)); 575 576 /* Write buffer to hw. */ 577 rv = soc_hu2_lpm_delete(unit, lpm_entry); 578 579 /* If new route added increment total number of routes. */ 580 if (rv >= 0) { 581 BCM_XGS3_L3_DEFIP_CNT_DEC(unit, lpm_cfg->defip_flags & BCM_L3_IP6); 582 } 583 return rv; 584 } 585 586 /* 587 * Function: 588 * _bcm_hu2_lpm_update_match 589 * Purpose: 590 * Update/Delete all entries in defip table matching a certain rule. 591 * Parameters: 592 * unit - (IN)SOC unit number. 593 * trv_data - (IN)Delete pattern + compare,act,notify routines. 594 * Returns: 595 * BCM_E_XXX 596 */ 597 int 598 _bcm_hu2_lpm_update_match(int unit, _bcm_l3_trvrs_data_t *trv_data) 599 { 600 uint32 ipv6; /* Iterate over ipv6 only flag. */ 601 int idx; /* Iteration index. */ 602 char *lpm_tbl_ptr; /* Dma table pointer. */ 603 int nh_ecmp_idx; /* Next hop/Ecmp group index. */ 604 int cmp_result; /* Test routine result. */ 605 uint32 *lpm_entry; /* Hw entry buffer. */ 606 _bcm_defip_cfg_t lpm_cfg; /* Buffer to fill route info. */ 607 int defip_table_size; /* Defip table size. */ 608 int rv; /* Operation return status. */ 609 int idx_start = 0; 610 int idx_end = 0; 611 soc_mem_t mem = L3_DEFIPm; /* Route table memory. */ 612 613 ipv6 = (trv_data->flags & BCM_L3_IP6); 614 615 /* Table DMA the LPM table to software copy */ 616 BCM_IF_ERROR_RETURN 617 (bcm_xgs3_l3_tbl_dma(unit, mem, BCM_XGS3_L3_ENT_SZ(unit, defip), 618 "lpm_tbl", &lpm_tbl_ptr, &defip_table_size)); 619 620 idx_start = 0; 621 if (soc_feature(unit, soc_feature_urpf) && SOC_URPF_STATUS_GET(unit)) { 622 /* only HR3 in HRx devices support uRPF feature 623 * - LPM table will be halved while uPRF enabled. And the lower 624 * LPM is for DIP lookup. 625 */ 626 idx_end = defip_table_size / 2; 627 } else { 628 idx_end = defip_table_size; 629 } 630 631 for (idx = idx_start; idx < idx_end; idx++) { 632 /* Calculate entry ofset. */ 633 lpm_entry = 634 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, lpm_tbl_ptr, idx); 635 636 /* Each lpm entry contains either 1 ipv4 or 1 ipv6 entry 637 * Make sure entry is valid. */ 638 if (!soc_L3_DEFIPm_field32_get(unit, lpm_entry, VALIDf)) { 639 continue; 640 } 641 642 #if defined(BCM_HURRICANE3_SUPPORT) 643 /* 644 * HR3-Lite : LPM WAR to sync-up HIT bit on correct LPM location 645 * >> HIT operation for LPM-DATA entries 32~63 will occrred on 646 * LPM-DATA internally. This behavior causes the HIT status 647 * need additional sync-up from LPM 512~543 entries. 648 */ 649 if (soc_feature(unit, soc_feature_hr3_lite_lpm_shadow_hit) && idx >= 32) { 650 defip_hit_only_entry_t lpm_hit_entry; 651 uint32 real_hit = 0; 652 653 BCM_IF_ERROR_RETURN(soc_mem_read(unit, 654 L3_DEFIP_HIT_ONLYm, MEM_BLOCK_ANY, idx, &lpm_hit_entry)); 655 real_hit = soc_L3_DEFIP_HIT_ONLYm_field32_get(unit, 656 &lpm_hit_entry, HITf); 657 LOG_INFO(BSL_LS_SOC_LPM, (BSL_META_U(unit, 658 "HR3-Lite LPM_WAR :LPM entry(%d) real_hit=%d!\n"), 659 idx, real_hit)); 660 661 /* sync-up the HIT field */ 662 soc_L3_DEFIPm_field32_set(unit, lpm_entry, HITf, real_hit); 663 } 664 #endif 665 666 /* Zero destination buffer first. */ 667 sal_memset(&lpm_cfg, 0, sizeof(_bcm_defip_cfg_t)); 668 669 /* Parse the entry. */ 670 _bcm_hu2_lpm_ent_parse(unit, &lpm_cfg, &nh_ecmp_idx, lpm_entry); 671 lpm_cfg.defip_index = idx; 672 673 /* If protocol doesn't match skip the entry. */ 674 if ((lpm_cfg.defip_flags & BCM_L3_IP6) != ipv6) { 675 continue; 676 } 677 678 /* Fill entry ip address & subnet mask. */ 679 _bcm_hu2_lpm_ent_get_key(unit, &lpm_cfg, lpm_entry); 680 681 /* Execute operation routine if any. */ 682 if (trv_data->op_cb) { 683 rv = (*trv_data->op_cb) (unit, (void *)trv_data, 684 (void *)&lpm_cfg, 685 (void *)&nh_ecmp_idx, &cmp_result); 686 if (rv < 0) { 687 soc_cm_sfree(unit, lpm_tbl_ptr); 688 return rv; 689 } 690 } 691 #ifdef BCM_WARM_BOOT_SUPPORT 692 if (SOC_WARM_BOOT(unit)) { 693 rv = soc_hu2_lpm_reinit(unit, idx, lpm_entry); 694 if (rv < 0) { 695 soc_cm_sfree(unit, lpm_tbl_ptr); 696 return rv; 697 } 698 } 699 #endif /* BCM_WARM_BOOT_SUPPORT */ 700 701 } 702 703 #ifdef BCM_WARM_BOOT_SUPPORT 704 SOC_IF_ERROR_RETURN(soc_hu2_lpm_reinit_done(unit)); 705 #endif /* BCM_WARM_BOOT_SUPPORT */ 706 soc_cm_sfree(unit, lpm_tbl_ptr); 707 return (BCM_E_NONE); 708 } 709 710 #endif /* INCLUDE_L3 */ 711