nat.c (153043B)
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 * NAT - Broadcom StrataSwitch NAT API. 8 */ 9 10 #include <sal/core/libc.h> 11 #include <soc/defs.h> 12 #if defined(INCLUDE_L3) 13 14 #include <soc/drv.h> 15 #include <bcm/error.h> 16 17 #include <bcm/l3.h> 18 #include <bcm/nat.h> 19 #include <bcm/tunnel.h> 20 #include <bcm/debug.h> 21 #include <bcm/error.h> 22 23 #include <bcm_int/esw/firebolt.h> 24 #include <bcm_int/esw/trident2.h> 25 #include <bcm_int/esw/flex_ctr.h> 26 #include <bcm_int/esw_dispatch.h> 27 #include <bcm_int/esw/nat.h> 28 #include <bcm_int/esw/trx.h> 29 30 #include <soc/mem.h> 31 #include <soc/profile_mem.h> 32 #include <soc/debug.h> 33 #include <soc/drv.h> 34 #include <soc/trident2.h> 35 #include <soc/trident3.h> 36 #ifdef BCM_TRIDENT3_SUPPORT 37 #include <soc/esw/cancun.h> 38 #include <soc/esw/cancun_enums.h> 39 #endif /* BCM_TRIDENT3_SUPPORT */ 40 41 _bcm_l3_nat_state_t *_bcm_l3_nat_state[BCM_MAX_NUM_UNITS]; 42 43 #define BCM_NAT_EGRESS_ID_MIN(unit) (SOC_IS_TRIDENT3X(unit) ? 1 : 0) 44 45 #ifdef BCM_TRIDENT2_SUPPORT 46 int 47 _bcm_esw_l3_nat_lock(int unit) 48 { 49 if (NULL != _bcm_l3_nat_state[unit]->lock) { 50 return sal_mutex_take(_bcm_l3_nat_state[unit]->lock, 51 sal_mutex_FOREVER); 52 } 53 return (BCM_E_NONE); 54 } 55 56 int 57 _bcm_esw_l3_nat_unlock(int unit) 58 { 59 if (NULL != _bcm_l3_nat_state[unit]->lock) { 60 return sal_mutex_give(_bcm_l3_nat_state[unit]->lock); 61 } 62 return (BCM_E_NONE); 63 } 64 #endif /* BCM_TRIDENT2_SUPPORT */ 65 66 #ifdef BCM_TRIDENT2_SUPPORT 67 /* DMA one of the memories specified by mem */ 68 int 69 _bcm_td2_l3_nat_read_mem(int unit, soc_mem_t tbl_mem, uint16 tbl_entry_sz, 70 char *descr, char **res_ptr, int *entry_count) 71 { 72 int alloc_size; 73 char *buffer; 74 int tbl_size; 75 76 /* Input parameters sanity check. */ 77 if ((NULL == res_ptr) || (NULL == descr)) { 78 return (BCM_E_PARAM); 79 } 80 81 /* If entry size is not deterministic. reject. */ 82 #if 0 83 if (tbl_entry_sz == BCM_XGS3_L3_INVALID_ENT_SZ) { 84 return (BCM_E_UNAVAIL); 85 } 86 #endif 87 88 if (INVALIDm == tbl_mem) { 89 return (BCM_E_NOT_FOUND); 90 } 91 92 /* Calculate table size. */ 93 tbl_size = soc_mem_index_count(unit, tbl_mem); 94 if (!tbl_size) { 95 return (BCM_E_NOT_FOUND); 96 } else if (NULL != entry_count) { 97 *entry_count = tbl_size; 98 } 99 alloc_size = tbl_entry_sz * tbl_size; 100 101 /* Allocate memory buffer. */ 102 buffer = soc_cm_salloc(unit, alloc_size, descr); 103 if (buffer == NULL) { 104 return (BCM_E_MEMORY); 105 } 106 107 /* Reset allocated buffer. */ 108 sal_memset(buffer, 0, alloc_size); 109 110 /* Read table to the buffer. */ 111 if (soc_mem_read_range(unit, tbl_mem, MEM_BLOCK_ANY, 112 soc_mem_index_min(unit, tbl_mem), 113 soc_mem_index_max(unit, tbl_mem), buffer) < 0) { 114 soc_cm_sfree(unit, buffer); 115 return (BCM_E_INTERNAL); 116 } 117 118 *res_ptr = buffer; 119 return (BCM_E_NONE); 120 } 121 122 #ifdef BCM_WARM_BOOT_SUPPORT 123 124 STATIC int 125 _bcm_td2_l3_nat_warmboot_tblcnt_update(int unit, int idx, 126 bcm_l3_nat_ingress_t *nat_info, 127 void *user_data) 128 { 129 int tbl; 130 soc_mem_t mem; 131 bcm_l3_nat_ingress_cb_context_t *user_context; 132 user_context = (bcm_l3_nat_ingress_cb_context_t *) user_data; 133 mem = user_context->mem; 134 135 switch (mem) { 136 case L3_ENTRY_IPV4_MULTICASTm: 137 #ifdef BCM_TRIDENT3_SUPPORT 138 case L3_ENTRY_DOUBLEm: 139 #endif 140 tbl = BCM_L3_NAT_INGRESS_DNAT_CNT; 141 break; 142 case ING_SNATm: 143 tbl = BCM_L3_NAT_INGRESS_SNAT_CNT; 144 break; 145 case ING_DNAT_ADDRESS_TYPEm: 146 tbl = BCM_L3_NAT_INGRESS_POOL_CNT; 147 break; 148 default : 149 tbl = BCM_L3_NAT_INGRESS_DNAT_CNT; 150 break; 151 } 152 BCM_L3_NAT_INGRESS_INFO((unit)).tbl_cnts[(tbl)]++; 153 154 return BCM_E_NONE; 155 } 156 157 /* 158 * Function: 159 * _bcm_esw_nat_reinit 160 * Purpose: 161 * Warm boot recovery for the NAT module 162 * Parameters: 163 * unit - Device Number 164 * Returns: 165 * BCM_E_XXX 166 */ 167 STATIC int 168 _bcm_esw_nat_reinit(int unit) 169 { 170 soc_mem_t mem; 171 bcm_l3_nat_ingress_cb_context_t user_context; 172 int tbl, i, idx_min, idx_max; 173 uint32 key_type, valid0, valid1, flags, egr_nat_id; 174 soc_field_t egr_nat_validf[2] = {VALIDf, VALID_0f}, key_typef = KEY_TYPE_0f; 175 soc_mem_t egr_nat_tbl[2] = {ING_SNATm, L3_ENTRY_IPV4_MULTICASTm}; 176 soc_field_t egr_nat_idxf[2] = {NAT_PACKET_EDIT_IDXf, NAT__PACKET_EDIT_IDXf}; 177 soc_field_t egr_nat_self_idxf[2] = {NAT_PACKET_EDIT_ENTRY_SELf, 178 NAT__PACKET_EDIT_ENTRY_SELf}; 179 char *ing_snat_tbl_ptr = NULL; 180 char *nat_tbl_ptr = NULL; 181 uint32 *pkt_edit_entry_ptr = NULL; 182 int rv = BCM_E_NONE; 183 uint32 *egr_nat_entry = NULL; 184 char *egr_nh_buf = NULL; 185 #ifdef BCM_MONTEREY_SUPPORT 186 char *ing_dnat_address_type_tbl_ptr = NULL; 187 if (SOC_IS_MONTEREY(unit)) { 188 rv = _bcm_td2_l3_nat_read_mem(unit, ING_DNAT_ADDRESS_TYPEm, 189 sizeof(ing_dnat_address_type_entry_t), 190 "ing_dnat_address_type_tbl", &ing_dnat_address_type_tbl_ptr, NULL); 191 if (BCM_FAILURE(rv)) { 192 goto cleanup; 193 } 194 } 195 #endif 196 rv = _bcm_td2_l3_nat_read_mem(unit, ING_SNATm, 197 sizeof(ing_snat_entry_t), 198 "ing_snat_tbl", &ing_snat_tbl_ptr, NULL); 199 if (BCM_FAILURE(rv)) { 200 goto cleanup; 201 } 202 203 if (SOC_IS_TRIDENT3X(unit)) { 204 rv = _bcm_td2_l3_nat_read_mem(unit, L3_ENTRY_DOUBLEm, 205 sizeof(l3_entry_double_entry_t), 206 "nat_tbl", &nat_tbl_ptr, NULL); 207 } else { 208 rv = _bcm_td2_l3_nat_read_mem(unit, L3_ENTRY_IPV4_MULTICASTm, 209 sizeof(l3_entry_ipv4_multicast_entry_t), 210 "nat_tbl", &nat_tbl_ptr, NULL); 211 } 212 213 if (BCM_FAILURE(rv)) { 214 goto cleanup; 215 } 216 217 if (SOC_IS_TRIDENT3X(unit)) { 218 egr_nat_tbl[1] = L3_ENTRY_DOUBLEm; 219 egr_nat_validf[1] = BASE_VALID_0f; 220 key_typef = KEY_TYPEf; 221 } 222 223 /* Recover egress nat state */ 224 for (tbl = 0; tbl < 2; tbl++) { 225 idx_min = BCM_NAT_EGRESS_ID_MIN(unit); 226 idx_max = soc_mem_index_max(unit, egr_nat_tbl[tbl]); 227 228 for (i = idx_min; i <= idx_max; i++) { 229 if (0 == tbl) { 230 egr_nat_entry = 231 soc_mem_table_idx_to_pointer(unit, egr_nat_tbl[tbl], 232 uint32 *, 233 ing_snat_tbl_ptr, i); 234 } else { 235 egr_nat_entry = 236 soc_mem_table_idx_to_pointer(unit, egr_nat_tbl[tbl], 237 uint32 *, nat_tbl_ptr, i); 238 239 } 240 if (soc_mem_field32_get(unit, egr_nat_tbl[tbl], 241 egr_nat_entry, egr_nat_validf[tbl]) == 0) { 242 continue; 243 } 244 245 if (tbl) { 246 key_type = soc_mem_field32_get(unit, egr_nat_tbl[tbl], 247 egr_nat_entry, key_typef); 248 if ((key_type != 18) && (key_type != 19)) { 249 continue; /* Not NAT entry */ 250 } 251 } 252 253 egr_nat_id = BCM_L3_NAT_EGRESS_SW_IDX_GET( 254 soc_mem_field32_get(unit, egr_nat_tbl[tbl], 255 egr_nat_entry, egr_nat_idxf[tbl]), 256 soc_mem_field32_get(unit, egr_nat_tbl[tbl], 257 egr_nat_entry, egr_nat_self_idxf[tbl])); 258 BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, egr_nat_id, 1); 259 } 260 } 261 262 if (nat_tbl_ptr) { 263 soc_cm_sfree(unit, nat_tbl_ptr); 264 nat_tbl_ptr = NULL; 265 } 266 267 mem = EGR_NAT_PACKET_EDIT_INFOm ; 268 idx_min = BCM_NAT_EGRESS_ID_MIN(unit); 269 idx_max = soc_mem_index_max(unit, mem); 270 rv = _bcm_td2_l3_nat_read_mem(unit, mem, 271 sizeof(egr_nat_packet_edit_info_entry_t), 272 "nat_tbl", &nat_tbl_ptr, NULL); 273 if (BCM_FAILURE(rv)) { 274 goto cleanup; 275 } 276 277 for (i = idx_min; i <= idx_max; i++) { 278 279 pkt_edit_entry_ptr = 280 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 281 nat_tbl_ptr, i); 282 283 valid0 = soc_mem_field32_get(unit, mem, pkt_edit_entry_ptr, VALID_0f); 284 valid1 = soc_mem_field32_get(unit, mem, pkt_edit_entry_ptr, VALID_1f); 285 286 if (!(valid0 || valid1)) { 287 continue; 288 } 289 290 if (valid0) { 291 SHR_BITSET(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, 292 (i << 1)); 293 egr_nat_id = (i << 1); 294 BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, egr_nat_id, 1); 295 } 296 297 if (valid1) { 298 SHR_BITSET(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, 299 ((i << 1) + 1)); 300 egr_nat_id = ((i << 1) + 1); 301 BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, egr_nat_id, 1); 302 } 303 } 304 305 /* Recover ingress nat state */ 306 if (SOC_IS_TRIDENT3X(unit)) { 307 mem = L3_ENTRY_DOUBLEm; 308 } else { 309 mem = L3_ENTRY_IPV4_MULTICASTm; 310 } 311 flags = BCM_L3_NAT_INGRESS_DNAT; 312 user_context.mem = mem; 313 314 rv = bcm_esw_l3_nat_ingress_traverse(unit, flags, soc_mem_index_min(unit, mem), 315 soc_mem_index_max(unit, mem), 316 _bcm_td2_l3_nat_warmboot_tblcnt_update, 317 (void *) &user_context); 318 if (BCM_FAILURE(rv)) { 319 goto cleanup; 320 } 321 mem = ING_DNAT_ADDRESS_TYPEm; 322 flags = BCM_L3_NAT_INGRESS_DNAT | BCM_L3_NAT_INGRESS_DNAT_POOL; 323 user_context.mem = mem; 324 325 rv = bcm_esw_l3_nat_ingress_traverse(unit, flags, soc_mem_index_min(unit, mem), 326 soc_mem_index_max(unit, mem), 327 _bcm_td2_l3_nat_warmboot_tblcnt_update, 328 (void *) &user_context); 329 if (BCM_FAILURE(rv)) { 330 goto cleanup; 331 } 332 333 #ifdef BCM_MONTEREY_SUPPORT 334 if (SOC_IS_MONTEREY(unit)) { 335 idx_min = soc_mem_index_min(unit, ING_DNAT_ADDRESS_TYPEm); 336 idx_max = soc_mem_index_max(unit, ING_DNAT_ADDRESS_TYPEm); 337 for (i = idx_min; i <= idx_max; i++) { 338 egr_nat_entry = 339 soc_mem_table_idx_to_pointer(unit, ING_DNAT_ADDRESS_TYPEm, 340 uint32 *, ing_dnat_address_type_tbl_ptr, i); 341 if (soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, egr_nat_entry, VALIDf) == 0) { 342 BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit) = i; 343 break; 344 } 345 } 346 if (i > idx_max) { 347 BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit) = i; 348 } 349 } 350 #endif 351 mem = ING_SNATm; 352 flags = 0; 353 user_context.mem = mem; 354 355 rv = bcm_esw_l3_nat_ingress_traverse(unit, flags, BCM_NAT_EGRESS_ID_MIN(unit), 356 soc_mem_index_max(unit, mem), 357 _bcm_td2_l3_nat_warmboot_tblcnt_update, 358 (void *) &user_context); 359 if (BCM_FAILURE(rv)) { 360 goto cleanup; 361 } 362 363 idx_min = BCM_NAT_EGRESS_ID_MIN(unit); 364 idx_max = soc_mem_index_max(unit, ING_SNATm); 365 for (i = idx_min; i <= idx_max; i++) { 366 egr_nat_entry = 367 soc_mem_table_idx_to_pointer(unit, ING_SNATm, 368 uint32 *, ing_snat_tbl_ptr, i); 369 if (soc_ING_SNATm_field32_get(unit, egr_nat_entry, VALIDf) == 0) { 370 BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit) = i; 371 break; 372 } 373 } 374 375 for (i = idx_max; i >= idx_min; i--) { 376 egr_nat_entry = 377 soc_mem_table_idx_to_pointer(unit, ING_SNATm, uint32 *, 378 ing_snat_tbl_ptr, i); 379 if (soc_ING_SNATm_field32_get(unit, egr_nat_entry, VALIDf) == 0) { 380 BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit) = i; 381 break; 382 } 383 } 384 #if defined(BCM_TRIDENT3_SUPPORT) 385 if (soc_feature(unit, soc_feature_large_scale_nat)) { 386 /* recover mac-da profile reference count from EGR NH table */ 387 int i, index_min, index_max; 388 uint32 entry_type = 0; 389 egr_l3_next_hop_entry_t *egr_nh_entry; 390 391 egr_nh_buf = soc_cm_salloc(unit, 392 SOC_MEM_TABLE_BYTES(unit, EGR_L3_NEXT_HOPm), "Egr Next Hop buffer"); 393 394 if (NULL == egr_nh_buf) { 395 rv = BCM_E_MEMORY; 396 goto cleanup; 397 } 398 index_min = soc_mem_index_min(unit, EGR_L3_NEXT_HOPm); 399 index_max = soc_mem_index_max(unit, EGR_L3_NEXT_HOPm); 400 rv = soc_mem_read_range(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY, 401 index_min, index_max, egr_nh_buf); 402 403 if (SOC_FAILURE(rv)) { 404 goto cleanup; 405 } 406 407 for (i = index_min; i <= index_max; i++) { 408 egr_nh_entry = soc_mem_table_idx_to_pointer(unit, EGR_L3_NEXT_HOPm, 409 egr_l3_next_hop_entry_t *, egr_nh_buf, i); 410 411 /* Check entry type */ 412 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry, 413 DATA_TYPEf); 414 415 if ((entry_type == 7) && /* IPMC */ 416 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh_entry, 417 L3MC__USE_MAC_DA_PROFILEf)) { 418 uint32 macda_idx; 419 macda_idx = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, egr_nh_entry, 420 L3MC__MAC_DA_PROFILE_INDEXf); 421 422 _bcm_common_profile_mem_ref_cnt_update( 423 unit, EGR_MAC_DA_PROFILEm, macda_idx, 1); 424 } 425 } 426 } 427 #endif 428 cleanup: 429 if (ing_snat_tbl_ptr) { 430 soc_cm_sfree(unit, ing_snat_tbl_ptr); 431 } 432 if (nat_tbl_ptr) { 433 soc_cm_sfree(unit, nat_tbl_ptr); 434 } 435 if (egr_nh_buf) { 436 soc_cm_sfree(unit, egr_nh_buf); 437 } 438 #ifdef BCM_MONTEREY_SUPPORT 439 if (SOC_IS_MONTEREY(unit)) { 440 if (ing_dnat_address_type_tbl_ptr) { 441 soc_cm_sfree(unit, ing_dnat_address_type_tbl_ptr); 442 } 443 } 444 #endif 445 return rv; 446 } 447 #endif /* BCM_WARM_BOOT_SUPPORT */ 448 449 /* 450 * Function: 451 * _bcm_esw_l3_nat_free_resource 452 * Purpose: 453 * Free all allocated software resources 454 * Parameters: 455 * unit - SOC unit number 456 * Returns: 457 * Nothing 458 */ 459 void 460 _bcm_esw_l3_nat_free_resource(int unit) 461 { 462 if (soc_feature(unit, soc_feature_nat)) { 463 if (_bcm_l3_nat_state[unit] != NULL) { 464 if (BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap != NULL) { 465 sal_free(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap); 466 BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap = NULL; 467 } 468 469 if (_bcm_l3_nat_state[unit]->lock != NULL) { 470 sal_mutex_destroy(_bcm_l3_nat_state[unit]->lock); 471 _bcm_l3_nat_state[unit]->lock = NULL; 472 } 473 sal_free(_bcm_l3_nat_state[unit]); 474 _bcm_l3_nat_state[unit] = NULL; 475 } 476 } 477 } 478 479 int 480 _bcm_esw_l3_nat_init(int unit) 481 { 482 int rv = BCM_E_UNAVAIL; 483 484 if (soc_feature(unit, soc_feature_nat)) { 485 int mem_sz; 486 int refcount_sz = 0; 487 488 /* allocate ingress and egress state */ 489 if (NULL == _bcm_l3_nat_state[unit]) { 490 _bcm_l3_nat_state[unit] = sal_alloc(sizeof(_bcm_l3_nat_state_t), 491 "nat_state"); 492 493 if (NULL == _bcm_l3_nat_state[unit]) { 494 return BCM_E_RESOURCE; 495 } 496 sal_memset(_bcm_l3_nat_state[unit], 0, sizeof(_bcm_l3_nat_state_t)); 497 } 498 499 /* initialize nat_id bitmap, nat_id_refcount */ 500 mem_sz = SHR_BITALLOCSIZE(soc_mem_index_count(unit, 501 EGR_NAT_PACKET_EDIT_INFOm) * 2); 502 if (NULL == BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap) { 503 BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap = sal_alloc(mem_sz, 504 "nat_id bitmap"); 505 } 506 if (NULL == BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap) { 507 _bcm_esw_l3_nat_free_resource(unit); 508 return BCM_E_RESOURCE; 509 } 510 sal_memset(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, 0, mem_sz); 511 refcount_sz = sizeof(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_refcount); 512 sal_memset(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_refcount, 0, refcount_sz); 513 514 /* initialize tbl_cnts, free indexes */ 515 BCM_L3_NAT_INGRESS_CLR_TBL_CNT(unit, BCM_L3_NAT_INGRESS_POOL_CNT); 516 BCM_L3_NAT_INGRESS_CLR_TBL_CNT(unit, BCM_L3_NAT_INGRESS_DNAT_CNT); 517 BCM_L3_NAT_INGRESS_CLR_TBL_CNT(unit, BCM_L3_NAT_INGRESS_SNAT_CNT); 518 BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit) = soc_mem_index_max(unit, 519 ING_SNATm); 520 BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit) = BCM_NAT_EGRESS_ID_MIN(unit); 521 #ifdef BCM_MONTEREY_SUPPORT 522 if (SOC_IS_MONTEREY(unit)) { 523 BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit) = soc_mem_index_min(unit, 524 ING_DNAT_ADDRESS_TYPEm); 525 } 526 #endif 527 /* allocate and initialize mutex */ 528 _bcm_l3_nat_state[unit]->lock = sal_mutex_create("NAT module mutex"); 529 if (NULL == _bcm_l3_nat_state[unit]->lock) { 530 _bcm_esw_l3_nat_free_resource(unit); 531 return BCM_E_RESOURCE; 532 } 533 rv = BCM_E_NONE; 534 535 #ifdef BCM_WARM_BOOT_SUPPORT 536 if (SOC_WARM_BOOT(unit)) { 537 rv = _bcm_esw_nat_reinit(unit); 538 if (BCM_FAILURE(rv)) { 539 _bcm_esw_l3_nat_free_resource(unit); 540 return rv; 541 } 542 } else 543 #endif /* BCM_WARM_BOOT_SUPPORT */ 544 { 545 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 546 547 /* Clear Ingress DNAT Address Type table */ 548 rv = soc_mem_clear(unit, ING_DNAT_ADDRESS_TYPEm, COPYNO_ALL, 1); 549 if (!SOC_SUCCESS(rv)) { 550 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 551 return BCM_E_INTERNAL; 552 } 553 554 /* Clear Ingress SNAT Lookup table */ 555 rv = soc_mem_clear(unit, ING_SNATm, COPYNO_ALL, 1); 556 if (!SOC_SUCCESS(rv)) { 557 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 558 return BCM_E_INTERNAL; 559 } 560 561 /* Clear Egress NAT packet edit entry */ 562 rv = soc_mem_clear(unit, EGR_NAT_PACKET_EDIT_INFOm, COPYNO_ALL, 1); 563 if (!SOC_SUCCESS(rv)) { 564 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 565 return BCM_E_INTERNAL; 566 } 567 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 568 } 569 570 } 571 return rv; 572 } 573 574 /* 575 * Function: 576 * _bcm_esw_l3_nat_cleanup 577 * Purpose: 578 * DeInit L3NAT software module 579 * Parameters: 580 * unit - Device Number 581 * Returns: 582 * BCM_E_XXX 583 */ 584 int 585 _bcm_esw_l3_nat_cleanup(int unit) 586 { 587 int rv = BCM_E_UNAVAIL; 588 589 _bcm_esw_l3_nat_free_resource(unit); 590 return rv; 591 } 592 #endif /* BCM_TRIDENT2_SUPPORT */ 593 594 #ifdef BCM_TRIDENT2_SUPPORT 595 /* populate the entry using nat_info */ 596 static int _bcm_td2_nat_egress_sw_to_hw(int unit, int nat_idx, 597 bcm_l3_nat_egress_t *nat_info, 598 void *hw_buf) 599 { 600 int rv, hw_idx, hw_half; 601 int bit_count; 602 int twice_nat = BCM_L3_NAT_EGRESS_FLAGS_FULL_NAT(nat_info->flags); 603 int twice_nat_val = 0; 604 soc_field_t modify_src_or_dst; 605 soc_field_t ip_address; 606 soc_field_t modify_l4_port_or_prefix; 607 soc_field_t l4_port_or_prefix; 608 soc_field_t valid; 609 610 /* translate to hw index */ 611 BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_idx, hw_idx, hw_half); 612 613 if (hw_half) { 614 modify_src_or_dst = MODIFY_SRC_OR_DST_1f; 615 ip_address = IP_ADDRESS_1f; 616 modify_l4_port_or_prefix = MODIFY_L4_PORT_OR_PREFIX_1f; 617 l4_port_or_prefix = L4_PORT_OR_PREFIX_1f; 618 valid = VALID_1f; 619 } else { 620 modify_src_or_dst = MODIFY_SRC_OR_DST_0f; 621 ip_address = IP_ADDRESS_0f; 622 modify_l4_port_or_prefix = MODIFY_L4_PORT_OR_PREFIX_0f; 623 l4_port_or_prefix = L4_PORT_OR_PREFIX_0f; 624 valid = VALID_0f; 625 } 626 if (nat_info->flags & BCM_L3_NAT_EGRESS_SNAT) { 627 if (twice_nat) { 628 /* override field selections */ 629 modify_src_or_dst = MODIFY_SRC_OR_DST_0f; 630 ip_address = IP_ADDRESS_0f; 631 modify_l4_port_or_prefix = MODIFY_L4_PORT_OR_PREFIX_0f; 632 l4_port_or_prefix = L4_PORT_OR_PREFIX_0f; 633 valid = VALID_0f; 634 twice_nat_val = 1; 635 } else { 636 /* first read the entry */ 637 rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx, 638 hw_buf); 639 SOC_IF_ERROR_RETURN(rv); 640 } 641 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 642 modify_src_or_dst, 0); /* SIP */ 643 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, ip_address, 644 nat_info->sip_addr); 645 if (nat_info->flags & BCM_L3_NAT_EGRESS_NAPT) { 646 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 647 modify_l4_port_or_prefix, 0); 648 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 649 l4_port_or_prefix, nat_info->src_port); 650 } else { 651 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 652 modify_l4_port_or_prefix, 1); 653 /* coverity[callee_ptr_arith : FALSE] */ 654 SHR_BITCOUNT_RANGE(&nat_info->sip_addr_mask, bit_count, 0, 32); 655 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 656 l4_port_or_prefix, bit_count); 657 } 658 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, valid, 1); 659 660 /* protect against errors: */ 661 if (!twice_nat) { 662 return BCM_E_NONE; 663 } 664 } 665 if (nat_info->flags & BCM_L3_NAT_EGRESS_DNAT) { 666 if (twice_nat) { 667 /* override field selections */ 668 modify_src_or_dst = MODIFY_SRC_OR_DST_1f; 669 ip_address = IP_ADDRESS_1f; 670 modify_l4_port_or_prefix = MODIFY_L4_PORT_OR_PREFIX_1f; 671 l4_port_or_prefix = L4_PORT_OR_PREFIX_1f; 672 valid = VALID_1f; 673 twice_nat_val = 1; 674 } else { 675 /* first read the entry */ 676 rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx, 677 hw_buf); 678 SOC_IF_ERROR_RETURN(rv); 679 } 680 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 681 modify_src_or_dst, 1); /* DIP */ 682 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, ip_address, 683 nat_info->dip_addr); 684 if (nat_info->flags & BCM_L3_NAT_EGRESS_NAPT) { 685 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 686 modify_l4_port_or_prefix, 0); 687 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 688 l4_port_or_prefix, nat_info->dst_port); 689 } else { 690 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 691 modify_l4_port_or_prefix, 1); 692 /* coverity[callee_ptr_arith : FALSE] */ 693 SHR_BITCOUNT_RANGE(&nat_info->dip_addr_mask, bit_count, 0, 32); 694 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, 695 l4_port_or_prefix, bit_count); 696 } 697 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, valid, 1); 698 } 699 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, hw_buf, TWICE_NATf, 700 twice_nat_val); 701 702 return BCM_E_NONE; 703 } 704 705 static int 706 _bcm_td2_nat_egress_hw_to_sw(int unit, void *hw_buf, 707 bcm_l3_nat_egress_t *nat_info, int hw_half) 708 { 709 int full_nat, valid0, valid1, tmp; 710 tmp = nat_info->nat_id; 711 sal_memset(nat_info, 0, sizeof(*nat_info)); 712 nat_info->nat_id = tmp; 713 714 /* decide twice_nat or not first */ 715 full_nat = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get(unit, hw_buf, 716 TWICE_NATf); 717 valid0 = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get(unit, hw_buf, 718 VALID_0f); 719 valid1 = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get(unit, hw_buf, 720 VALID_1f); 721 if (full_nat) { 722 nat_info->flags |= (BCM_L3_NAT_EGRESS_SNAT | BCM_L3_NAT_EGRESS_DNAT); 723 /* populate SNAT into entry 0 and DNAT into entry 1 */ 724 if (!valid0 || !valid1) { 725 return BCM_E_EMPTY; 726 } 727 BCM_L3_NAT_FILL_SW_ENTRY_X(hw_buf, nat_info, 0f); 728 BCM_L3_NAT_FILL_SW_ENTRY_X(hw_buf, nat_info, 1f); 729 } else { 730 /* figure out which half to parse */ 731 if (hw_half) { 732 /* fill from ENTRY_1 */ 733 if (!valid1) return BCM_E_EMPTY; 734 BCM_L3_NAT_FILL_SW_ENTRY_X(hw_buf, nat_info, 1f); 735 } else { 736 if (!valid0) return BCM_E_EMPTY; 737 BCM_L3_NAT_FILL_SW_ENTRY_X(hw_buf, nat_info, 0f); 738 } 739 } 740 return BCM_E_NONE; 741 } 742 #endif /* BCM_TRIDENT2_SUPPORT */ 743 744 /* allocate either a half or full-nat egress translate entry */ 745 int 746 _bcm_td2_nat_egress_id_alloc(int unit, uint32 flags, int *id, int *count) 747 { 748 int full_nat = BCM_L3_NAT_EGRESS_FLAGS_FULL_NAT(flags); 749 int i = 0, num_ids, step_count, used, min_idx; 750 751 num_ids = soc_mem_index_count(unit, EGR_NAT_PACKET_EDIT_INFOm) * 752 BCM_L3_NAT_EGRESS_ENTRIES_PER_INDEX; 753 step_count = full_nat ? 2 : 1; 754 755 min_idx = BCM_NAT_EGRESS_ID_MIN(unit) * BCM_L3_NAT_EGRESS_ENTRIES_PER_INDEX; 756 757 if (flags & BCM_L3_NAT_EGRESS_WITH_ID) { 758 /* for full nat make sure proper id is used. Even for full nat, any 759 for half nat */ 760 if (*id % step_count) { 761 return BCM_E_PARAM; 762 } 763 /* make sure it is unused */ 764 SHR_BITTEST_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, *id, 765 step_count, used); 766 if (flags & BCM_L3_NAT_EGRESS_REPLACE) { 767 /* make sure it is used */ 768 if (1 == used) { 769 *count = step_count; 770 return BCM_E_NONE; 771 } else { 772 return BCM_E_NOT_FOUND; 773 } 774 } 775 /* make sure it is unused without BCM_L3_NAT_EGRESS_REPLACE */ 776 if (0 == used) { 777 SHR_BITSET_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, *id, 778 step_count); 779 *count = step_count; 780 return BCM_E_NONE; 781 } 782 /* if it is in use then flag error */ 783 return BCM_E_RESOURCE; 784 } else if (flags & BCM_L3_NAT_EGRESS_REPLACE) { 785 return BCM_E_PARAM; 786 } 787 788 for (i = min_idx; i < num_ids; i += step_count) { 789 SHR_BITTEST_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, i, 790 step_count, used); 791 if (0 == used) { 792 break; 793 } 794 } 795 if (i == num_ids) { 796 return BCM_E_RESOURCE; 797 } 798 SHR_BITSET_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, i, step_count); 799 *count = step_count; 800 *id = i; 801 return BCM_E_NONE; 802 } 803 804 int 805 _bcm_td2_nat_egress_id_free(int unit, int nat_id, int count) 806 { 807 int used; 808 SHR_BITTEST_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, nat_id, count, 809 used); 810 if (!used) { 811 return BCM_E_RESOURCE; 812 } 813 SHR_BITCLR_RANGE(BCM_L3_NAT_EGRESS_INFO(unit).nat_id_bitmap, nat_id, count); 814 return BCM_E_NONE; 815 } 816 817 /* 818 * Function: 819 * _bcm_td2_l3_nat_egress_inc_refcount 820 * Description: 821 * Increasements the reference count for the entry. 822 * Parameters: 823 * unit - (IN) Device number. 824 * nat_id - (IN) Index of egress nat to be increased. 825 */ 826 int 827 _bcm_td2_l3_nat_egress_inc_refcount( 828 int unit, 829 bcm_l3_nat_id_t nat_id) 830 { 831 #ifdef BCM_TRIDENT2_SUPPORT 832 int rv = BCM_E_NONE, hw_idx, hw_half, full_nat=0; 833 egr_nat_packet_edit_info_entry_t hw_buf; 834 835 if (soc_feature(unit, soc_feature_nat)) { 836 /* read entry at nat_id */ 837 BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_id, hw_idx, hw_half); 838 COMPILER_REFERENCE(hw_half); 839 840 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 841 rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx, 842 (void *)&hw_buf); 843 if (!SOC_SUCCESS(rv)) { 844 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 845 return BCM_E_INTERNAL; 846 } 847 848 /* check twice_nat field */ 849 full_nat = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get( 850 unit, (void *)&hw_buf, TWICE_NATf); 851 852 /* Increasement refcount */ 853 BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, nat_id, 1); 854 if (full_nat) { 855 BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, nat_id + 1, 1); 856 } 857 858 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 859 return BCM_E_NONE; 860 } 861 #endif /* BCM_TRIDENT2_SUPPORT */ 862 return BCM_E_UNAVAIL; 863 } 864 865 /* 866 * Function: 867 * _bcm_td2_l3_nat_egress_dec_refcount 868 * Description: 869 * Decrements the reference count for the entry. 870 * Parameters: 871 * unit - (IN) Device number. 872 * nat_id - (IN) Index of egress nat to be decreased. 873 */ 874 int 875 _bcm_td2_l3_nat_egress_dec_refcount( 876 int unit, 877 bcm_l3_nat_id_t nat_id) 878 { 879 #ifdef BCM_TRIDENT2_SUPPORT 880 int rv = BCM_E_NONE, hw_idx, hw_half, full_nat=0; 881 egr_nat_packet_edit_info_entry_t hw_buf; 882 883 if (soc_feature(unit, soc_feature_nat)) { 884 /* read entry at nat_id */ 885 BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_id, hw_idx, hw_half); 886 COMPILER_REFERENCE(hw_half); 887 888 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 889 rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx, 890 (void *)&hw_buf); 891 if (!SOC_SUCCESS(rv)) { 892 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 893 return BCM_E_INTERNAL; 894 } 895 896 if (BCM_L3_NAT_EGRESS_GET_REF_COUNT(unit, nat_id) == 0) { 897 /* already deleted */ 898 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 899 return BCM_E_EMPTY; 900 } 901 902 /* check twice_nat field */ 903 full_nat = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get( 904 unit, (void *)&hw_buf, TWICE_NATf); 905 906 /* Decrement refcount */ 907 BCM_L3_NAT_EGRESS_DEC_REF_COUNT(unit, nat_id); 908 if (full_nat) { 909 BCM_L3_NAT_EGRESS_DEC_REF_COUNT(unit, nat_id + 1); 910 } 911 912 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 913 return BCM_E_NONE; 914 } 915 #endif /* BCM_TRIDENT2_SUPPORT */ 916 return BCM_E_UNAVAIL; 917 } 918 919 #if defined (BCM_TRIDENT2_SUPPORT) 920 /* 921 * Function: _bcm_esw_nat_egress_ref_count_update 922 * 923 * Purpose: Update the reference count for the Egress Nat 924 * 925 * Parameters: 926 * unit - (IN) Device number. 927 * nat_id - (IN) Index of the Nat entry to be updated. 928 * incr - (IN) Increment/Decrement. 929 * 930 * Returns: 931 * BCM_E_XXX 932 */ 933 int _bcm_esw_nat_egress_ref_count_update(int unit, uint32 nat_id, int incr) { 934 if (incr) { 935 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_inc_refcount(unit, nat_id)); 936 } 937 else { 938 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_dec_refcount 939 (unit, nat_id)); 940 } 941 return (BCM_E_NONE); 942 } 943 #endif 944 945 /* 946 * Function: 947 * bcm_esw_l3_nat_egress_add 948 * Description: 949 * Add a NAT translation entry to the egress NAT xlate table. 950 * Parameters: 951 * unit - (IN) Device number. 952 * nat_info - (IN/OUT) 953 * IN: packet edit info: original IP/ports and translated IP/ports 954 * OUT: nat_id field is populated with the index of the xlate table where 955 * this translation entry was added. 956 * Returns: 957 * BCM_E_XXX 958 */ 959 960 int 961 bcm_esw_l3_nat_egress_add(int unit, bcm_l3_nat_egress_t *nat_info) 962 { 963 #ifdef BCM_TRIDENT2_SUPPORT 964 int rv = BCM_E_NONE, nat_id, count, hw_idx, hw_half; 965 egr_nat_packet_edit_info_entry_t hw_buf; 966 967 if (soc_feature(unit, soc_feature_nat)) { 968 /* validate input */ 969 if (NULL == nat_info) { 970 return BCM_E_PARAM; 971 } 972 if (!(nat_info->flags & (BCM_L3_NAT_EGRESS_SNAT | BCM_L3_NAT_EGRESS_DNAT))) { 973 /* must specify at least one of SNAT and DNAT */ 974 return BCM_E_PARAM; 975 } 976 /* if WITH_ID is specified, attempt is made to allocate this one, if 977 it is free 978 */ 979 nat_id = nat_info->nat_id; 980 981 if (SOC_IS_TRIDENT3X(unit) && (nat_info->flags & BCM_L3_NAT_EGRESS_WITH_ID)) { 982 if (nat_id < (BCM_NAT_EGRESS_ID_MIN(unit) * 983 BCM_L3_NAT_EGRESS_ENTRIES_PER_INDEX)) { 984 return BCM_E_PARAM; 985 } 986 } 987 988 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 989 990 /* allocate index: For twice nat nat_id and nat_id + 1 are allocated */ 991 rv = _bcm_td2_nat_egress_id_alloc(unit, nat_info->flags, &nat_id, 992 &count); 993 if (BCM_FAILURE(rv)) { 994 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 995 return BCM_E_RESOURCE; 996 } 997 998 /* populate the entry using nat_info */ 999 sal_memset(&hw_buf, 0, sizeof(hw_buf)); 1000 rv = _bcm_td2_nat_egress_sw_to_hw(unit, nat_id, nat_info, (void *)&hw_buf); 1001 if (rv < 0) { 1002 _bcm_td2_nat_egress_id_free(unit, nat_id, count); 1003 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1004 return BCM_E_PARAM; 1005 } 1006 1007 BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_id, hw_idx, hw_half); 1008 COMPILER_REFERENCE(hw_half); 1009 1010 /* write the hardware entry */ 1011 rv = WRITE_EGR_NAT_PACKET_EDIT_INFOm(unit, MEM_BLOCK_ALL, hw_idx, 1012 (void *)&hw_buf); 1013 if (rv < 0) { 1014 _bcm_td2_nat_egress_id_free(unit, nat_id, count); 1015 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1016 return BCM_E_INTERNAL; 1017 } 1018 /* increment refcount except the case of replacement */ 1019 if (!(nat_info->flags & BCM_L3_NAT_EGRESS_REPLACE)) { 1020 BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, nat_id, count); 1021 } 1022 nat_info->nat_id = nat_id; 1023 1024 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1025 return BCM_E_NONE; 1026 } 1027 #endif /* BCM_TRIDENT2_SUPPORT */ 1028 return BCM_E_UNAVAIL; 1029 } 1030 1031 /* Function: 1032 * bcm_esw_l3_nat_delete 1033 * Description: 1034 * Delete the egress NAT packet edit entry at the specified index. Decrements 1035 * the reference count for the entry. When refcount falls to one it is 1036 * removed from the table. 1037 * Parameters: 1038 * unit - (IN) Device number. 1039 * nat_id - IN Index of entry to be deleted. 1040 */ 1041 int 1042 bcm_esw_l3_nat_egress_delete( 1043 int unit, 1044 bcm_l3_nat_id_t nat_id) 1045 { 1046 #ifdef BCM_TRIDENT2_SUPPORT 1047 int rv = BCM_E_NONE, hw_idx, hw_half, full_nat=0; 1048 egr_nat_packet_edit_info_entry_t hw_buf; 1049 1050 if (soc_feature(unit, soc_feature_nat)) { 1051 1052 /* read entry at nat_id */ 1053 BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_id, hw_idx, hw_half); 1054 1055 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 1056 rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx, 1057 (void *)&hw_buf); 1058 if (!SOC_SUCCESS(rv)) { 1059 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1060 return BCM_E_INTERNAL; 1061 } 1062 1063 if (BCM_L3_NAT_EGRESS_GET_REF_COUNT(unit, nat_id) == 0) { 1064 /* already deleted */ 1065 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1066 return BCM_E_EMPTY; 1067 } 1068 1069 if (1 < BCM_L3_NAT_EGRESS_GET_REF_COUNT(unit, nat_id)) { 1070 /* If nat is in-use - reject deletion */ 1071 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1072 return BCM_E_BUSY; 1073 } 1074 1075 /* check twice_nat field */ 1076 1077 full_nat = soc_EGR_NAT_PACKET_EDIT_INFOm_field32_get(unit, (void *)&hw_buf, 1078 TWICE_NATf); 1079 1080 /* Decrement refcount */ 1081 BCM_L3_NAT_EGRESS_DEC_REF_COUNT(unit, nat_id); 1082 if (full_nat) { 1083 BCM_L3_NAT_EGRESS_DEC_REF_COUNT(unit, nat_id + 1); 1084 } 1085 1086 if (BCM_L3_NAT_EGRESS_GET_REF_COUNT(unit, nat_id) > 0) { 1087 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1088 return BCM_E_NONE; 1089 } 1090 1091 /* clear valid bit for either 1 half or both halves if full nat */ 1092 if (full_nat) { 1093 /* clear both halves */ 1094 sal_memset(&hw_buf, 0, sizeof(hw_buf)); 1095 } else { 1096 if (hw_half) { 1097 /* clear ENTRY_1 valid bit */ 1098 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, &hw_buf, 1099 VALID_1f, 0); 1100 } else { 1101 soc_EGR_NAT_PACKET_EDIT_INFOm_field32_set(unit, &hw_buf, 1102 VALID_0f, 0); 1103 } 1104 } 1105 rv = WRITE_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ALL, hw_idx, 1106 (void *) &hw_buf); 1107 if (!SOC_SUCCESS(rv)) { 1108 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1109 return BCM_E_INTERNAL; 1110 } 1111 /* free nat_id and nat_id + 1 */ 1112 rv = _bcm_td2_nat_egress_id_free(unit, nat_id, full_nat + 1); 1113 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1114 return rv; 1115 } 1116 #endif /* BCM_TRIDENT2_SUPPORT */ 1117 return BCM_E_UNAVAIL; 1118 } 1119 1120 /* Function: 1121 * bcm_esw_l3_nat_egress_get 1122 * Description: 1123 * Retrieve the egress NAT packet edit entry at the specified index 1124 * Parameters: 1125 * unit - (IN) Device number. 1126 * nat_id - IN Index of entry to get. 1127 */ 1128 int bcm_esw_l3_nat_egress_get( 1129 int unit, 1130 bcm_l3_nat_egress_t *nat_info) 1131 { 1132 #ifdef BCM_TRIDENT2_SUPPORT 1133 int rv = BCM_E_NONE, hw_idx, hw_half; 1134 egr_nat_packet_edit_info_entry_t hw_buf; 1135 1136 if (soc_feature(unit, soc_feature_nat)) { 1137 if (NULL == nat_info) { 1138 return BCM_E_PARAM; 1139 } 1140 /* validate the index */ 1141 BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_info->nat_id, hw_idx, hw_half); 1142 if ((hw_idx < BCM_NAT_EGRESS_ID_MIN(unit)) || 1143 (hw_idx > soc_mem_index_max(unit, EGR_NAT_PACKET_EDIT_INFOm))) { 1144 return BCM_E_PARAM; 1145 } 1146 1147 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 1148 1149 /* read entry at index nat_id. */ 1150 rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, hw_idx, 1151 &hw_buf); 1152 if (!SOC_SUCCESS(rv)) { 1153 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1154 return BCM_E_INTERNAL; 1155 } 1156 rv = _bcm_td2_nat_egress_hw_to_sw(unit, (void *)&hw_buf, nat_info, 1157 hw_half); 1158 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1159 return rv; 1160 } 1161 #endif /* BCM_TRIDENT2_SUPPORT */ 1162 return BCM_E_UNAVAIL; 1163 } 1164 1165 /* Function: 1166 * bcm_esw_l3_nat_egress_traverse 1167 * Description: 1168 * Traverse all valid NAT packet edit entries in the egress translate table 1169 * and call the supplied callback routine for each. 1170 * Parameters: 1171 * unit - (IN) Device number. 1172 * nat_id - IN Index of entry to get. 1173 */ 1174 int bcm_esw_l3_nat_egress_traverse( 1175 int unit, 1176 uint32 flags, 1177 uint32 start, 1178 uint32 end, 1179 bcm_l3_nat_egress_traverse_cb cb, 1180 void *user_data) 1181 { 1182 #ifdef BCM_TRIDENT2_SUPPORT 1183 1184 int rv = BCM_E_NONE, i; 1185 int idx_max, full_nat; 1186 egr_nat_packet_edit_info_entry_t hw_buf; 1187 bcm_l3_nat_egress_t nat_info; 1188 1189 if (!soc_feature(unit, soc_feature_nat)) { 1190 return BCM_E_UNAVAIL; 1191 } 1192 if (NULL == cb) { 1193 return BCM_E_NONE; 1194 } 1195 idx_max = soc_mem_index_max(unit, EGR_NAT_PACKET_EDIT_INFOm); 1196 /* Input indexes sanity */ 1197 if ((start > (uint32)idx_max) || ((end > (uint32)idx_max) 1198 && (end != 0xffffffff)) || (start > end)) { 1199 return BCM_E_PARAM; 1200 } 1201 1202 /* End value according to real table size */ 1203 if (end == 0xffffffff) { 1204 end = (uint32)idx_max; 1205 } 1206 1207 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 1208 1209 for (i = start; i <= end; i++) { 1210 /* traverse either one or 2 entries depending on half or full nat */ 1211 rv = READ_EGR_NAT_PACKET_EDIT_INFOm(unit, SOC_BLOCK_ANY, i, 1212 &hw_buf); 1213 if (!SOC_SUCCESS(rv)) { 1214 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1215 return BCM_E_INTERNAL; 1216 } 1217 1218 /* assume full nat entry first */ 1219 nat_info.nat_id = BCM_L3_NAT_EGRESS_SW_IDX_GET(i, 0); 1220 rv = _bcm_td2_nat_egress_hw_to_sw(unit, (void *)&hw_buf, &nat_info, 0); 1221 if (rv != BCM_E_EMPTY) { 1222 if (flags && (flags != nat_info.flags)) { 1223 continue; 1224 } 1225 /* call callback fn */ 1226 rv = (*cb) (unit, i, &nat_info, user_data); 1227 #ifdef BCM_CB_ABORT_ON_ERR 1228 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 1229 break; 1230 } 1231 #endif 1232 } 1233 1234 /* confirm if full nat or not */ 1235 full_nat = BCM_L3_NAT_EGRESS_FLAGS_FULL_NAT(nat_info.flags); 1236 1237 if (full_nat) { 1238 continue; 1239 } 1240 nat_info.nat_id = BCM_L3_NAT_EGRESS_SW_IDX_GET(i, 1); 1241 rv = _bcm_td2_nat_egress_hw_to_sw(unit, (void *)&hw_buf, &nat_info, 1); 1242 if (rv != BCM_E_EMPTY) { 1243 if (flags && (flags != nat_info.flags)) { 1244 continue; 1245 } 1246 /* call callback fn */ 1247 rv = cb(unit, i, &nat_info, user_data); 1248 #ifdef BCM_CB_ABORT_ON_ERR 1249 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 1250 break; 1251 } 1252 #endif 1253 } 1254 1255 } 1256 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1257 return BCM_E_NONE; 1258 #endif /* BCM_TRIDENT2_SUPPORT */ 1259 return BCM_E_UNAVAIL; 1260 } 1261 1262 /* 1263 * Function: 1264 * _bcm_esw_l3_nat_egress_reference_get 1265 * Description: 1266 * Get the reference count of the egress nat. 1267 * 1268 * Parameters: 1269 * unit - (IN) bcm device. 1270 * nat_id - (IN) egress nat id. 1271 * ref_count - (OUT) The number of references to egress nat. 1272 * Returns: 1273 * BCM_E_XXX 1274 */ 1275 int 1276 _bcm_esw_l3_nat_egress_reference_get(int unit, bcm_l3_nat_id_t nat_id, 1277 uint32 *ref_count) 1278 { 1279 #ifdef BCM_TRIDENT2_SUPPORT 1280 int num_ids; 1281 1282 if (soc_feature(unit, soc_feature_nat)) { 1283 num_ids = soc_mem_index_count(unit, EGR_NAT_PACKET_EDIT_INFOm) * 1284 BCM_L3_NAT_EGRESS_ENTRIES_PER_INDEX; 1285 if (nat_id > num_ids) { 1286 return BCM_E_PARAM; 1287 } 1288 1289 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 1290 *ref_count = BCM_L3_NAT_EGRESS_GET_REF_COUNT(unit, nat_id) - 1; 1291 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 1292 1293 return BCM_E_NONE; 1294 } 1295 #endif 1296 return BCM_E_UNAVAIL; 1297 } 1298 1299 /* 1300 * FLEX STAT FUNCTIONS for L3 NAT 1301 * 1302 * This following functions implements flex stat routines to attach, detach and get/set 1303 * flex counter functions. 1304 * 1305 * FLEX ATTACH 1306 * The function allocates flex counter from the counter pool and configures 1307 * attributes to set the base counter index and base offset. Flex counter pool, 1308 * base index and offset is associated to the table index request for the 1309 * module identifiers like, vpn, port, vp Additionally the reference counter 1310 * for the flex counter is incremented for multple references of the counter. 1311 * 1312 * FLEX DETACH 1313 * The function disassociates flex counter details assigned during flex attach 1314 * and decrements the reference counter. 1315 * 1316 * FLEX COUNTER GET/SET 1317 * The function read/set the associate counter values. Set is required for the 1318 * purpose of clearing the counter. 1319 * 1320 * 1321 * FLEX COUNTER MULTI GET/SET 1322 * The function reads/sets multiple flex stats and returns the counter arrays. 1323 * 1324 * FLEX STAT ID 1325 * The funciton retrieves the stat id for the given module identifiers. The 1326 * flex counter stat id has the following format. 1327 * 1328 * (8 modes) (32 groups) (16 pools) (32 objIds) (64K index) 1329 * +---------+------------+----------+-----------+-----------------+ 1330 * | | | | | | 1331 * | ModeId | GroupMode | PoolId | Account | Base Index | 1332 * | | | | objectId | | 1333 * +---------+------------+----------+-----------+-----------------+ 1334 * (31) (29)(28) (24)(23) (20)(19) (15)(14) (0) 1335 * 1336 * 1337 * PoolId : Counter pool no. 1338 * ( TD2: Ingress(8 pool x 4k counters) 1339 * Egress (4 pool x 4k counters) 1340 * GroupMode : Attribute group mode determines base offset and no. of counters 1341 * ModeId : Ingress/Egress Modes 1342 * Base Idx : Index into counter block of 256 counters 1343 * Account Obj : Flexible accounting objects 1344 */ 1345 1346 1347 #if defined(BCM_TRIDENT2_SUPPORT) 1348 /* 1349 * Function: 1350 * _bcm_td2_l3_route_stat_attach 1351 * Description: 1352 * Attach counters entries to the given l3 route defip index . Allocate 1353 * flex counter and assign counter index and offset for the index pointed 1354 * by l3 defip index 1355 * 1356 * Parameters: 1357 * unit - (IN) unit number 1358 * info - (IN) L3 Route Info 1359 * stat_counter_id - (IN) Stat Counter ID. 1360 * 1361 * Return Value: 1362 * BCM_E_XXX 1363 * Notes: 1364 */ 1365 1366 /* 1367 * Function: 1368 * _bcm_td2_l3_nat_egress_stat_get_table_info 1369 * Description: 1370 * Provides relevant flex table information(table-name,index with 1371 * direction) for given ingress interface. 1372 * 1373 * Parameters: 1374 * unit - (IN) unit number 1375 * info - (IN) Egress Nat Info 1376 * num_of_tables - (OUT) Number of flex counter tables 1377 * table_info - (OUT) Flex counter tables information 1378 * 1379 * Return Value: 1380 * BCM_E_XXX 1381 * Notes: 1382 */ 1383 static 1384 bcm_error_t _bcm_td2_l3_nat_egress_stat_get_table_info( 1385 int unit, 1386 bcm_l3_nat_egress_t *info, 1387 uint32 *num_of_tables, 1388 bcm_stat_flex_table_info_t *table_info) 1389 { 1390 int rv; 1391 int index = 0; 1392 1393 if (!soc_feature(unit,soc_feature_advanced_flex_counter)) { 1394 return BCM_E_UNAVAIL; 1395 } 1396 1397 /* Validate L3 EGRESS NAT Info */ 1398 rv = bcm_esw_l3_nat_egress_get(unit, info); 1399 if (!BCM_SUCCESS(rv)) { 1400 return rv; 1401 } 1402 index = info->nat_id; 1403 1404 /* Ingress L3 Egress NAT */ 1405 table_info[*num_of_tables].table=EGR_NAT_PACKET_EDIT_INFOm; 1406 table_info[*num_of_tables].index=index; 1407 table_info[*num_of_tables].direction=bcmStatFlexDirectionEgress; 1408 (*num_of_tables)++; 1409 1410 return BCM_E_NONE; 1411 } 1412 1413 1414 1415 /* 1416 * Function: 1417 * _bcm_td2_l3_nat_egress_stat_attach 1418 * Description: 1419 * Attach counters entries to the given egress nat (egr nat packet edit 1420 * info). Allocate flex counter and assign counter index and offset for 1421 * the index pointed by egr nat info ( packet edit index) 1422 * 1423 * Parameters: 1424 * unit - (IN) unit number 1425 * info - (IN) Egress Nat Info 1426 * stat_counter_id - (IN) Stat Counter ID. 1427 * 1428 * Return Value: 1429 * BCM_E_XXX 1430 * Notes: 1431 */ 1432 1433 int _bcm_td2_l3_nat_egress_stat_attach ( 1434 int unit, 1435 bcm_l3_nat_egress_t *info, 1436 uint32 stat_counter_id) 1437 { 1438 int rv = BCM_E_NONE; 1439 int counter_flag = 0; 1440 soc_mem_t table = 0; 1441 bcm_stat_flex_direction_t direction = bcmStatFlexDirectionIngress; 1442 uint32 pool_number = 0; 1443 uint32 base_index = 0; 1444 bcm_stat_flex_mode_t offset_mode = 0; 1445 bcm_stat_object_t object = bcmStatObjectIngPort; 1446 bcm_stat_group_mode_t group_mode = bcmStatGroupModeSingle; 1447 uint32 count = 0; 1448 uint32 actual_num_tables = 0; 1449 uint32 num_of_tables = 0; 1450 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 1451 1452 1453 /* Get pool, base index group mode and offset modes from stat counter id */ 1454 _bcm_esw_stat_get_counter_id_info( 1455 unit, stat_counter_id, 1456 &group_mode, &object, &offset_mode, &pool_number, &base_index); 1457 1458 /* Validate object and group mode */ 1459 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit, object, &direction)); 1460 BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit, group_mode)); 1461 1462 /* Get Table index to attach flexible counter */ 1463 BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info( 1464 unit, object, 1, &actual_num_tables, &table, &direction)); 1465 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_get_table_info( 1466 unit, info, &num_of_tables, &table_info[0])); 1467 1468 for (count = 0; count < num_of_tables; count++) { 1469 if ((table_info[count].direction == direction) && 1470 (table_info[count].table == table) ) { 1471 if (direction == bcmStatFlexDirectionIngress) { 1472 counter_flag = 1; 1473 rv = _bcm_esw_stat_flex_attach_ingress_table_counters( 1474 unit, 1475 table_info[count].table, 1476 table_info[count].index, 1477 offset_mode, 1478 base_index, 1479 pool_number); 1480 if(BCM_FAILURE(rv)) { 1481 break; 1482 } 1483 } else { 1484 counter_flag = 1; 1485 rv = _bcm_esw_stat_flex_attach_egress_table_counters( 1486 unit, 1487 table_info[count].table, 1488 table_info[count].index, 1489 0, 1490 offset_mode, 1491 base_index, 1492 pool_number); 1493 1494 if(BCM_FAILURE(rv)) { 1495 break; 1496 } 1497 } 1498 } 1499 } 1500 1501 if (counter_flag == 0) { 1502 rv = BCM_E_NOT_FOUND; 1503 } 1504 1505 return rv; 1506 } 1507 1508 1509 /* 1510 * Function: 1511 * _bcm_td2_l3_nat_egress_stat_detach 1512 * Description: 1513 * Detach counter entries to the given l3 egress nat index. 1514 * 1515 * Parameters: 1516 * unit - (IN) unit number 1517 * info - (IN) Egress Nat Info 1518 * 1519 * Return Value: 1520 * BCM_E_XXX 1521 * Notes: 1522 */ 1523 int _bcm_td2_l3_nat_egress_stat_detach ( 1524 int unit, 1525 bcm_l3_nat_egress_t *info) 1526 { 1527 uint32 count = 0; 1528 uint32 num_of_tables = 0; 1529 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 1530 bcm_error_t rv = BCM_E_NONE; 1531 bcm_error_t err_code[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION] = {BCM_E_NONE}; 1532 1533 /* Get the table index to be detached */ 1534 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_get_table_info( 1535 unit, info, &num_of_tables, &table_info[0])); 1536 1537 for (count = 0; count < num_of_tables; count++) { 1538 if (table_info[count].direction == bcmStatFlexDirectionIngress) { 1539 rv = _bcm_esw_stat_flex_detach_ingress_table_counters( 1540 unit, table_info[count].table, table_info[count].index); 1541 if (BCM_E_NONE != rv && 1542 BCM_E_NONE == err_code[bcmStatFlexDirectionIngress]) { 1543 err_code[bcmStatFlexDirectionIngress] = rv; 1544 } 1545 } else { 1546 rv = _bcm_esw_stat_flex_detach_egress_table_counters( 1547 unit, 0, table_info[count].table, table_info[count].index); 1548 if (BCM_E_NONE != rv && 1549 BCM_E_NONE == err_code[bcmStatFlexDirectionEgress]) { 1550 err_code[bcmStatFlexDirectionEgress] = rv; 1551 } 1552 } 1553 } 1554 1555 BCM_STAT_FLEX_DETACH_RETURN(err_code) 1556 } 1557 1558 /* 1559 * Function: 1560 * _bcm_td2_l3_nat_egress_stat_counter_get 1561 * 1562 * Description: 1563 * Get l3 egress nat counter value for specified l3 egress nat index 1564 * if sync_mode is set, sync the sw accumulated count 1565 * with hw count value first, else return sw count. 1566 * 1567 * Parameters: 1568 * unit - (IN) unit number 1569 * sync_mode - (IN) hwcount is to be synced to sw count 1570 * info - (IN) Egress Nat Info 1571 * stat - (IN) l3 egress nat counter stat types 1572 * num_entries - (IN) Number of counter Entries 1573 * counter_indexes - (IN) Pointer to Counter indexes entries 1574 * counter_values - (OUT) Pointer to counter values 1575 * 1576 * Return Value: 1577 * BCM_E_XXX 1578 * Notes: 1579 */ 1580 int _bcm_td2_l3_nat_egress_stat_counter_get( 1581 int unit, 1582 int sync_mode, 1583 bcm_l3_nat_egress_t *info, 1584 bcm_l3_nat_egress_stat_t stat, 1585 uint32 num_entries, 1586 uint32 *counter_indexes, 1587 bcm_stat_value_t *counter_values) 1588 { 1589 uint32 table_count = 0; 1590 uint32 index_count = 0; 1591 uint32 num_of_tables = 0; 1592 bcm_stat_flex_direction_t direction = bcmStatFlexDirectionIngress; 1593 uint32 byte_flag = 0; 1594 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 1595 1596 /* Get the flex counter direction - ingress/egress */ 1597 if ((stat == bcmL3NatOutPackets) || 1598 (stat == bcmL3NatOutBytes)) { 1599 direction = bcmStatFlexDirectionEgress; 1600 } else { 1601 /* direction = bcmStatFlexDirectionIngress;*/ 1602 return BCM_E_UNAVAIL; 1603 } 1604 if (stat == bcmL3NatOutPackets) { 1605 byte_flag=0; 1606 } else { 1607 byte_flag=1; 1608 } 1609 1610 /* Get Table index to read the flex counter */ 1611 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_get_table_info( 1612 unit, info, &num_of_tables, &table_info[0])); 1613 1614 /* Get the flex counter for the attached table index */ 1615 for (table_count = 0; table_count < num_of_tables ; table_count++) { 1616 if (table_info[table_count].direction == direction) { 1617 for (index_count = 0; index_count < num_entries ; index_count++) { 1618 BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_get( 1619 unit, sync_mode, 1620 table_info[table_count].index, 1621 table_info[table_count].table, 1622 0, 1623 byte_flag, 1624 counter_indexes[index_count], 1625 &counter_values[index_count])); 1626 } 1627 } 1628 } 1629 1630 return BCM_E_NONE; 1631 } 1632 1633 /* 1634 * Function: 1635 * _bcm_td2_l3_nat_egress_stat_counter_set 1636 * 1637 * Description: 1638 * Set l3 egress nat counter value for specified l3 egress nat index 1639 * 1640 * Parameters: 1641 * unit - (IN) unit number 1642 * info - (IN) Egress Nat Info 1643 * stat - (IN) l3 egress nat counter stat types 1644 * num_entries - (IN) Number of counter Entries 1645 * counter_indexes - (IN) Pointer to Counter indexes entries 1646 * counter_values - (OUT) Pointer to counter values 1647 * 1648 * Return Value: 1649 * BCM_E_XXX 1650 * Notes: 1651 */ 1652 int _bcm_td2_l3_nat_egress_stat_counter_set( 1653 int unit, 1654 bcm_l3_nat_egress_t *info, 1655 bcm_l3_nat_egress_stat_t stat, 1656 uint32 num_entries, 1657 uint32 *counter_indexes, 1658 bcm_stat_value_t *counter_values) 1659 { 1660 uint32 table_count=0; 1661 uint32 index_count=0; 1662 uint32 num_of_tables=0; 1663 bcm_stat_flex_direction_t direction=bcmStatFlexDirectionIngress; 1664 uint32 byte_flag=0; 1665 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 1666 1667 /* Get the flex counter direction - ingress/egress */ 1668 if ((stat == bcmL3NatOutPackets) || 1669 (stat == bcmL3NatOutBytes)) { 1670 direction = bcmStatFlexDirectionEgress; 1671 } else { 1672 /* direction = bcmStatFlexDirectionIngress;*/ 1673 return BCM_E_UNAVAIL; 1674 } 1675 if (stat == bcmL3NatOutPackets) { 1676 byte_flag=0; 1677 } else { 1678 byte_flag=1; 1679 } 1680 1681 /* Get Table index to read the flex counter */ 1682 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_get_table_info( 1683 unit, info, &num_of_tables, &table_info[0])); 1684 1685 /* Get the flex counter for the attached table index */ 1686 for (table_count = 0; table_count < num_of_tables ; table_count++) { 1687 if (table_info[table_count].direction == direction) { 1688 for (index_count = 0; index_count < num_entries; index_count++) { 1689 BCM_IF_ERROR_RETURN(_bcm_esw_stat_counter_set( 1690 unit, 1691 table_info[table_count].index, 1692 table_info[table_count].table, 1693 0, 1694 byte_flag, 1695 counter_indexes[index_count], 1696 &counter_values[index_count])); 1697 } 1698 } 1699 } 1700 return BCM_E_NONE; 1701 } 1702 1703 /* 1704 * Function: 1705 * _bcm_td2_l3_nat_egress_stat_multi_get 1706 * 1707 * Description: 1708 * Get Multiple l3 egress nat counter value for specified l3 egress nat index for multiple stat 1709 * types 1710 * 1711 * Parameters: 1712 * unit - (IN) unit number 1713 * info - (IN) Egress Nat Info 1714 * nstat - (IN) Number of elements in stat array 1715 * stat_arr - (IN) Collected statistics descriptors array 1716 * value_arr - (OUT) Collected counters values 1717 * 1718 * Return Value: 1719 * BCM_E_XXX 1720 * Notes: 1721 */ 1722 1723 1724 int _bcm_td2_l3_nat_egress_stat_multi_get( 1725 int unit, 1726 bcm_l3_nat_egress_t *info, 1727 int nstat, 1728 bcm_l3_nat_egress_stat_t *stat_arr, 1729 uint64 *value_arr) 1730 { 1731 int rv = BCM_E_NONE; 1732 int idx; 1733 uint32 counter_indexes = 0; 1734 bcm_stat_value_t counter_values = {0}; 1735 int sync_mode = 0; 1736 1737 /* Iterate of all stats array to retrieve flex counter values */ 1738 for (idx = 0; idx < nstat ;idx++) { 1739 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_counter_get( 1740 unit, sync_mode, info, stat_arr[idx], 1741 1, &counter_indexes, &counter_values)); 1742 if ((stat_arr[idx] == bcmL3NatOutPackets)) { 1743 COMPILER_64_SET(value_arr[idx], 1744 COMPILER_64_HI(counter_values.packets64), 1745 COMPILER_64_LO(counter_values.packets64)); 1746 } else { 1747 COMPILER_64_SET(value_arr[idx], 1748 COMPILER_64_HI(counter_values.bytes), 1749 COMPILER_64_LO(counter_values.bytes)); 1750 } 1751 } 1752 return rv; 1753 } 1754 1755 /* 1756 * Function: 1757 * _bcm_td2_l3_nat_egress_stat_multi_get32 1758 * 1759 * Description: 1760 * Get 32bit l3 egress nat counter value for specified l3 egress nat index for multiple stat 1761 * types 1762 * 1763 * Parameters: 1764 * unit - (IN) unit number 1765 * info - (IN) Egress Nat Info 1766 * nstat - (IN) Number of elements in stat array 1767 * stat_arr - (IN) Collected statistics descriptors array 1768 * value_arr - (OUT) Collected counters values 1769 * 1770 * Return Value: 1771 * BCM_E_XXX 1772 * Notes: 1773 */ 1774 int _bcm_td2_l3_nat_egress_stat_multi_get32( 1775 int unit, 1776 bcm_l3_nat_egress_t *info, 1777 int nstat, 1778 bcm_l3_nat_egress_stat_t *stat_arr, 1779 uint32 *value_arr) 1780 { 1781 int rv = BCM_E_NONE; 1782 int idx; 1783 uint32 counter_indexes = 0; 1784 bcm_stat_value_t counter_values = {0}; 1785 int sync_mode = 0; 1786 1787 /* Iterate of all stats array to retrieve flex counter values */ 1788 for (idx = 0; idx < nstat ;idx++) { 1789 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_counter_get( 1790 unit, sync_mode, info, stat_arr[idx], 1791 1, &counter_indexes, &counter_values)); 1792 if ((stat_arr[idx] == bcmL3NatOutPackets)) { 1793 value_arr[idx] = counter_values.packets; 1794 } else { 1795 value_arr[idx] = COMPILER_64_LO(counter_values.bytes); 1796 } 1797 } 1798 return rv; 1799 } 1800 1801 /* 1802 * Function: 1803 * _bcm_td2_l3_nat_egress_stat_multi_set 1804 * 1805 * Description: 1806 * Set l3 egress nat counter value for specified l3 egress nat index for multiple stat 1807 * types 1808 * 1809 * Parameters: 1810 * unit - (IN) unit number 1811 * info - (IN) Egress Nat Info 1812 * stat - (IN) l3 egress nat counter stat types 1813 * num_entries - (IN) Number of counter Entries 1814 * counter_indexes - (IN) Pointer to Counter indexes entries 1815 * counter_values - (OUT) Pointer to counter values 1816 * 1817 * Return Value: 1818 * BCM_E_XXX 1819 * Notes: 1820 */ 1821 int _bcm_td2_l3_nat_egress_stat_multi_set( 1822 int unit, 1823 bcm_l3_nat_egress_t *info, 1824 int nstat, 1825 bcm_l3_nat_egress_stat_t *stat_arr, 1826 uint64 *value_arr) 1827 { 1828 int rv = BCM_E_NONE; 1829 int idx; 1830 uint32 counter_indexes = 0; 1831 bcm_stat_value_t counter_values = {0}; 1832 1833 /* Iterate f all stats array to retrieve flex counter values */ 1834 for (idx = 0; idx < nstat ;idx++) { 1835 if ((stat_arr[idx] == bcmL3NatOutPackets)) { 1836 counter_values.packets = COMPILER_64_LO(value_arr[idx]); 1837 } else { 1838 COMPILER_64_SET(counter_values.bytes, 1839 COMPILER_64_HI(value_arr[idx]), 1840 COMPILER_64_LO(value_arr[idx])); 1841 } 1842 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_counter_set( 1843 unit, info, stat_arr[idx], 1844 1, &counter_indexes, &counter_values)); 1845 } 1846 return rv; 1847 } 1848 1849 /* 1850 * Function: 1851 * _bcm_td2_l3_nat_egress_stat_multi_set32 1852 * 1853 * Description: 1854 * Set 32bit l3 egress nat counter value for specified l3 egress nat index for multiple stat 1855 * types 1856 * 1857 * Parameters: 1858 * unit - (IN) unit number 1859 * info - (IN) Egress Nat Info 1860 * stat - (IN) l3 egress nat counter stat types 1861 * num_entries - (IN) Number of counter Entries 1862 * counter_indexes - (IN) Pointer to Counter indexes entries 1863 * counter_values - (OUT) Pointer to counter values 1864 * 1865 * Return Value: 1866 * BCM_E_XXX 1867 * Notes: 1868 */ 1869 1870 int _bcm_td2_l3_nat_egress_stat_multi_set32( 1871 int unit, 1872 bcm_l3_nat_egress_t *info, 1873 int nstat, 1874 bcm_l3_nat_egress_stat_t *stat_arr, 1875 uint32 *value_arr) 1876 { 1877 int rv = BCM_E_NONE; 1878 int idx; 1879 uint32 counter_indexes = 0; 1880 bcm_stat_value_t counter_values = {0}; 1881 1882 /* Iterate of all stats array to retrieve flex counter values */ 1883 for (idx = 0; idx < nstat ;idx++) { 1884 if ((stat_arr[idx] == bcmL3NatOutPackets)) { 1885 counter_values.packets = value_arr[idx]; 1886 } else { 1887 COMPILER_64_SET(counter_values.bytes,0,value_arr[idx]); 1888 } 1889 1890 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_counter_set( 1891 unit, info, stat_arr[idx], 1892 1, &counter_indexes, &counter_values)); 1893 } 1894 return rv; 1895 } 1896 1897 /* 1898 * Function: 1899 * _bcm_td2_l3_nat_egress_stat_id_get 1900 * 1901 * Description: 1902 * Get Stat Counter if associated with given l3 egress nat index 1903 * 1904 * Parameters: 1905 * unit - (IN) bcm device 1906 * info - (IN) Egress Nat Info 1907 * stat - (IN) l3 egress nat counter stat types 1908 * stat_counter_id - (IN) Stat Counter ID. 1909 * 1910 * Returns: 1911 * BCM_E_NONE - Success 1912 * BCM_E_XXX 1913 * Notes: 1914 */ 1915 1916 int _bcm_td2_l3_nat_egress_stat_id_get( 1917 int unit, 1918 bcm_l3_nat_egress_t *info, 1919 bcm_l3_nat_egress_stat_t stat, 1920 uint32 *stat_counter_id) 1921 { 1922 bcm_stat_flex_direction_t direction = bcmStatFlexDirectionIngress; 1923 uint32 num_of_tables = 0; 1924 bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION]; 1925 uint32 index = 0; 1926 uint32 num_stat_counter_ids = 0; 1927 1928 if ((stat == bcmL3NatOutPackets) || 1929 (stat == bcmL3NatOutBytes)) { 1930 direction = bcmStatFlexDirectionEgress; 1931 } else { 1932 /* direction = bcmStatFlexDirectionIngress;*/ 1933 return BCM_E_UNAVAIL; 1934 } 1935 1936 /* Get Tables, for which flex counter are attached */ 1937 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_egress_stat_get_table_info( 1938 unit, info, &num_of_tables, &table_info[0])); 1939 1940 /* Retrieve stat counter id */ 1941 for (index = 0; index < num_of_tables ; index++) { 1942 if (table_info[index].direction == direction) 1943 return _bcm_esw_stat_flex_get_counter_id( 1944 unit, 1, &table_info[index], 1945 &num_stat_counter_ids, stat_counter_id); 1946 } 1947 return BCM_E_NOT_FOUND; 1948 } 1949 #endif /* BCM_TRIDENT2_SUPPORT */ 1950 /* 1951 * Function: 1952 * bcm_esw_l3_nat_egress_stat_attach 1953 * Description: 1954 * Attach counters entries to the given egress nat (egr nat packet edit 1955 * info). Allocate flex counter and assign counter index and offset for 1956 * the index pointed by egr nat info ( packet edit index) 1957 * 1958 * Parameters: 1959 * unit - (IN) unit number 1960 * info - (IN) Egress Nat Info 1961 * stat_counter_id - (IN) Stat Counter ID. 1962 * 1963 * Return Value: 1964 * BCM_E_XXX 1965 * Notes: 1966 */ 1967 1968 int bcm_esw_l3_nat_egress_stat_attach ( 1969 int unit, 1970 bcm_l3_nat_egress_t *info, 1971 uint32 stat_counter_id) 1972 { 1973 int rv = BCM_E_UNAVAIL; 1974 1975 #if defined(BCM_TRIDENT2_SUPPORT) 1976 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 1977 rv = _bcm_td2_l3_nat_egress_stat_attach ( 1978 unit, info, stat_counter_id); 1979 } 1980 #endif 1981 return rv; 1982 } 1983 1984 1985 /* 1986 * Function: 1987 * bcm_esw_l3_nat_egress_stat_detach 1988 * Description: 1989 * Detach counter entries to the given l3 egress nat index. 1990 * 1991 * Parameters: 1992 * unit - (IN) unit number 1993 * info - (IN) Egress Nat Info 1994 * 1995 * Return Value: 1996 * BCM_E_XXX 1997 * Notes: 1998 */ 1999 int bcm_esw_l3_nat_egress_stat_detach ( 2000 int unit, 2001 bcm_l3_nat_egress_t *info) 2002 { 2003 int rv = BCM_E_UNAVAIL; 2004 2005 #if defined(BCM_TRIDENT2_SUPPORT) 2006 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 2007 rv = _bcm_td2_l3_nat_egress_stat_detach (unit, info); 2008 } 2009 #endif 2010 return rv; 2011 } 2012 2013 /* 2014 * Function: 2015 * _bcm_esw_l3_nat_egress_stat_counter_get 2016 * 2017 * Description: 2018 * Get l3 egress nat counter value for specified l3 egress nat index 2019 * if sync_mode is set, sync the sw accumulated count 2020 * with hw count value first, else return sw count. 2021 * 2022 * Parameters: 2023 * unit - (IN) unit number 2024 * sync_mode - (IN) hwcount is to be synced to sw count 2025 * info - (IN) Egress Nat Info 2026 * stat - (IN) l3 egress nat counter stat types 2027 * num_entries - (IN) Number of counter Entries 2028 * counter_indexes - (IN) Pointer to Counter indexes entries 2029 * counter_values - (OUT) Pointer to counter values 2030 * 2031 * Return Value: 2032 * BCM_E_XXX 2033 * Notes: 2034 */ 2035 bcm_error_t 2036 _bcm_esw_l3_nat_egress_stat_counter_get(int unit, 2037 int sync_mode, 2038 bcm_l3_nat_egress_t *info, 2039 bcm_l3_nat_egress_stat_t stat, 2040 uint32 num_entries, 2041 uint32 *counter_indexes, 2042 bcm_stat_value_t *counter_values) 2043 { 2044 int rv = BCM_E_UNAVAIL; 2045 2046 #if defined(BCM_TRIDENT2_SUPPORT) 2047 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 2048 rv = _bcm_td2_l3_nat_egress_stat_counter_get(unit, sync_mode, 2049 info, stat, num_entries, 2050 counter_indexes, 2051 counter_values); 2052 } 2053 #endif 2054 return rv; 2055 } 2056 2057 /* 2058 * Function: 2059 * bcm_esw_l3_nat_egress_stat_counter_get 2060 * 2061 * Description: 2062 * Get l3 egress nat counter value for specified l3 egress nat index 2063 * 2064 * Parameters: 2065 * unit - (IN) unit number 2066 * info - (IN) Egress Nat Info 2067 * stat - (IN) l3 egress nat counter stat types 2068 * num_entries - (IN) Number of counter Entries 2069 * counter_indexes - (IN) Pointer to Counter indexes entries 2070 * counter_values - (OUT) Pointer to counter values 2071 * 2072 * Return Value: 2073 * BCM_E_XXX 2074 * Notes: 2075 */ 2076 int 2077 bcm_esw_l3_nat_egress_stat_counter_get(int unit, 2078 bcm_l3_nat_egress_t *info, 2079 bcm_l3_nat_egress_stat_t stat, 2080 uint32 num_entries, 2081 uint32 *counter_indexes, 2082 bcm_stat_value_t *counter_values) 2083 { 2084 return _bcm_esw_l3_nat_egress_stat_counter_get(unit, 0, info, 2085 stat, num_entries, 2086 counter_indexes, 2087 counter_values); 2088 } 2089 2090 /* 2091 * Function: 2092 * bcm_esw_l3_nat_egress_stat_counter_sync_get 2093 * 2094 * Description: 2095 * Get l3 egress nat counter value for specified l3 egress nat index 2096 * sw accumulated counters synced with hw count. 2097 * 2098 * Parameters: 2099 * unit - (IN) unit number 2100 * info - (IN) Egress Nat Info 2101 * stat - (IN) l3 egress nat counter stat types 2102 * num_entries - (IN) Number of counter Entries 2103 * counter_indexes - (IN) Pointer to Counter indexes entries 2104 * counter_values - (OUT) Pointer to counter values 2105 * 2106 * Return Value: 2107 * BCM_E_XXX 2108 * Notes: 2109 */ 2110 int 2111 bcm_esw_l3_nat_egress_stat_counter_sync_get(int unit, 2112 bcm_l3_nat_egress_t *info, 2113 bcm_l3_nat_egress_stat_t stat, 2114 uint32 num_entries, 2115 uint32 *counter_indexes, 2116 bcm_stat_value_t *counter_values) 2117 { 2118 return _bcm_esw_l3_nat_egress_stat_counter_get(unit, 1, info, 2119 stat, num_entries, 2120 counter_indexes, 2121 counter_values); 2122 } 2123 2124 /* 2125 * Function: 2126 * bcm_esw_l3_nat_egress_stat_counter_set 2127 * 2128 * Description: 2129 * Set l3 egress nat counter value for specified l3 egress nat index 2130 * 2131 * Parameters: 2132 * unit - (IN) unit number 2133 * info - (IN) Egress Nat Info 2134 * stat - (IN) l3 egress nat counter stat types 2135 * num_entries - (IN) Number of counter Entries 2136 * counter_indexes - (IN) Pointer to Counter indexes entries 2137 * counter_values - (OUT) Pointer to counter values 2138 * 2139 * Return Value: 2140 * BCM_E_XXX 2141 * Notes: 2142 */ 2143 int bcm_esw_l3_nat_egress_stat_counter_set( 2144 int unit, 2145 bcm_l3_nat_egress_t *info, 2146 bcm_l3_nat_egress_stat_t stat, 2147 uint32 num_entries, 2148 uint32 *counter_indexes, 2149 bcm_stat_value_t *counter_values) 2150 { 2151 int rv = BCM_E_UNAVAIL; 2152 2153 #if defined(BCM_TRIDENT2_SUPPORT) 2154 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 2155 rv = _bcm_td2_l3_nat_egress_stat_counter_set ( 2156 unit, info, stat, num_entries, 2157 counter_indexes, counter_values); 2158 } 2159 #endif 2160 return rv; 2161 } 2162 2163 /* 2164 * Function: 2165 * bcm_esw_l3_nat_egress_stat_multi_get 2166 * 2167 * Description: 2168 * Get Multiple l3 egress nat counter value for specified l3 egress nat index for multiple stat 2169 * types 2170 * 2171 * Parameters: 2172 * unit - (IN) unit number 2173 * info - (IN) Egress Nat Info 2174 * nstat - (IN) Number of elements in stat array 2175 * stat_arr - (IN) Collected statistics descriptors array 2176 * value_arr - (OUT) Collected counters values 2177 * 2178 * Return Value: 2179 * BCM_E_XXX 2180 * Notes: 2181 */ 2182 2183 2184 int bcm_esw_l3_nat_egress_stat_multi_get( 2185 int unit, 2186 bcm_l3_nat_egress_t *info, 2187 int nstat, 2188 bcm_l3_nat_egress_stat_t *stat_arr, 2189 uint64 *value_arr) 2190 { 2191 int rv = BCM_E_UNAVAIL; 2192 2193 #if defined(BCM_TRIDENT2_SUPPORT) 2194 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 2195 rv = _bcm_td2_l3_nat_egress_stat_multi_get ( 2196 unit, info, nstat, stat_arr, value_arr); 2197 } 2198 #endif 2199 return rv; 2200 } 2201 2202 /* 2203 * Function: 2204 * bcm_esw_l3_nat_egress_stat_multi_get32 2205 * 2206 * Description: 2207 * Get 32bit l3 egress nat counter value for specified l3 egress nat index for multiple stat 2208 * types 2209 * 2210 * Parameters: 2211 * unit - (IN) unit number 2212 * info - (IN) Egress Nat Info 2213 * nstat - (IN) Number of elements in stat array 2214 * stat_arr - (IN) Collected statistics descriptors array 2215 * value_arr - (OUT) Collected counters values 2216 * 2217 * Return Value: 2218 * BCM_E_XXX 2219 * Notes: 2220 */ 2221 int bcm_esw_l3_nat_egress_stat_multi_get32( 2222 int unit, 2223 bcm_l3_nat_egress_t *info, 2224 int nstat, 2225 bcm_l3_nat_egress_stat_t *stat_arr, 2226 uint32 *value_arr) 2227 { 2228 int rv = BCM_E_UNAVAIL; 2229 2230 #if defined(BCM_TRIDENT2_SUPPORT) 2231 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 2232 rv = _bcm_td2_l3_nat_egress_stat_multi_get32 ( 2233 unit, info, nstat, stat_arr, value_arr); 2234 } 2235 #endif 2236 return rv; 2237 } 2238 2239 /* 2240 * Function: 2241 * bcm_esw_l3_nat_egress_stat_multi_set 2242 * 2243 * Description: 2244 * Set l3 egress nat counter value for specified l3 egress nat index for multiple stat 2245 * types 2246 * 2247 * Parameters: 2248 * unit - (IN) unit number 2249 * info - (IN) Egress Nat Info 2250 * stat - (IN) l3 egress nat counter stat types 2251 * num_entries - (IN) Number of counter Entries 2252 * counter_indexes - (IN) Pointer to Counter indexes entries 2253 * counter_values - (OUT) Pointer to counter values 2254 * 2255 * Return Value: 2256 * BCM_E_XXX 2257 * Notes: 2258 */ 2259 int bcm_esw_l3_nat_egress_stat_multi_set( 2260 int unit, 2261 bcm_l3_nat_egress_t *info, 2262 int nstat, 2263 bcm_l3_nat_egress_stat_t *stat_arr, 2264 uint64 *value_arr) 2265 { 2266 int rv = BCM_E_UNAVAIL; 2267 2268 #if defined(BCM_TRIDENT2_SUPPORT) 2269 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 2270 rv = _bcm_td2_l3_nat_egress_stat_multi_set ( 2271 unit, info, nstat, stat_arr, value_arr); 2272 } 2273 #endif 2274 return rv; 2275 } 2276 2277 /* 2278 * Function: 2279 * bcm_esw_l3_nat_egress_stat_multi_set32 2280 * 2281 * Description: 2282 * Set 32bit l3 egress nat counter value for specified l3 egress nat index for multiple stat 2283 * types 2284 * 2285 * Parameters: 2286 * unit - (IN) unit number 2287 * info - (IN) Egress Nat Info 2288 * stat - (IN) l3 egress nat counter stat types 2289 * num_entries - (IN) Number of counter Entries 2290 * counter_indexes - (IN) Pointer to Counter indexes entries 2291 * counter_values - (OUT) Pointer to counter values 2292 * 2293 * Return Value: 2294 * BCM_E_XXX 2295 * Notes: 2296 */ 2297 2298 int bcm_esw_l3_nat_egress_stat_multi_set32( 2299 int unit, 2300 bcm_l3_nat_egress_t *info, 2301 int nstat, 2302 bcm_l3_nat_egress_stat_t *stat_arr, 2303 uint32 *value_arr) 2304 { 2305 int rv = BCM_E_UNAVAIL; 2306 2307 #if defined(BCM_TRIDENT2_SUPPORT) 2308 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 2309 rv = _bcm_td2_l3_nat_egress_stat_multi_set32 ( 2310 unit, info, nstat, stat_arr, value_arr); 2311 } 2312 #endif 2313 return rv; 2314 } 2315 2316 /* 2317 * Function: 2318 * bcm_esw_l3_nat_egress_stat_id_get 2319 * 2320 * Description: 2321 * Get Stat Counter if associated with given l3 egress nat index 2322 * 2323 * Parameters: 2324 * unit - (IN) bcm device 2325 * info - (IN) Egress Nat Info 2326 * stat - (IN) l3 egress nat counter stat types 2327 * stat_counter_id - (IN) Stat Counter ID. 2328 * 2329 * Returns: 2330 * BCM_E_NONE - Success 2331 * BCM_E_XXX 2332 * Notes: 2333 */ 2334 2335 int bcm_esw_l3_nat_egress_stat_id_get( 2336 int unit, 2337 bcm_l3_nat_egress_t *info, 2338 bcm_l3_nat_egress_stat_t stat, 2339 uint32 *stat_counter_id) 2340 { 2341 int rv = BCM_E_UNAVAIL; 2342 2343 #if defined(BCM_TRIDENT2_SUPPORT) 2344 if (soc_feature(unit,soc_feature_advanced_flex_counter)) { 2345 rv = _bcm_td2_l3_nat_egress_stat_id_get ( 2346 unit, info, stat, stat_counter_id); 2347 } 2348 #endif 2349 return rv; 2350 } 2351 2352 #if defined(BCM_TRIDENT2_SUPPORT) 2353 /* Convert from hw to sw representation of memory based on the type of ingress 2354 * NAT table 2355 */ 2356 static int 2357 _bcm_td2_l3_nat_ingress_hw_to_sw(int unit, soc_mem_t mem, void *key, 2358 bcm_l3_nat_ingress_t *result) 2359 { 2360 int keyt0, keyt1; 2361 uint32 dest_type = 0; 2362 2363 if (NULL == result) { 2364 return BCM_E_PARAM; 2365 } 2366 sal_memset(result, 0, sizeof(*result)); 2367 2368 switch (mem) { 2369 case ING_DNAT_ADDRESS_TYPEm: 2370 if (soc_feature(unit, soc_feature_base_valid)) { 2371 if (!soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, key, BASE_VALIDf)) { 2372 return BCM_E_EMPTY; 2373 } 2374 } else { 2375 if (!soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, key, VALIDf)) { 2376 return BCM_E_EMPTY; 2377 } 2378 } 2379 result->flags |= (BCM_L3_NAT_INGRESS_DNAT | BCM_L3_NAT_INGRESS_DNAT_POOL); 2380 result->ip_addr = 2381 soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, key, DEST_IPV4_ADDRf); 2382 result->vrf = 2383 soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, key, VRFf); 2384 if (soc_ING_DNAT_ADDRESS_TYPEm_field32_get(unit, key, POOL_ADDRESS_TYPEf)) 2385 { 2386 result->flags |= BCM_L3_NAT_INGRESS_TYPE_NAPT; 2387 } 2388 break; 2389 2390 case ING_SNATm: 2391 if (!soc_ING_SNATm_field32_get(unit, key, VALIDf)) { 2392 return BCM_E_EMPTY; 2393 } 2394 result->ip_addr = 2395 soc_ING_SNATm_field32_get(unit, key, IP_ADDRESSf); 2396 result->vrf = 2397 soc_ING_SNATm_field32_get(unit, key, VRFf); 2398 if (soc_mem_field32_get(unit, mem, key, NAT_TYPE_NAPTf)) { 2399 if (soc_ING_SNATm_field32_get(unit, key, L4_VALIDf)) { 2400 /* assume other fields are correctly masked */ 2401 result->flags |= BCM_L3_NAT_INGRESS_TYPE_NAPT; 2402 result->l4_port = 2403 soc_ING_SNATm_field32_get(unit, key, L4_SRC_PORTf); 2404 result->ip_proto = 2405 soc_ING_SNATm_field32_get(unit, key, IP_PROTOf); 2406 } else { 2407 /* something wrong with the entry */ 2408 return BCM_E_INTERNAL; 2409 } 2410 } 2411 result->nat_id = BCM_L3_NAT_EGRESS_SW_IDX_GET( 2412 soc_ING_SNATm_field32_get(unit, key, NAT_PACKET_EDIT_IDXf), 2413 soc_ING_SNATm_field32_get(unit, key, NAT_PACKET_EDIT_ENTRY_SELf)); 2414 if (soc_ING_SNATm_field32_get(unit, key, HITf)) { 2415 result->flags |= BCM_L3_NAT_INGRESS_HIT; 2416 } 2417 break; 2418 2419 case L3_ENTRY_IPV4_MULTICASTm: 2420 case L3_ENTRY_DOUBLEm: 2421 if (soc_feature(unit, soc_feature_base_valid)) { 2422 if (!(soc_L3_ENTRY_DOUBLEm_field32_get(unit, key, BASE_VALID_0f) && 2423 soc_L3_ENTRY_DOUBLEm_field32_get(unit, key, BASE_VALID_1f))) { 2424 return BCM_E_EMPTY; 2425 } 2426 } else { 2427 if (!(soc_L3_ENTRY_IPV4_MULTICASTm_field32_get(unit, key, VALID_0f) && 2428 soc_L3_ENTRY_IPV4_MULTICASTm_field32_get(unit, key, VALID_1f))) { 2429 return BCM_E_EMPTY; 2430 } 2431 } 2432 2433 /* check key type also. Needs to be either NAT or NAPT */ 2434 2435 if ( mem == L3_ENTRY_DOUBLEm) { 2436 keyt0 = soc_mem_field32_get(unit, mem, key, KEY_TYPEf); 2437 keyt1 = soc_mem_field32_get(unit, mem, key, KEY_TYPEf); 2438 } else { 2439 keyt0 = soc_mem_field32_get(unit, mem, key, KEY_TYPE_0f); 2440 keyt1 = soc_mem_field32_get(unit, mem, key,KEY_TYPE_1f); 2441 } 2442 result->flags |= BCM_L3_NAT_INGRESS_DNAT; 2443 result->ip_addr = 2444 soc_mem_field32_get(unit, mem, key, NAT__IP_ADDRf); 2445 result->vrf = 2446 soc_mem_field32_get(unit, mem, key, NAT__VRF_IDf); 2447 if (soc_mem_field32_get(unit, mem, key, NAT__L4_VALIDf)) { 2448 if ((keyt0 != TD2_L3_HASH_KEY_TYPE_DST_NAPT) || 2449 (keyt1 != TD2_L3_HASH_KEY_TYPE_DST_NAPT)) { 2450 return BCM_E_EMPTY; 2451 } 2452 result->flags |= BCM_L3_NAT_INGRESS_TYPE_NAPT; 2453 2454 result->l4_port = 2455 soc_mem_field32_get(unit, mem, key, NAT__L4_DEST_PORTf); 2456 result->ip_proto = 2457 soc_mem_field32_get(unit, mem, key, NAT__IP_PROTOf); 2458 } else { 2459 if ((keyt0 != TD2_L3_HASH_KEY_TYPE_DST_NAT) || 2460 (keyt1 != TD2_L3_HASH_KEY_TYPE_DST_NAT)) { 2461 return BCM_E_EMPTY; 2462 } 2463 } 2464 if (soc_mem_field32_get(unit, mem, key, HIT_0f) && 2465 soc_mem_field32_get(unit, mem, key, HIT_1f)) { 2466 result->flags |= BCM_L3_NAT_INGRESS_HIT; 2467 } 2468 2469 if (soc_feature(unit, soc_feature_generic_dest)) { 2470 result->nexthop = soc_mem_field32_dest_get(unit, mem, key, NAT__DESTINATIONf, 2471 &dest_type) ; 2472 if (dest_type == SOC_MEM_FIF_DEST_ECMP) { 2473 result->flags |= BCM_L3_NAT_INGRESS_MULTIPATH; 2474 result->nexthop += BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 2475 } else { 2476 result->nexthop += BCM_XGS3_EGRESS_IDX_MIN(unit); 2477 } 2478 } else { 2479 if (soc_L3_ENTRY_IPV4_MULTICASTm_field32_get(unit, key, NAT__ECMPf)) { 2480 result->flags |= BCM_L3_NAT_INGRESS_MULTIPATH; 2481 result->nexthop = soc_L3_ENTRY_IPV4_MULTICASTm_field32_get(unit, 2482 key, NAT__ECMP_PTRf) 2483 + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 2484 } else { 2485 result->nexthop = soc_L3_ENTRY_IPV4_MULTICASTm_field32_get(unit, 2486 key, NAT__NEXT_HOP_INDEXf) 2487 + BCM_XGS3_EGRESS_IDX_MIN(unit); 2488 } 2489 } 2490 if (soc_mem_field32_get(unit, mem, key, NAT__DST_DISCARDf)) { 2491 result->flags |= BCM_L3_NAT_INGRESS_DST_DISCARD; 2492 } 2493 2494 if (soc_mem_field32_get(unit, mem, key, NAT__RPEf)) { 2495 result->flags |= BCM_L3_NAT_INGRESS_RPE; 2496 result->pri = soc_mem_field32_get(unit, mem, key, NAT__PRIf); 2497 } 2498 result->class_id = soc_mem_field32_get(unit, mem, key, NAT__CLASS_IDf); 2499 result->nat_id = BCM_L3_NAT_EGRESS_SW_IDX_GET( 2500 soc_mem_field32_get(unit, mem, key, NAT__PACKET_EDIT_IDXf), 2501 soc_mem_field32_get(unit, mem, key, NAT__PACKET_EDIT_ENTRY_SELf)); 2502 break; 2503 2504 default: 2505 return BCM_E_PARAM; 2506 } 2507 return BCM_E_NONE; 2508 } 2509 2510 static int 2511 _bcm_td2_l3_nat_ingress_hit_update(int unit, soc_mem_t mem, int index, 2512 bcm_l3_nat_ingress_t *result) 2513 { 2514 uint32 hit; 2515 ing_snat_hit_only_x_entry_t snat_hit_x; 2516 ing_snat_hit_only_y_entry_t snat_hit_y; 2517 l3_entry_hit_only_x_entry_t l3_hit_x; 2518 l3_entry_hit_only_y_entry_t l3_hit_y; 2519 l3_entry_hit_only_entry_t l3_hit_default; 2520 int idx, idx_max, idx_offset, hit_idx_shift; 2521 soc_field_t hitf[] = {HIT_0f, HIT_1f, HIT_2f, HIT_3f}; 2522 2523 switch (mem) { 2524 case ING_DNAT_ADDRESS_TYPEm: 2525 break; 2526 2527 case ING_SNATm: 2528 BCM_IF_ERROR_RETURN( 2529 BCM_XGS3_MEM_READ(unit, ING_SNAT_HIT_ONLY_Xm, 2530 index, &snat_hit_x)); 2531 BCM_IF_ERROR_RETURN( 2532 BCM_XGS3_MEM_READ(unit, ING_SNAT_HIT_ONLY_Ym, 2533 index, &snat_hit_y)); 2534 if (soc_ING_SNAT_HIT_ONLY_Xm_field32_get(unit, &snat_hit_x, HITf) || 2535 soc_ING_SNAT_HIT_ONLY_Ym_field32_get(unit, &snat_hit_y, HITf)) { 2536 result->flags |= BCM_L3_NAT_INGRESS_HIT; 2537 } 2538 break; 2539 2540 case L3_ENTRY_IPV4_MULTICASTm: 2541 case L3_ENTRY_DOUBLEm: 2542 idx_max = 2; 2543 hit_idx_shift = 1; 2544 idx_offset = (index & 0x1) << 1; 2545 2546 if (soc_feature(unit, soc_feature_two_ingress_pipes)) { 2547 BCM_IF_ERROR_RETURN( 2548 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Xm, 2549 (index >> hit_idx_shift), &l3_hit_x)); 2550 BCM_IF_ERROR_RETURN( 2551 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLY_Ym, 2552 (index >> hit_idx_shift), &l3_hit_y)); 2553 2554 hit = 0; 2555 for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) { 2556 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Xm, 2557 &l3_hit_x, hitf[idx]); 2558 } 2559 2560 for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) { 2561 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLY_Ym, 2562 &l3_hit_y, hitf[idx]); 2563 } 2564 } else { 2565 BCM_IF_ERROR_RETURN( 2566 BCM_XGS3_MEM_READ(unit, L3_ENTRY_HIT_ONLYm, 2567 (index >> hit_idx_shift), &l3_hit_default)); 2568 2569 hit = 0; 2570 for (idx = idx_offset; idx < (idx_offset + idx_max); idx++) { 2571 hit |= soc_mem_field32_get(unit, L3_ENTRY_HIT_ONLYm, 2572 &l3_hit_default, hitf[idx]); 2573 } 2574 } 2575 if (hit) { 2576 result->flags |= BCM_L3_NAT_INGRESS_HIT; 2577 } 2578 break; 2579 2580 default: 2581 return BCM_E_PARAM; 2582 } 2583 2584 return BCM_E_NONE; 2585 } 2586 2587 static int 2588 _bcm_td2_l3_nat_ingress_set_nexthop(int unit, soc_mem_t mem, void *hw_buf, 2589 bcm_l3_nat_ingress_t *nat_info) 2590 { 2591 int rv = BCM_E_NONE, nh_idx; 2592 uint32 mpath_flag = 0; 2593 2594 /* figure out hw index from egress object */ 2595 rv = bcm_xgs3_get_nh_from_egress_object(unit, nat_info->nexthop, 2596 &mpath_flag, 0, &nh_idx); 2597 2598 if (BCM_FAILURE(rv)) { 2599 return rv; 2600 } 2601 /* make sure mpath setting is consistent with input */ 2602 if (nat_info->flags & BCM_L3_NAT_INGRESS_MULTIPATH) { 2603 if (!mpath_flag) { 2604 return BCM_E_PARAM; 2605 } 2606 2607 if (soc_feature(unit, soc_feature_generic_dest)) { 2608 soc_mem_field32_dest_set(unit, mem, (uint32 *)hw_buf, 2609 NAT__DESTINATIONf, SOC_MEM_FIF_DEST_ECMP, nh_idx); 2610 } else { 2611 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__ECMPf, 2612 1); 2613 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__ECMP_PTRf, 2614 nh_idx); 2615 } 2616 } else { 2617 if (mpath_flag) { 2618 return BCM_E_PARAM; 2619 } 2620 if (nh_idx != BCM_XGS3_L3_INVALID_INDEX ) { 2621 if (soc_feature(unit, soc_feature_generic_dest)) { 2622 soc_mem_field32_dest_set(unit, mem, (uint32 *)hw_buf, 2623 NAT__DESTINATIONf, SOC_MEM_FIF_DEST_NEXTHOP, nh_idx); 2624 } else { 2625 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__ECMPf, 2626 0); 2627 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__NEXT_HOP_INDEXf, 2628 nh_idx); 2629 } 2630 } else { 2631 return BCM_E_PARAM; 2632 } 2633 } 2634 return rv; 2635 } 2636 2637 static int 2638 _bcm_td2_l3_nat_ingress_sw_to_hw(int unit, soc_mem_t mem, void *hw_buf, 2639 bcm_l3_nat_ingress_t *nat_info) 2640 { 2641 /* Fill out key depending on the memory type */ 2642 uint32 mask_len, mask; 2643 int hw_idx, hw_half, key_type,data_type; 2644 2645 if ((NULL == hw_buf) || (NULL == nat_info)) { 2646 return BCM_E_PARAM; 2647 } 2648 2649 if (nat_info->nat_id > (NAT_ID_MAX(unit)-1)) { 2650 return BCM_E_PARAM; 2651 } 2652 2653 switch (mem) { 2654 case ING_DNAT_ADDRESS_TYPEm: 2655 sal_memset(hw_buf, 0, sizeof(ing_dnat_address_type_entry_t)); 2656 soc_ING_DNAT_ADDRESS_TYPEm_field32_set(unit, hw_buf, DEST_IPV4_ADDRf, 2657 nat_info->ip_addr); 2658 soc_ING_DNAT_ADDRESS_TYPEm_field32_set(unit, hw_buf, VRFf, 2659 nat_info->vrf); 2660 #ifdef BCM_MONTEREY_SUPPORT 2661 if (SOC_IS_MONTEREY(unit)) { 2662 soc_mem_field32_set(unit, mem, hw_buf, DEST_IPV4_ADDR_MASKf, 2663 0xffffffff); 2664 2665 soc_ING_SNATm_field32_set(unit, hw_buf, VRFf, nat_info->vrf); 2666 mask_len = soc_mem_field_length(unit, ING_DNAT_ADDRESS_TYPEm, VRFf); 2667 mask = (1 << mask_len) - 1; 2668 soc_mem_field32_set(unit, mem, hw_buf, VRF_MASKf, mask); 2669 } 2670 #endif 2671 /* data portion */ 2672 soc_ING_DNAT_ADDRESS_TYPEm_field32_set(unit, hw_buf, POOL_ADDRESS_TYPEf, 2673 nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT ? 1 : 0); 2674 2675 2676 if (soc_feature(unit, soc_feature_base_valid)) { 2677 soc_ING_DNAT_ADDRESS_TYPEm_field32_set(unit, hw_buf, BASE_VALIDf, 1); 2678 } else { 2679 soc_ING_DNAT_ADDRESS_TYPEm_field32_set(unit, hw_buf, VALIDf, 1); 2680 } 2681 break; 2682 case ING_SNATm: 2683 sal_memset(hw_buf, 0, sizeof(ing_snat_entry_t)); 2684 soc_ING_SNATm_field32_set(unit, hw_buf, IP_ADDRESSf, nat_info->ip_addr); 2685 2686 soc_mem_field32_set(unit, mem, hw_buf, IP_ADDRESS_MASKf, 2687 0xffffffff); 2688 2689 soc_ING_SNATm_field32_set(unit, hw_buf, VRFf, nat_info->vrf); 2690 mask_len = soc_mem_field_length(unit, ING_SNATm, VRFf); 2691 mask = (1 << mask_len) - 1; 2692 soc_mem_field32_set(unit, mem, hw_buf, VRF_MASKf, mask); 2693 2694 if (nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT) { 2695 soc_ING_SNATm_field32_set(unit, hw_buf, IP_PROTOf, 2696 nat_info->ip_proto); 2697 mask_len = soc_mem_field_length(unit, ING_SNATm, IP_PROTOf); 2698 mask = (1 << mask_len) - 1; 2699 soc_mem_field32_set(unit, mem, hw_buf, IP_PROTO_MASKf, mask); 2700 2701 soc_ING_SNATm_field32_set(unit, hw_buf, L4_SRC_PORTf, 2702 nat_info->l4_port); 2703 mask_len = soc_mem_field_length(unit, ING_SNATm, L4_SRC_PORTf); 2704 mask = (1 << mask_len) - 1; 2705 soc_mem_field32_set(unit, mem, hw_buf, L4_SRC_PORT_MASKf, 2706 mask); 2707 2708 soc_ING_SNATm_field32_set(unit, hw_buf, L4_VALIDf, 1); 2709 mask_len = soc_mem_field_length(unit, ING_SNATm, L4_VALIDf); 2710 mask = (1 << mask_len) - 1; 2711 soc_mem_field32_set(unit, mem, hw_buf, L4_VALID_MASKf, mask); 2712 2713 /* data part */ 2714 soc_ING_SNATm_field32_set(unit, hw_buf, NAT_TYPE_NAPTf, 1); 2715 } 2716 2717 /* data portion */ 2718 BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_info->nat_id, hw_idx, hw_half); 2719 soc_ING_SNATm_field32_set(unit, hw_buf, NAT_PACKET_EDIT_ENTRY_SELf, 2720 hw_half); 2721 soc_ING_SNATm_field32_set(unit, hw_buf, NAT_PACKET_EDIT_IDXf, hw_idx); 2722 soc_ING_SNATm_field32_set(unit, hw_buf, HITf, 2723 nat_info->flags & BCM_L3_NAT_INGRESS_HIT ? 1 : 0); 2724 2725 soc_ING_SNATm_field32_set(unit, hw_buf, VALIDf, 1); 2726 2727 break; 2728 case L3_ENTRY_IPV4_MULTICASTm: 2729 #ifdef BCM_TRIDENT3_SUPPORT 2730 case L3_ENTRY_DOUBLEm: 2731 #endif 2732 sal_memset(hw_buf, 0, sizeof(l3_entry_only_double_entry_t)); 2733 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__IP_ADDRf, 2734 nat_info->ip_addr); 2735 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__VRF_IDf, 2736 nat_info->vrf); 2737 key_type = TD2_L3_HASH_KEY_TYPE_DST_NAT; 2738 data_type = TD3_L3_HASH_DATA_TYPE_DST_NAT; 2739 2740 if (nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT) { 2741 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, 2742 NAT__IP_PROTOf, 2743 nat_info->ip_proto); 2744 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, 2745 NAT__L4_DEST_PORTf, 2746 nat_info->l4_port); 2747 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, 2748 NAT__L4_VALIDf, 1); 2749 key_type = TD2_L3_HASH_KEY_TYPE_DST_NAPT; 2750 data_type = TD3_L3_HASH_DATA_TYPE_DST_NAPT; 2751 } 2752 2753 /* data portion */ 2754 if (nat_info->flags & BCM_L3_NAT_INGRESS_DST_DISCARD) { 2755 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, 2756 NAT__DST_DISCARDf, 1); 2757 } 2758 2759 if (nat_info->flags & BCM_L3_NAT_INGRESS_RPE) { 2760 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__RPEf,1); 2761 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__PRIf, 2762 nat_info->pri); 2763 } 2764 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, NAT__CLASS_IDf, 2765 nat_info->class_id); 2766 BCM_L3_NAT_EGRESS_HW_IDX_GET(nat_info->nat_id, hw_idx, hw_half); 2767 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, 2768 NAT__PACKET_EDIT_ENTRY_SELf, hw_half); 2769 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, 2770 NAT__PACKET_EDIT_IDXf, hw_idx); 2771 2772 if (mem == L3_ENTRY_DOUBLEm) { 2773 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, KEY_TYPEf, 2774 key_type); 2775 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, BASE_VALID_0f, 3); 2776 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, BASE_VALID_1f, 4); 2777 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, DATA_TYPEf, 2778 data_type); 2779 } else { 2780 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, KEY_TYPE_0f, 2781 key_type); 2782 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, KEY_TYPE_1f, 2783 key_type); 2784 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, VALID_0f, 1); 2785 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, VALID_1f, 1); 2786 } 2787 2788 2789 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, HIT_0f, 2790 nat_info->flags & BCM_L3_NAT_INGRESS_HIT ? 1 : 0); 2791 soc_mem_field32_set(unit, mem, (uint32 *)hw_buf, HIT_1f, 2792 nat_info->flags & BCM_L3_NAT_INGRESS_HIT ? 1 : 0); 2793 2794 if (soc_feature(unit, soc_feature_generic_dest)) { 2795 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, nat_info->nexthop) && 2796 nat_info->flags & BCM_L3_NAT_INGRESS_MULTIPATH) { 2797 soc_mem_field32_dest_set(unit, mem, (uint32 *)hw_buf, NAT__DESTINATIONf, 2798 SOC_MEM_FIF_DEST_ECMP, nat_info->nexthop - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)); 2799 } else if(BCM_XGS3_L3_EGRESS_IDX_VALID(unit, nat_info->nexthop)){ 2800 soc_mem_field32_dest_set(unit, mem, (uint32 *)hw_buf, NAT__DESTINATIONf, 2801 SOC_MEM_FIF_DEST_NEXTHOP, 2802 nat_info->nexthop - BCM_XGS3_EGRESS_IDX_MIN(unit)); 2803 } 2804 } else { 2805 if (BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, nat_info->nexthop) && 2806 nat_info->flags & BCM_L3_NAT_INGRESS_MULTIPATH) { 2807 soc_L3_ENTRY_IPV4_MULTICASTm_field32_set(unit, hw_buf, NAT__ECMPf, 1); 2808 soc_L3_ENTRY_IPV4_MULTICASTm_field32_set(unit, hw_buf, NAT__ECMP_PTRf, 2809 nat_info->nexthop - 2810 BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)); 2811 } else if(BCM_XGS3_L3_EGRESS_IDX_VALID(unit, nat_info->nexthop)){ 2812 soc_L3_ENTRY_IPV4_MULTICASTm_field32_set(unit, hw_buf, NAT__NEXT_HOP_INDEXf, 2813 nat_info->nexthop - 2814 BCM_XGS3_EGRESS_IDX_MIN(unit)); 2815 } 2816 } 2817 break; 2818 default: 2819 return BCM_E_PARAM; 2820 } 2821 return BCM_E_NONE; 2822 } 2823 #ifdef BCM_MONTEREY_SUPPORT 2824 2825 /* helper function that compares the int_dnat_address_type entries */ 2826 static int 2827 _bcm_mn_l3_nat_ing_dnat_address_type_cmp(int unit, bcm_l3_nat_ingress_t *snat_entry, 2828 bcm_l3_nat_ingress_t *hw_snat_entry) 2829 { 2830 if (snat_entry->ip_addr != hw_snat_entry->ip_addr) { 2831 return BCM_E_FAIL; 2832 } 2833 if (snat_entry->vrf != hw_snat_entry->vrf) { 2834 return BCM_E_FAIL; 2835 } 2836 return BCM_E_NONE; 2837 } 2838 2839 /* helper function that lookup an entry in the int_dnat_address_type table */ 2840 static int 2841 _bcm_mn_l3_nat_ing_dnat_address_type_lookup(int unit, bcm_l3_nat_ingress_t *nat_info, 2842 void *key, int *index, void *result) 2843 { 2844 ing_dnat_address_type_entry_t *dnat_address_type_entryp; 2845 bcm_l3_nat_ingress_t hw_nat_info; 2846 soc_mem_t mem = ING_DNAT_ADDRESS_TYPEm; 2847 char *tbl = NULL; 2848 int start_idx, end_idx, i, rv, tbl_count; 2849 2850 dnat_address_type_entryp = (ing_dnat_address_type_entry_t *) key; 2851 2852 /* dma memory */ 2853 rv = _bcm_td2_l3_nat_read_mem(unit, mem, sizeof(*dnat_address_type_entryp), "ing dnat address type", 2854 &tbl, &tbl_count); 2855 2856 /* search NAT part */ 2857 start_idx = soc_mem_index_min(unit, mem); 2858 end_idx = BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit); 2859 2860 for (i = start_idx; i < end_idx; i++) { 2861 dnat_address_type_entryp = soc_mem_table_idx_to_pointer(unit, mem, 2862 ing_dnat_address_type_entry_t *, tbl, i); 2863 /* compare the dmaed entry with input key */ 2864 rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, (void *) dnat_address_type_entryp, 2865 &hw_nat_info); 2866 if (!BCM_SUCCESS(rv)) { 2867 /* had trouble converting. Likely a mismatch anyway */ 2868 continue; 2869 } 2870 rv = _bcm_mn_l3_nat_ing_dnat_address_type_cmp(unit, nat_info, &hw_nat_info); 2871 if (BCM_SUCCESS(rv)) { 2872 break; 2873 } 2874 } 2875 if (i == end_idx) { 2876 rv = BCM_E_NOT_FOUND; 2877 } else { 2878 rv = BCM_E_NONE; 2879 } 2880 *index = i; 2881 /* copy entry into result pointer */ 2882 if (BCM_SUCCESS(rv)) { 2883 sal_memcpy(result, dnat_address_type_entryp, sizeof(*dnat_address_type_entryp)); 2884 } 2885 /* free dmaed table memory */ 2886 soc_cm_sfree(unit, tbl); 2887 2888 return rv; 2889 } 2890 /* Just do plain addition. Replacement already done in caller. */ 2891 static int 2892 _bcm_mn_l3_nat_ing_dnat_address_type_entry_add(int unit, soc_mem_t mem, 2893 bcm_l3_nat_ingress_t *nat_info, 2894 ing_dnat_address_type_entry_t *entryp) 2895 { 2896 int rv; 2897 int idx, new_idx, *idx_ptr; 2898 2899 /* New entry. Not duplicate. */ 2900 /* check if space is available */ 2901 if (BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit) > 2902 soc_mem_index_max(unit, ING_DNAT_ADDRESS_TYPEm)) { 2903 return BCM_E_FULL; 2904 } 2905 2906 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, entryp, 2907 nat_info)); 2908 2909 idx = BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit); 2910 idx_ptr = &BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit); 2911 new_idx = idx + 1; 2912 /* coverity[negative_returns : FALSE] */ 2913 rv = soc_mem_write(unit, mem, COPYNO_ALL, idx, entryp); 2914 if (SOC_SUCCESS(rv)) { 2915 *idx_ptr = new_idx; 2916 return BCM_E_NONE; 2917 } 2918 return BCM_E_FAIL; 2919 } 2920 2921 /* helper function that deletes an entry from the int_dnat_address_type table */ 2922 static int 2923 _bcm_mn_l3_nat_ing_dnat_address_type_entry_delete(int unit, soc_mem_t mem, 2924 bcm_l3_nat_ingress_t *nat_info, 2925 void *key) 2926 { 2927 int index = -1, rv; 2928 int last_idx, *idx_ptr; 2929 ing_dnat_address_type_entry_t last_entry; 2930 2931 /* lookup entry. */ 2932 rv = _bcm_mn_l3_nat_ing_dnat_address_type_lookup(unit, nat_info, key, &index, key); 2933 2934 if (!BCM_SUCCESS(rv)) { 2935 return rv; 2936 } 2937 2938 /* copy last valid entry into this entry index */ 2939 /* get last ing_dnat_address_type entry index */ 2940 last_idx = BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit) - 1; 2941 idx_ptr = &BCM_L3_NAT_ING_DNAT_ADDRESS_TYPE_FREE_IDX(unit); 2942 2943 /* read last entry */ 2944 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, last_idx, &last_entry); 2945 2946 if (!SOC_SUCCESS(rv)) { 2947 return BCM_E_INTERNAL; 2948 } 2949 2950 /* write it into the entry to be deleted */ 2951 /* coverity[negative_returns : FALSE] */ 2952 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, &last_entry); 2953 if (!SOC_SUCCESS(rv)) { 2954 return BCM_E_INTERNAL; 2955 } 2956 2957 /* delete last entry */ 2958 sal_memset(&last_entry, 0, sizeof(last_entry)); 2959 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, last_idx, &last_entry); 2960 if (!SOC_SUCCESS(rv)) { 2961 return BCM_E_INTERNAL; 2962 } 2963 2964 /* update free index */ 2965 *idx_ptr = last_idx; 2966 return BCM_E_NONE; 2967 } 2968 #endif 2969 static int 2970 _bcm_td2_l3_nat_ing_snat_cmp(int unit, bcm_l3_nat_ingress_t *snat_entry, 2971 bcm_l3_nat_ingress_t *hw_snat_entry) 2972 { 2973 /* filter out flags which are not relevant for match */ 2974 if ((snat_entry->flags & ~(BCM_L3_NAT_INGRESS_HIT | BCM_L3_NAT_INGRESS_REPLACE)) 2975 != (hw_snat_entry->flags & ~BCM_L3_NAT_INGRESS_HIT)) { 2976 return BCM_E_FAIL; 2977 } 2978 if (snat_entry->ip_addr != hw_snat_entry->ip_addr) { 2979 return BCM_E_FAIL; 2980 } 2981 if (snat_entry->vrf != hw_snat_entry->vrf) { 2982 return BCM_E_FAIL; 2983 } 2984 if (snat_entry->vrf != hw_snat_entry->vrf) { 2985 return BCM_E_FAIL; 2986 } 2987 if (!(snat_entry->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT)) { 2988 return BCM_E_NONE; 2989 } 2990 if (snat_entry->ip_proto != hw_snat_entry->ip_proto) { 2991 return BCM_E_FAIL; 2992 } 2993 if (snat_entry->l4_port != hw_snat_entry->l4_port) { 2994 return BCM_E_FAIL; 2995 } 2996 return BCM_E_NONE; 2997 } 2998 2999 3000 3001 static int 3002 _bcm_td2_l3_nat_ing_snat_lookup(int unit, bcm_l3_nat_ingress_t *nat_info, 3003 void *key, int *index, void *result) 3004 { 3005 ing_snat_entry_t *snat_entryp; 3006 bcm_l3_nat_ingress_t hw_nat_info; 3007 soc_mem_t mem = ING_SNATm; 3008 char *tbl = NULL; 3009 int start_idx, end_idx, i, rv, tbl_count; 3010 3011 snat_entryp = (ing_snat_entry_t *) key; 3012 #if 0 3013 /* already done in caller */ 3014 rv = _bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, &snat_entry, nat_info); 3015 #endif 3016 3017 /* dma memory */ 3018 rv = _bcm_td2_l3_nat_read_mem(unit, mem, sizeof(*snat_entryp), "ing snat", 3019 &tbl, &tbl_count); 3020 3021 if (nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT) { 3022 /* search NAPT part */ 3023 start_idx = BCM_NAT_EGRESS_ID_MIN(unit); 3024 end_idx = BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit); 3025 } else { 3026 /* search NAT part */ 3027 start_idx = BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit) + 1; 3028 end_idx = soc_mem_index_max(unit, mem) + 1; 3029 } 3030 for (i = start_idx; i < end_idx; i++) { 3031 snat_entryp = soc_mem_table_idx_to_pointer(unit, mem, 3032 ing_snat_entry_t *, tbl, i); 3033 /* compare the dmaed entry with input key */ 3034 rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, (void *) snat_entryp, 3035 &hw_nat_info); 3036 if (!BCM_SUCCESS(rv)) { 3037 /* had trouble converting. Likely a mismatch anyway */ 3038 continue; 3039 } 3040 rv = _bcm_td2_l3_nat_ing_snat_cmp(unit, nat_info, &hw_nat_info); 3041 if (BCM_SUCCESS(rv)) { 3042 break; 3043 } 3044 } 3045 if (i == end_idx) { 3046 rv = BCM_E_NOT_FOUND; 3047 } else { 3048 rv = BCM_E_NONE; 3049 } 3050 *index = i; 3051 /* copy entry into result pointer */ 3052 if (BCM_SUCCESS(rv)) { 3053 sal_memcpy(result, snat_entryp, sizeof(*snat_entryp)); 3054 } 3055 /* free dmaed table memory */ 3056 soc_cm_sfree(unit, tbl); 3057 3058 return rv; 3059 } 3060 static int 3061 _bcm_td2_l3_nat_search_ing_mems(int unit, soc_mem_t mem, 3062 bcm_l3_nat_ingress_t *nat_info, 3063 int *index, void *key, void *result) 3064 { 3065 int rv = 0; 3066 3067 if (NULL == key || NULL == result) { 3068 return BCM_E_PARAM; 3069 } 3070 3071 rv = _bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, key, nat_info); 3072 if (!BCM_SUCCESS(rv)) { 3073 return rv; 3074 } 3075 3076 /* launch lookup */ 3077 if (mem == ING_SNATm) { 3078 rv = _bcm_td2_l3_nat_ing_snat_lookup(unit, nat_info, key, index, result); 3079 } else { 3080 #ifdef BCM_MONTEREY_SUPPORT 3081 if (SOC_IS_MONTEREY(unit) && 3082 (mem == ING_DNAT_ADDRESS_TYPEm)) { 3083 rv = _bcm_mn_l3_nat_ing_dnat_address_type_lookup(unit, nat_info, key, index, result); 3084 } else 3085 #endif 3086 { 3087 rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, index, key, result, 0); 3088 if (rv != SOC_E_NONE) { 3089 return BCM_E_NOT_FOUND; 3090 } 3091 } 3092 } 3093 return rv; 3094 } 3095 3096 3097 3098 /* helper function that deletes entries from the ingress SNAT/DNAT table. Just 3099 an intermediary function to all the delete api function */ 3100 int 3101 _bcm_td2_l3_nat_ingress_delete_entry(int unit, int idx, 3102 bcm_l3_nat_ingress_t *nat_info, 3103 void *user_data) 3104 { 3105 return bcm_esw_l3_nat_ingress_delete(unit, nat_info); 3106 } 3107 3108 int 3109 _bcm_td2_l3_nat_ingress_age_entry(int unit, int idx, 3110 bcm_l3_nat_ingress_t *nat_info, 3111 void *user_data) 3112 { 3113 /* Extract original user data */ 3114 bcm_l3_nat_ingress_cb_context_t *user_context; 3115 int rv = BCM_E_NONE; 3116 uint32 hw_buf[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer. */ 3117 3118 3119 sal_memset(hw_buf, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 3120 3121 if ((NULL == nat_info) || (NULL == user_data)) { 3122 return BCM_E_PARAM; 3123 } 3124 3125 user_context = (bcm_l3_nat_ingress_cb_context_t *) user_data; 3126 3127 3128 /* if HIT bit set then clear it */ 3129 if (nat_info->flags & BCM_L3_NAT_INGRESS_HIT) { 3130 nat_info->flags &= (~BCM_L3_NAT_INGRESS_HIT); 3131 rv = _bcm_td2_l3_nat_ingress_sw_to_hw(unit, user_context->mem, hw_buf, 3132 nat_info); 3133 if (!BCM_SUCCESS(rv)) { 3134 return rv; 3135 } 3136 /* write entry with cleared hit bit to hw */ 3137 rv = soc_mem_write(unit, user_context->mem, COPYNO_ALL, idx, hw_buf); 3138 } else { 3139 /* hit bit already cleared. Delete it */ 3140 rv = bcm_esw_l3_nat_ingress_delete(unit, nat_info); 3141 } 3142 3143 /* call user callback */ 3144 if ((BCM_SUCCESS(rv)) && (user_context->user_cb)) { 3145 rv = (*(user_context->user_cb))(unit, idx, nat_info, 3146 user_context->user_data); 3147 } 3148 3149 return rv; 3150 } 3151 3152 3153 /* Just do plain addition. Replacement already done in caller. */ 3154 static int 3155 _bcm_td2_l3_nat_ingress_snat_entry_add(int unit, soc_mem_t mem, 3156 bcm_l3_nat_ingress_t *nat_info, 3157 ing_snat_entry_t *snat_entryp) 3158 { 3159 int rv; 3160 int idx, new_idx, *idx_ptr; 3161 3162 /* NAPT entries occupy upper side of table, NAT entries occupy lower side 3163 to ensure NAPT gets higher priority match */ 3164 /* New entry. Not duplicate. */ 3165 /* check if space is available */ 3166 if (BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit) > 3167 BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit)) { 3168 return BCM_E_FULL; 3169 } 3170 3171 if (nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT) { 3172 idx = BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit); 3173 idx_ptr = &BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit); 3174 new_idx = idx + 1; 3175 } else { 3176 idx = BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit); 3177 idx_ptr = &BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit); 3178 new_idx = idx - 1; 3179 } 3180 rv = soc_mem_write(unit, mem, COPYNO_ALL, idx, snat_entryp); 3181 if (SOC_SUCCESS(rv)) { 3182 *idx_ptr = new_idx; 3183 return BCM_E_NONE; 3184 } 3185 return BCM_E_FAIL; 3186 } 3187 #endif /* BCM_TRIDENT2_SUPPORT */ 3188 3189 /* 3190 * Function: 3191 * bcm_esw_l3_nat_ingress_add 3192 * 3193 * Description: 3194 * Add an ingress NAT table entry. Depending on the flags settings an 3195 * entry is added to either the ingress DNAT pool table, DNAT session 3196 * table or SNAT session table. 3197 * 3198 * Parameters: 3199 * unit - (IN) bcm device 3200 * nat_info - (IN) ingress nat_info 3201 */ 3202 int 3203 bcm_esw_l3_nat_ingress_add(int unit, bcm_l3_nat_ingress_t *nat_info) 3204 { 3205 int rv = BCM_E_UNAVAIL; 3206 3207 #if defined(BCM_TRIDENT2_SUPPORT) 3208 soc_mem_t mem; 3209 bcm_l3_nat_egress_t tmp_nat; 3210 bcm_l3_nat_ingress_t tmp_ing_nat; 3211 ing_dnat_address_type_entry_t pool; 3212 ing_snat_entry_t snat; 3213 int mem_counter; 3214 int index; 3215 int max_int_pri = 15; 3216 void *result; 3217 int hw_idx, hw_half; 3218 ing_dnat_address_type_entry_t old_pool; 3219 ing_snat_entry_t old_snat; 3220 uint32 dnat[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer. */ 3221 uint32 old_dnat[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer. */ 3222 void *old_result; 3223 int full_nat, count; 3224 3225 sal_memset(dnat, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 3226 sal_memset(old_dnat, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 3227 if (soc_feature(unit, soc_feature_nat)) { 3228 if (NULL == nat_info) { 3229 return BCM_E_PARAM; 3230 } 3231 3232 if ((nat_info->vrf > SOC_VRF_MAX(unit)) || 3233 (nat_info->vrf < BCM_L3_VRF_DEFAULT)) { 3234 return BCM_E_PARAM; 3235 } 3236 3237 full_nat = BCM_L3_NAT_EGRESS_FLAGS_FULL_NAT(nat_info->flags); 3238 count = full_nat ? 2 : 1; 3239 /* figure out which mem to operate on */ 3240 BCM_L3_NAT_INGRESS_GET_MEM_POINTER(unit, nat_info, mem, pool, dnat, 3241 snat, result, mem_counter); 3242 /* figure out which old mem to operate on */ 3243 BCM_L3_NAT_INGRESS_GET_MEM_ONLY(unit, nat_info, mem, old_pool, 3244 old_dnat, old_snat, old_result); 3245 3246 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 3247 3248 /* validate info in nat_info structure: */ 3249 if (mem != ING_DNAT_ADDRESS_TYPEm) { 3250 if ((mem == L3_ENTRY_IPV4_MULTICASTm) && 3251 (nat_info->flags & BCM_L3_NAT_INGRESS_RPE)) { 3252 if ((nat_info->pri < BCM_PRIO_MIN) || 3253 (nat_info->pri > max_int_pri)) { 3254 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3255 return BCM_E_PARAM; 3256 } 3257 }else if ((mem == L3_ENTRY_DOUBLEm) && 3258 (nat_info->flags & BCM_L3_NAT_INGRESS_RPE)) { 3259 if ((nat_info->pri < BCM_PRIO_MIN) || 3260 (nat_info->pri > max_int_pri)) { 3261 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3262 return BCM_E_PARAM; 3263 } 3264 } 3265 /* DNAT and SNAT entries should have valid pkt edit idx */ 3266 /* check if provided nat_id is valid */ 3267 tmp_nat.nat_id = nat_info->nat_id; 3268 rv = bcm_esw_l3_nat_egress_get(unit, &tmp_nat); 3269 3270 3271 if (!BCM_SUCCESS(rv)) { 3272 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3273 return rv; 3274 } 3275 } 3276 /* check if entry already exists in the specified table */ 3277 rv = _bcm_td2_l3_nat_search_ing_mems(unit, mem, nat_info, 3278 &index, result, old_result); 3279 3280 /* if found, if replace flag set then replace entry. Otherwise declare error 3281 */ 3282 if (rv == BCM_E_NONE) { 3283 if (nat_info->flags & BCM_L3_NAT_INGRESS_REPLACE) { 3284 if (mem == L3_ENTRY_IPV4_MULTICASTm) { 3285 /* set nexthop correctly */ 3286 rv = _bcm_td2_l3_nat_ingress_set_nexthop(unit, mem, result, 3287 nat_info) ; 3288 if (!BCM_SUCCESS(rv)) { 3289 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3290 return rv; 3291 } 3292 } 3293 if (mem == L3_ENTRY_DOUBLEm) { 3294 /* set nexthop correctly */ 3295 rv = _bcm_td2_l3_nat_ingress_set_nexthop(unit, mem, result, 3296 nat_info) ; 3297 if (!BCM_SUCCESS(rv)) { 3298 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3299 return rv; 3300 } 3301 } 3302 3303 /* if nat_id is different, then delete original nat_id */ 3304 if (mem != ING_DNAT_ADDRESS_TYPEm) { 3305 /* convert result to sw format to get nat_id */ 3306 rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, old_result, 3307 &tmp_ing_nat); 3308 if (!BCM_SUCCESS(rv)) { 3309 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3310 return BCM_E_INTERNAL; 3311 } 3312 if (tmp_ing_nat.nat_id != nat_info->nat_id) { 3313 /* delete the original nat id */ 3314 rv = _bcm_td2_l3_nat_egress_dec_refcount(unit, 3315 tmp_ing_nat.nat_id); 3316 if (!BCM_SUCCESS(rv)) { 3317 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3318 return BCM_E_INTERNAL; 3319 } 3320 3321 BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, nat_info->nat_id, 3322 count); 3323 3324 /* Update data portion */ 3325 BCM_L3_NAT_EGRESS_HW_IDX_GET 3326 (nat_info->nat_id, hw_idx, hw_half); 3327 if (mem == ING_SNATm) { 3328 soc_ING_SNATm_field32_set 3329 (unit, result, NAT_PACKET_EDIT_ENTRY_SELf, 3330 hw_half); 3331 soc_ING_SNATm_field32_set 3332 (unit, result, NAT_PACKET_EDIT_IDXf, hw_idx); 3333 } else if (mem == L3_ENTRY_IPV4_MULTICASTm) { 3334 soc_L3_ENTRY_IPV4_MULTICASTm_field32_set 3335 (unit, result, NAT__PACKET_EDIT_ENTRY_SELf, 3336 hw_half); 3337 soc_L3_ENTRY_IPV4_MULTICASTm_field32_set 3338 (unit, result, NAT__PACKET_EDIT_IDXf, hw_idx); 3339 } 3340 #ifdef BCM_TRIDENT3_SUPPORT 3341 else if (mem == L3_ENTRY_DOUBLEm) { 3342 soc_L3_ENTRY_DOUBLEm_field32_set 3343 (unit, result, NAT__PACKET_EDIT_ENTRY_SELf, 3344 hw_half); 3345 soc_L3_ENTRY_DOUBLEm_field32_set 3346 (unit, result, NAT__PACKET_EDIT_IDXf, hw_idx); 3347 } 3348 #endif 3349 } 3350 } 3351 /* overwrite entry with this one */ 3352 rv = soc_mem_write(unit, mem, COPYNO_ALL, index, result); 3353 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3354 return rv; 3355 } else { 3356 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3357 return BCM_E_EXISTS; 3358 } 3359 } else if (rv == BCM_E_NOT_FOUND) { 3360 if (nat_info->flags & BCM_L3_NAT_INGRESS_REPLACE) { 3361 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3362 return rv; 3363 } 3364 } else { 3365 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3366 return rv; 3367 } 3368 3369 /* new entry. Insert into relevant table */ 3370 if (mem != ING_SNATm) { 3371 if (mem == L3_ENTRY_IPV4_MULTICASTm || mem == L3_ENTRY_DOUBLEm) { 3372 /* set nexthop correctly */ 3373 rv = _bcm_td2_l3_nat_ingress_set_nexthop(unit, mem, result, 3374 nat_info) ; 3375 if (!BCM_SUCCESS(rv)) { 3376 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3377 return rv; 3378 } 3379 } 3380 #ifdef BCM_MONTEREY_SUPPORT 3381 if (SOC_IS_MONTEREY(unit) && 3382 (mem == ING_DNAT_ADDRESS_TYPEm)) { 3383 rv = _bcm_mn_l3_nat_ing_dnat_address_type_entry_add(unit, mem, nat_info, 3384 (ing_dnat_address_type_entry_t*)result); 3385 } else 3386 #endif 3387 { 3388 rv = soc_mem_insert(unit, mem, COPYNO_ALL, result); 3389 } 3390 if (rv == SOC_E_FULL) { 3391 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3392 return BCM_E_FULL; 3393 } 3394 if (rv != SOC_E_NONE) { 3395 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3396 return BCM_E_INTERNAL; 3397 } 3398 } else { 3399 rv = _bcm_td2_l3_nat_ingress_snat_entry_add(unit, mem, nat_info, 3400 (ing_snat_entry_t *)result); 3401 if (!BCM_SUCCESS(rv)) { 3402 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3403 return rv; 3404 } 3405 } 3406 3407 /* Increment Egress ref count */ 3408 if (mem != ING_DNAT_ADDRESS_TYPEm) { 3409 BCM_L3_NAT_EGRESS_INC_REF_COUNT(unit, nat_info->nat_id, count); 3410 } 3411 3412 /* increment table count */ 3413 BCM_L3_NAT_INGRESS_INC_TBL_CNT(unit, mem_counter); 3414 rv = BCM_E_NONE; 3415 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3416 } 3417 #endif 3418 return rv; 3419 } 3420 3421 #ifdef BCM_TRIDENT2_SUPPORT 3422 3423 static int 3424 _bcm_td2_l3_nat_ingress_snat_entry_delete(int unit, soc_mem_t mem, 3425 bcm_l3_nat_ingress_t *nat_info, 3426 void *key) 3427 { 3428 int index = -1, rv; 3429 int last_idx, *idx_ptr; 3430 ing_snat_entry_t last_snat; 3431 3432 /* lookup entry. */ 3433 rv = _bcm_td2_l3_nat_ing_snat_lookup(unit, nat_info, key, &index, key); 3434 3435 if (!BCM_SUCCESS(rv)) { 3436 return rv; 3437 } 3438 3439 /* copy last valid entry into this entry index */ 3440 if (nat_info->flags & BCM_L3_NAT_INGRESS_TYPE_NAPT) { 3441 /* get last napt entry index */ 3442 last_idx = BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit) - 1; 3443 idx_ptr = &BCM_L3_NAT_INGRESS_SNAT_NAPT_FREE_IDX(unit); 3444 } else { 3445 last_idx = BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit) + 1; 3446 idx_ptr = &BCM_L3_NAT_INGRESS_SNAT_NAT_FREE_IDX(unit); 3447 } 3448 3449 /* read last entry */ 3450 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, last_idx, &last_snat); 3451 3452 if (!SOC_SUCCESS(rv)) { 3453 return BCM_E_INTERNAL; 3454 } 3455 3456 /* write it into the entry to be deleted */ 3457 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, &last_snat); 3458 if (!SOC_SUCCESS(rv)) { 3459 return BCM_E_INTERNAL; 3460 } 3461 3462 /* delete last entry */ 3463 sal_memset(&last_snat, 0, sizeof(last_snat)); 3464 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, last_idx, &last_snat); 3465 if (!SOC_SUCCESS(rv)) { 3466 return BCM_E_INTERNAL; 3467 } 3468 3469 /* update free index */ 3470 *idx_ptr = last_idx; 3471 return BCM_E_NONE; 3472 } 3473 #endif /* BCM_TRIDENT2_SUPPORT */ 3474 3475 /* 3476 * Function: 3477 * bcm_esw_l3_nat_ingress_delete 3478 * 3479 * Description: 3480 * Delete an ingress NAT table entry. Depending on the flags settings an 3481 * entry is deleted from either the ingress DNAT pool table, DNAT session 3482 * table or SNAT session table. 3483 * 3484 * Parameters: 3485 * unit - (IN) bcm device 3486 * nat_info - (IN) ingress nat_info 3487 */ 3488 int 3489 bcm_esw_l3_nat_ingress_delete( 3490 int unit, 3491 bcm_l3_nat_ingress_t *nat_info) 3492 { 3493 int rv = BCM_E_UNAVAIL; 3494 3495 #if defined(BCM_TRIDENT2_SUPPORT) 3496 soc_mem_t mem; 3497 ing_dnat_address_type_entry_t pool, old_pool; 3498 ing_snat_entry_t snat; 3499 bcm_l3_nat_ingress_t tmp_ing_nat; 3500 ing_snat_entry_t old_snat; 3501 void *result; 3502 void *old_result; 3503 int mem_counter, index; 3504 uint32 dnat[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer. */ 3505 uint32 old_dnat[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer. */ 3506 3507 sal_memset(dnat, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 3508 sal_memset(old_dnat, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 3509 3510 3511 if (soc_feature(unit, soc_feature_nat)) { 3512 /* validate input */ 3513 if (NULL == nat_info) { 3514 return BCM_E_PARAM; 3515 } 3516 3517 if ((nat_info->vrf > SOC_VRF_MAX(unit)) || 3518 (nat_info->vrf < BCM_L3_VRF_DEFAULT)) { 3519 return BCM_E_PARAM; 3520 } 3521 BCM_L3_NAT_INGRESS_GET_MEM_POINTER(unit, nat_info, mem, pool, dnat, 3522 snat, result, mem_counter); 3523 /* figure out which old mem to operate on */ 3524 BCM_L3_NAT_INGRESS_GET_MEM_ONLY(unit, nat_info, mem, old_pool, 3525 old_dnat, old_snat, old_result); 3526 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, result, 3527 nat_info)); 3528 /* Clean PRIf to avoid illegal pri */ 3529 if ((mem == L3_ENTRY_IPV4_MULTICASTm) && 3530 (nat_info->flags & BCM_L3_NAT_INGRESS_RPE)) { 3531 soc_L3_ENTRY_IPV4_MULTICASTm_field32_set(unit, result, 3532 NAT__PRIf, 0); 3533 } else if ((mem == L3_ENTRY_DOUBLEm) && 3534 (nat_info->flags & BCM_L3_NAT_INGRESS_RPE)) { 3535 soc_L3_ENTRY_DOUBLEm_field32_set(unit, result, 3536 NAT__PRIf, 0); 3537 } 3538 3539 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 3540 3541 if (mem != ING_SNATm) { 3542 if (mem == L3_ENTRY_IPV4_MULTICASTm || mem == L3_ENTRY_DOUBLEm) { 3543 rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &index, result, 3544 old_result, 0); 3545 if (rv != SOC_E_NONE) { 3546 return BCM_E_NOT_FOUND; 3547 } 3548 rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, old_result, 3549 &tmp_ing_nat); 3550 if (!BCM_SUCCESS(rv)) { 3551 return BCM_E_INTERNAL; 3552 } 3553 nat_info->nat_id = tmp_ing_nat.nat_id; 3554 } 3555 /* delete entry from table */ 3556 #ifdef BCM_MONTEREY_SUPPORT 3557 if (SOC_IS_MONTEREY(unit) && 3558 (mem == ING_DNAT_ADDRESS_TYPEm)) { 3559 rv = _bcm_mn_l3_nat_ing_dnat_address_type_entry_delete(unit, mem, nat_info, 3560 result); 3561 } else 3562 #endif 3563 { 3564 rv = soc_mem_delete(unit, mem, COPYNO_ALL, result); 3565 } 3566 if (SOC_FAILURE(rv)) { 3567 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3568 return rv; 3569 } 3570 } else { 3571 rv = _bcm_td2_l3_nat_ingress_snat_entry_delete(unit, mem, nat_info, 3572 result); 3573 if (rv != BCM_E_NONE) { 3574 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3575 return rv; 3576 } 3577 } 3578 3579 if (mem != ING_DNAT_ADDRESS_TYPEm) { 3580 /* decrement refcount for the egress nat_id */ 3581 rv = _bcm_td2_l3_nat_egress_dec_refcount(unit, nat_info->nat_id); 3582 3583 if (rv != BCM_E_NONE) { 3584 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3585 return rv; 3586 } 3587 } 3588 /* decrement table count */ 3589 BCM_L3_NAT_INGRESS_DEC_TBL_CNT(unit, mem_counter); 3590 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3591 return BCM_E_NONE; 3592 } 3593 #endif /* BCM_TRIDENT_SUPPORT */ 3594 return rv; 3595 } 3596 3597 /* 3598 * Function: 3599 * bcm_esw_l3_nat_ingress_traverse 3600 * 3601 * Description: 3602 * Traverse through the ingress NAT table specified by flags and invoke a 3603 * user provided callback for each valid entry, that matches the flags. 3604 * 3605 * Parameters: 3606 * unit - (IN) bcm device 3607 * flags - (IN) Flags to match during traverse 3608 * start - (IN) First index to read 3609 * end - (IN) Last index to read 3610 * cb - (IN) Caller notification callback 3611 * user_data - (IN) User cookie which should be returned in cb 3612 */ 3613 int bcm_esw_l3_nat_ingress_traverse(int unit, uint32 flags, uint32 start, 3614 uint32 end, bcm_l3_nat_ingress_traverse_cb cb, 3615 void *user_data) 3616 { 3617 int rv = BCM_E_UNAVAIL; 3618 3619 #if defined(BCM_TRIDENT2_SUPPORT) 3620 soc_mem_t mem; 3621 bcm_l3_nat_ingress_t tmp_nat; 3622 ing_dnat_address_type_entry_t *pool; 3623 ing_snat_entry_t *snat; 3624 l3_entry_ipv4_multicast_entry_t *dnat; 3625 l3_entry_double_entry_t *dnatdouble; 3626 int pool_sz = sizeof(ing_dnat_address_type_entry_t); 3627 int dnat_sz = sizeof(l3_entry_ipv4_multicast_entry_t); 3628 #ifdef BCM_TRIDENT3_SUPPORT 3629 int dnat_sz1 = sizeof(l3_entry_double_entry_t); 3630 #endif 3631 int snat_sz = sizeof(ing_snat_entry_t); 3632 int *result, idx, tbl_size; 3633 char *buffer = NULL; 3634 void *entry_ptr; 3635 uint32 tmp_flags = BCM_L3_NAT_INGRESS_HIT 3636 | BCM_L3_NAT_INGRESS_MULTIPATH | BCM_L3_NAT_INGRESS_RPE 3637 | BCM_L3_NAT_INGRESS_DST_DISCARD | BCM_L3_NAT_INGRESS_REPLACE; 3638 3639 if (soc_feature(unit, soc_feature_nat)) { 3640 /* pick memory */ 3641 /* make macro-compatible: */ 3642 tmp_nat.flags = flags; 3643 #ifdef BCM_TRIDENT3_SUPPORT 3644 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_DOUBLEm)) { 3645 BCM_L3_NAT_INGRESS_GET_MEM_ONLY(unit, &tmp_nat, mem, pool_sz, dnat_sz1, 3646 snat_sz, result); 3647 } else 3648 #endif 3649 { 3650 BCM_L3_NAT_INGRESS_GET_MEM_ONLY(unit, &tmp_nat, mem, pool_sz, dnat_sz, 3651 snat_sz, result); 3652 } 3653 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 3654 3655 /* dma memory */ 3656 rv = _bcm_td2_l3_nat_read_mem(unit, mem, *result, "l3 nat ingress", &buffer, 3657 &tbl_size); 3658 if (!BCM_SUCCESS(rv)) { 3659 /* free memory */ 3660 if (buffer != NULL) { 3661 soc_cm_sfree(unit, buffer); 3662 } 3663 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3664 return rv; 3665 } 3666 3667 /* Input indexes sanity */ 3668 if (start >= (uint32)tbl_size || (end >= (uint32)tbl_size 3669 && end != 0xffffffff) || start > end) { 3670 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3671 return (BCM_E_NOT_FOUND); 3672 } 3673 /* End value according to real table size */ 3674 if (end == 0xffffffff) { 3675 end = (uint32)tbl_size - 1; 3676 } 3677 3678 /* walk from start to end, matching flags */ 3679 for (idx = start; idx <= end; idx++) { 3680 /* read entry at index */ 3681 switch (mem) { 3682 case ING_DNAT_ADDRESS_TYPEm: 3683 pool = soc_mem_table_idx_to_pointer(unit, mem, 3684 ing_dnat_address_type_entry_t *, buffer, idx); 3685 entry_ptr = (void *) pool; 3686 break; 3687 case ING_SNATm: 3688 snat = soc_mem_table_idx_to_pointer(unit, mem, 3689 ing_snat_entry_t *, buffer, idx); 3690 entry_ptr = (void *) snat; 3691 break; 3692 case L3_ENTRY_IPV4_MULTICASTm: 3693 dnat = soc_mem_table_idx_to_pointer(unit, mem, 3694 l3_entry_ipv4_multicast_entry_t *, buffer, idx); 3695 entry_ptr = (void *) dnat; 3696 break; 3697 case L3_ENTRY_DOUBLEm: 3698 dnatdouble = soc_mem_table_idx_to_pointer(unit, mem, 3699 l3_entry_double_entry_t *, buffer, idx); 3700 entry_ptr = (void *) dnatdouble; 3701 break; 3702 /* coverity[dead_error_begin] */ 3703 default: 3704 soc_cm_sfree(unit, buffer); 3705 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3706 return BCM_E_PARAM; 3707 } 3708 rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, entry_ptr, 3709 &tmp_nat); 3710 /* no valid entry */ 3711 if (BCM_E_EMPTY == rv) { 3712 continue; 3713 } 3714 (void)_bcm_td2_l3_nat_ingress_hit_update(unit, mem, idx, 3715 &tmp_nat); 3716 3717 if ((flags & BCM_L3_NAT_INGRESS_HIT) 3718 && (!(tmp_nat.flags & BCM_L3_NAT_INGRESS_HIT))) { 3719 continue; 3720 } 3721 3722 if ((flags & BCM_L3_NAT_INGRESS_MULTIPATH) 3723 && (!(tmp_nat.flags & BCM_L3_NAT_INGRESS_MULTIPATH))) { 3724 continue; 3725 } 3726 3727 if ((flags & BCM_L3_NAT_INGRESS_RPE) 3728 && (!(tmp_nat.flags & BCM_L3_NAT_INGRESS_RPE))) { 3729 continue; 3730 } 3731 3732 if ((flags & BCM_L3_NAT_INGRESS_DST_DISCARD) 3733 && (!(tmp_nat.flags & BCM_L3_NAT_INGRESS_DST_DISCARD))) { 3734 continue; 3735 } 3736 3737 if ((flags & (~tmp_flags)) != (tmp_nat.flags & (~tmp_flags))) { 3738 continue; 3739 } 3740 3741 /* call callback */ 3742 rv = (*cb)(unit, idx, &tmp_nat, user_data); 3743 #ifdef BCM_CB_ABORT_ON_ERR 3744 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 3745 break; 3746 } 3747 #endif 3748 } 3749 if (idx > end) { 3750 /* broke out at end of loop */ 3751 rv = BCM_E_NONE; 3752 } 3753 } 3754 if (buffer) { 3755 soc_cm_sfree(unit, buffer); 3756 } 3757 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3758 #endif /* BCM_TRIDENT_SUPPORT */ 3759 return rv; 3760 } 3761 3762 /* 3763 * Function: 3764 * bcm_esw_l3_nat_ingress_find 3765 * 3766 * Description: 3767 * Find an ingress NAT table entry. Depending on the flags settings an 3768 * entry is search for in either the ingress DNAT pool table, DNAT session 3769 * table or SNAT session table. 3770 * 3771 * Parameters: 3772 * unit - (IN) bcm device 3773 * nat_info - (IN/OUT) ingress nat_info 3774 */ 3775 int 3776 bcm_esw_l3_nat_ingress_find( 3777 int unit, 3778 bcm_l3_nat_ingress_t *nat_info) 3779 { 3780 int rv = BCM_E_UNAVAIL; 3781 3782 #if defined(BCM_TRIDENT2_SUPPORT) 3783 soc_mem_t mem; 3784 ing_dnat_address_type_entry_t pool; 3785 ing_snat_entry_t snat; 3786 void *result; 3787 int idx; 3788 uint32 dnat[SOC_MAX_MEM_FIELD_WORDS]; /* HW entry buffer. */ 3789 3790 sal_memset(dnat, 0, SOC_MAX_MEM_FIELD_WORDS * sizeof(uint32)); 3791 3792 if (soc_feature(unit, soc_feature_nat)) { 3793 if (NULL == nat_info) { 3794 return BCM_E_PARAM; 3795 } 3796 3797 if ((nat_info->vrf > SOC_VRF_MAX(unit)) || 3798 (nat_info->vrf < BCM_L3_VRF_DEFAULT)) { 3799 return BCM_E_PARAM; 3800 } 3801 /* search for the entry */ 3802 BCM_L3_NAT_INGRESS_GET_MEM_ONLY(unit, nat_info, mem, pool, dnat, 3803 snat, result); 3804 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, result, 3805 nat_info)); 3806 3807 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 3808 if (mem != ING_SNATm) { 3809 #ifdef BCM_MONTEREY_SUPPORT 3810 if (SOC_IS_MONTEREY(unit) && 3811 (mem == ING_DNAT_ADDRESS_TYPEm)) { 3812 rv = _bcm_mn_l3_nat_ing_dnat_address_type_lookup(unit, nat_info, result, &idx, 3813 result); 3814 } else 3815 #endif 3816 { 3817 rv = soc_mem_search(unit, mem, MEM_BLOCK_ANY, &idx, result, 3818 result, 0); 3819 } 3820 if (rv != SOC_E_NONE) { 3821 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3822 return BCM_E_NOT_FOUND; 3823 } 3824 } else { 3825 rv = _bcm_td2_l3_nat_ing_snat_lookup(unit, nat_info, result, &idx, 3826 result); 3827 if (rv != BCM_E_NONE) { 3828 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3829 return BCM_E_NOT_FOUND; 3830 } 3831 } 3832 rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, result, nat_info); 3833 (void)_bcm_td2_l3_nat_ingress_hit_update(unit, mem, idx, nat_info); 3834 3835 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3836 return rv; 3837 } 3838 #endif /* BCM_TRIDENT_SUPPORT */ 3839 return rv; 3840 } 3841 3842 /* 3843 * Function: 3844 * bcm_esw_l3_nat_ingress_delete_all 3845 * 3846 * Description: 3847 * Traverse through the ingress NAT table specified by flags and invoke a 3848 * user provided callback for each valid entry, that matches the flags. 3849 * 3850 * Parameters: 3851 * unit - (IN) bcm device 3852 * nat_info - (IN) Only flags field is valid. These are used to figure 3853 * out which table to clear 3854 */ 3855 int bcm_esw_l3_nat_ingress_delete_all( 3856 int unit, 3857 bcm_l3_nat_ingress_t *nat_info) 3858 { 3859 int rv = BCM_E_UNAVAIL; 3860 3861 #if defined(BCM_TRIDENT2_SUPPORT) 3862 soc_mem_t mem; 3863 int mem_counter; 3864 if (soc_feature(unit, soc_feature_nat)) { 3865 if (NULL == nat_info) { 3866 return BCM_E_PARAM; 3867 } 3868 3869 /* figure out which memory to clear */ 3870 if (nat_info->flags & (BCM_L3_NAT_INGRESS_DNAT)) { 3871 if (nat_info->flags & BCM_L3_NAT_INGRESS_DNAT_POOL) { 3872 mem = ING_DNAT_ADDRESS_TYPEm; 3873 mem_counter = BCM_L3_NAT_INGRESS_POOL_CNT; 3874 } else { 3875 if (SOC_MEM_IS_VALID( unit, L3_ENTRY_DOUBLEm)) { 3876 mem = L3_ENTRY_DOUBLEm; 3877 } else { 3878 mem = L3_ENTRY_IPV4_MULTICASTm; 3879 } 3880 mem_counter = BCM_L3_NAT_INGRESS_DNAT_CNT; 3881 } 3882 } else { 3883 mem = ING_SNATm; 3884 mem_counter = BCM_L3_NAT_INGRESS_SNAT_CNT; 3885 } 3886 3887 /* if not shared table just clear it */ 3888 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_lock(unit)); 3889 if (mem == ING_DNAT_ADDRESS_TYPEm) { 3890 #ifdef BCM_MONTEREY_SUPPORT 3891 if (SOC_IS_MONTEREY(unit)) { 3892 rv = bcm_esw_l3_nat_ingress_traverse(unit, nat_info->flags, 3893 soc_mem_index_min(unit, mem), soc_mem_index_max(unit, mem), 3894 _bcm_td2_l3_nat_ingress_delete_entry, NULL); 3895 } else 3896 #endif 3897 { 3898 rv = soc_mem_clear(unit, mem, COPYNO_ALL, 1); 3899 } 3900 if (!SOC_SUCCESS(rv)) { 3901 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3902 return BCM_E_INTERNAL; 3903 } 3904 } else { 3905 /* if shared table, traverse and delete individual entries */ 3906 rv = bcm_esw_l3_nat_ingress_traverse(unit, nat_info->flags, 3907 soc_mem_index_min(unit, mem), soc_mem_index_max(unit, mem), 3908 _bcm_td2_l3_nat_ingress_delete_entry, NULL); 3909 if (BCM_FAILURE(rv)) { 3910 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3911 return rv; 3912 } 3913 } 3914 /* clear table count to 0 */ 3915 BCM_L3_NAT_INGRESS_CLR_TBL_CNT(unit, mem_counter); 3916 BCM_IF_ERROR_RETURN(_bcm_esw_l3_nat_unlock(unit)); 3917 return BCM_E_NONE; 3918 } 3919 #endif /* BCM_TRIDENT2_SUPPORT */ 3920 return rv; 3921 } 3922 3923 /* 3924 * Function: 3925 * bcm_esw_l3_nat_ingress_age 3926 * 3927 * Description: 3928 * Run aging on either DNAT session or SNAT session table as specified 3929 * by the flags. Clear the hit bit for the entry or if it is already cleared 3930 * delete the entry. 3931 * 3932 * Parameters: 3933 * unit - (IN) bcm device 3934 * flags - (IN) flags to match to identify entry to act upon. 3935 * age_cb - (IN) user provided callback fn to call for each entry 3936 * user_data - (IN) parameter to user provided callback 3937 */ 3938 int bcm_esw_l3_nat_ingress_age(int unit, uint32 flags, 3939 bcm_l3_nat_ingress_traverse_cb age_cb, 3940 void *user_data) 3941 { 3942 int rv = BCM_E_UNAVAIL; 3943 3944 #if defined(BCM_TRIDENT2_SUPPORT) 3945 soc_mem_t mem; 3946 bcm_l3_nat_ingress_cb_context_t user_context; 3947 3948 if (soc_feature(unit, soc_feature_nat)) { 3949 /* validate flags. Aging supported only on DNAT or SNAT session tables */ 3950 if (flags & BCM_L3_NAT_INGRESS_DNAT_POOL) { 3951 return BCM_E_PARAM; 3952 } 3953 /* call traversal function with an ager callback */ 3954 if (flags & BCM_L3_NAT_INGRESS_DNAT) { 3955 mem = L3_ENTRY_IPV4_MULTICASTm; 3956 if (SOC_MEM_IS_VALID(unit, L3_ENTRY_DOUBLEm)) { 3957 mem = L3_ENTRY_DOUBLEm; 3958 } 3959 } else { 3960 mem = ING_SNATm; 3961 } 3962 /* pass original user callback info to intermediate callback function */ 3963 user_context.user_cb = age_cb; 3964 user_context.user_data = user_data; 3965 user_context.mem = mem; 3966 rv = bcm_esw_l3_nat_ingress_traverse(unit, flags, BCM_NAT_EGRESS_ID_MIN(unit), 3967 soc_mem_index_max(unit, mem), 3968 _bcm_td2_l3_nat_ingress_age_entry, 3969 (void *) &user_context); 3970 return rv; 3971 3972 } 3973 #endif /* BCM_TRIDENT2_SUPPORT */ 3974 return rv; 3975 } 3976 3977 /* 3978 * Function: 3979 * bcm_esw_l3_large_nat_egress_add 3980 * Description: 3981 * Add a NAT translation entry to the egress NAT xlate table. 3982 * Parameters: 3983 * unit - (IN) Device number. 3984 * nat_info - (IN) 3985 * IN: packet edit info: original IP/ports and translated IP/ports 3986 * Returns: 3987 * BCM_E_XXX 3988 */ 3989 int 3990 bcm_esw_l3_large_nat_egress_add( 3991 int unit, 3992 bcm_l3_large_nat_egress_t *nat_info) 3993 { 3994 #if defined(BCM_TRIDENT3_SUPPORT) 3995 if (soc_feature(unit, soc_feature_large_scale_nat)) { 3996 /* validate input */ 3997 if (NULL == nat_info) { 3998 return BCM_E_PARAM; 3999 } 4000 4001 /* must specify at least one of SNAT or DNAT */ 4002 if (!(nat_info->flags & (BCM_L3_LARGE_NAT_EGRESS_SNAT | 4003 BCM_L3_LARGE_NAT_EGRESS_DNAT))) { 4004 return BCM_E_PARAM; 4005 } 4006 4007 if ((nat_info->flags & BCM_L3_LARGE_NAT_EGRESS_MACDA_UPDATE) && 4008 !(nat_info->flags & BCM_L3_LARGE_NAT_EGRESS_MULTICAST)) { 4009 return BCM_E_PARAM; 4010 } 4011 4012 /* validate nat class id */ 4013 if (nat_info->nat_class_id <= 0 || 4014 nat_info->nat_class_id > 0xffff) { 4015 return BCM_E_PARAM; 4016 } 4017 4018 /* validate l3 interface class id if supplied */ 4019 if (nat_info->intf_class_id < 0 || 4020 nat_info->intf_class_id > 0xfff) { 4021 return BCM_E_PARAM; 4022 } 4023 4024 /* validate replication id if supplied */ 4025 if (nat_info->replication_id < 0 || 4026 nat_info->replication_id > 0xffff) { 4027 return BCM_E_PARAM; 4028 } 4029 4030 return _bcm_td3_large_nat_egress_add(unit, nat_info); 4031 } 4032 #endif /* BCM_TRIDENT3_SUPPORT */ 4033 return BCM_E_UNAVAIL; 4034 } 4035 4036 /* Function: 4037 * bcm_esw_l3_large_nat_delete 4038 * Description: 4039 * Delete the egress NAT entry from EVXLT table. 4040 * Parameters: 4041 * unit - (IN) Device number. 4042 * nat_info - (IN) key fields to be deleted. 4043 */ 4044 int 4045 bcm_esw_l3_large_nat_egress_delete( 4046 int unit, 4047 bcm_l3_large_nat_egress_t *nat_info) 4048 { 4049 #if defined(BCM_TRIDENT3_SUPPORT) 4050 soc_mem_t mem = EGR_VLAN_XLATE_2_DOUBLEm; 4051 uint32 entry[SOC_MAX_MEM_WORDS]; 4052 int nat_key; 4053 4054 if (soc_feature(unit, soc_feature_large_scale_nat)) { 4055 /* validate input */ 4056 if (NULL == nat_info) { 4057 return BCM_E_PARAM; 4058 } 4059 4060 /* validate nat class id */ 4061 if (nat_info->nat_class_id <= 0 || 4062 nat_info->nat_class_id > 0xffff) { 4063 return BCM_E_PARAM; 4064 } 4065 4066 /* validate l3 interface class id if supplied */ 4067 if (nat_info->intf_class_id < 0 || 4068 nat_info->intf_class_id > 0xfff) { 4069 return BCM_E_PARAM; 4070 } 4071 /* validate replication id if supplied */ 4072 if (nat_info->replication_id < 0 || 4073 nat_info->replication_id > 0xffff) { 4074 return BCM_E_PARAM; 4075 } 4076 4077 sal_memset(entry, 0, sizeof(entry)); 4078 4079 BCM_IF_ERROR_RETURN( 4080 _bcm_td3_large_nat_egress_key_set(unit, 4081 mem, nat_info, &nat_key, entry)); 4082 4083 BCM_IF_ERROR_RETURN(soc_mem_delete(unit, 4084 mem, MEM_BLOCK_ANY, entry)); 4085 4086 return BCM_E_NONE; 4087 } 4088 #endif /* BCM_TRIDENT3_SUPPORT */ 4089 4090 return BCM_E_UNAVAIL; 4091 } 4092 4093 /* Function: 4094 * bcm_esw_l3_large_nat_egress_get 4095 * Description: 4096 * Retrieve the egress NAT packet edit entry at the specified index 4097 * Parameters: 4098 * unit - (IN) Device number. 4099 * nat_id - IN Index of entry to get. 4100 */ 4101 int bcm_esw_l3_large_nat_egress_get( 4102 int unit, 4103 bcm_l3_large_nat_egress_t *nat_info) 4104 { 4105 #if defined(BCM_TRIDENT3_SUPPORT) 4106 soc_mem_t mem = EGR_VLAN_XLATE_2_DOUBLEm; 4107 uint32 entry[SOC_MAX_MEM_WORDS]; 4108 int nat_key; 4109 4110 if (soc_feature(unit, soc_feature_large_scale_nat)) { 4111 /* validate input */ 4112 if (NULL == nat_info) { 4113 return BCM_E_PARAM; 4114 } 4115 4116 /* validate nat class id */ 4117 if (nat_info->nat_class_id <= 0 || 4118 nat_info->nat_class_id > 0xffff) { 4119 return BCM_E_PARAM; 4120 } 4121 4122 /* validate l3 interface class id if supplied */ 4123 if (nat_info->intf_class_id < 0 || 4124 nat_info->intf_class_id > 0xfff) { 4125 return BCM_E_PARAM; 4126 } 4127 4128 /* validate replication id if supplied */ 4129 if (nat_info->replication_id < 0 || 4130 nat_info->replication_id > 0xffff) { 4131 return BCM_E_PARAM; 4132 } 4133 4134 sal_memset(entry, 0, sizeof(entry)); 4135 4136 BCM_IF_ERROR_RETURN( 4137 _bcm_td3_large_nat_egress_key_set(unit, 4138 mem, nat_info, &nat_key, entry)); 4139 4140 BCM_IF_ERROR_RETURN( 4141 _bcm_td3_large_nat_egress_entry_get(unit, 4142 mem, entry, nat_key, nat_info)); 4143 4144 return BCM_E_NONE; 4145 } 4146 #endif /* BCM_TRIDENT3_SUPPORT */ 4147 return BCM_E_UNAVAIL; 4148 } 4149 4150 /* Function: 4151 * bcm_esw_l3_large_nat_egress_traverse 4152 * 4153 * Description: 4154 * Traverse all valid NAT entries in the egress translate table 4155 * and call the supplied callback routine for each. 4156 * 4157 * Parameters: 4158 * unit - (IN) Device number. 4159 * cb - (IN) User call-back function 4160 */ 4161 int bcm_esw_l3_large_nat_egress_traverse( 4162 int unit, 4163 bcm_l3_large_nat_egress_traverse_cb cb, 4164 void *user_data) 4165 { 4166 #if defined(BCM_TRIDENT3_SUPPORT) 4167 if (soc_feature(unit, soc_feature_large_scale_nat)) { 4168 /* validate input */ 4169 if (NULL == cb) { 4170 return BCM_E_NONE; 4171 } 4172 4173 return _bcm_td3_large_nat_egress_traverse(unit, 4174 EGR_VLAN_XLATE_2_DOUBLEm, cb, user_data); 4175 } 4176 #endif /* BCM_TRIDENT3_SUPPORT */ 4177 return BCM_E_UNAVAIL; 4178 } 4179 4180 4181 #if 0 4182 #if defined(BCM_TRIDENT2_SUPPORT) 4183 int 4184 _bcm_td2_l3_nat_ingress_key_match(int unit, soc_mem_t mem, void *hw_buf) 4185 { 4186 if (mem == ING_DNAT_ADDRESS_TYPEm) { 4187 return 1; 4188 } 4189 if (mem == L3_ENTRY_IPV4_MULTICASTm) { 4190 return ((soc_mem_field32_get(unit, mem, hw_buf, KEY_TYPEf) == 4191 TD2_L3_HASH_KEY_TYPE_DST_NAT) || 4192 (soc_mem_field32_get(unit, mem, hw_buf, KEY_TYPEf) == 4193 TD2_L3_HASH_KEY_TYPE_DST_NAPT)); 4194 } 4195 return 0; 4196 } 4197 int 4198 _bcm_td2_l3_nat_ingress_conflict_get(int unit, bcm_l3_nat_ingress_t *nat_info, 4199 bcm_l3_nat_ingress_t *cf_array, int cf_max, 4200 int *cf_count) 4201 { 4202 uint32 valid, *bufp; /* Hardware buffer ptr */ 4203 soc_mem_t mem = L3_ENTRY_IPV4_MULTICASTm; 4204 int index, rv = BCM_E_NONE; /* Operation status. */ 4205 uint32 hw_buf[SOC_MAX_MEM_WORDS]; 4206 uint8 i, bidx, num_ent, shared_l3_banks, start_bidx, end_bidx; 4207 l3_entry_ipv4_multicast_entry_t l3v4_ext_entry; 4208 ing_dnat_address_type_entry_t dnat_pool; 4209 4210 4211 4212 /* Input parameters check. */ 4213 if ((NULL == nat_info) || (NULL == cf_count) || 4214 (NULL == cf_array) || (cf_max <= 0)) { 4215 return (BCM_E_PARAM); 4216 } 4217 4218 if (nat_info->flags & BCM_L3_NAT_INGRESS_DNAT) { 4219 if (nat_info->flags & BCM_L3_NAT_INGRESS_DNAT_POOL) { 4220 mem = ING_DNAT_ADDRESS_TYPEm; 4221 /* Set the valid field */ 4222 valid = VALIDf; 4223 start_bidx = 0; 4224 end_bidx = 1; 4225 bufp = (void *) &dnat_pool; 4226 } else { 4227 mem = L3_ENTRY_IPV4_MULTICASTm; 4228 /* Set the valid field */ 4229 valid = VALID_0f; 4230 /* get number of shared L3 banks */ 4231 shared_l3_banks = (soc_mem_index_count(unit, L3_ENTRY_ONLYm) - 4232 16 * 1024) / (64 * 1024); 4233 if (shared_l3_banks > 3) { 4234 return BCM_E_NOT_FOUND; 4235 } 4236 start_bidx = (6 - shared_l3_banks); 4237 end_bidx = 9; 4238 bufp = (void *) &l3v4_ext_entry; 4239 } 4240 } else { 4241 /* Not support for SNAT table */ 4242 return BCM_E_PARAM; 4243 } 4244 4245 /* Translate lookup key to hw format. */ 4246 BCM_IF_ERROR_RETURN(_bcm_td2_l3_nat_ingress_sw_to_hw(unit, mem, bufp, 4247 nat_info)); 4248 4249 4250 #if 0 4251 /* Set table fields */ 4252 BCM_TD2_L3_HOST_TABLE_FLD(unit, mem, ipv6, fld); 4253 4254 /* Assign entry buf based on table being used */ 4255 BCM_TD2_L3_HOST_ENTRY_BUF(ipv6, mem, bufp, 4256 l3v4_entry, 4257 l3v4_ext_entry, 4258 l3v6_entry, 4259 l3v6_ext_entry); 4260 /* Prepare host entry for addition. */ 4261 BCM_IF_ERROR_RETURN(_bcm_td2_l3_ent_init(unit, mem, &l3cfg, bufp)); 4262 #endif 4263 4264 4265 *cf_count = 0; 4266 4267 #if 0 4268 /* get number of shared L3 banks */ 4269 shared_l3_banks = (soc_mem_index_count(unit, L3_ENTRY_ONLYm) - 16 * 1024) / 4270 (64 * 1024); 4271 4272 if (shared_l3_banks > 3) { 4273 return BCM_E_NOT_FOUND; 4274 } 4275 #endif 4276 4277 /* bank 9 to 6 are dedicated L3 banks, 5 to 3 are dedicated, depends on 4278 * mode how many shared banks are assigned to l3 4279 */ 4280 for (bidx = start_bidx; bidx <= end_bidx; bidx++) { 4281 4282 num_ent = 4; /* 4 entries per bucket */ 4283 4284 BCM_TD2_NAT_INGRESS_BANK_ENTRY_HASH(mem, unit, bidx, bufp, index); 4285 if (index == 0) { 4286 return BCM_E_INTERNAL; 4287 } 4288 4289 for (i = 0; (i < num_ent) && (*cf_count < cf_max); i++) { 4290 rv = soc_mem_read(unit, mem, COPYNO_ALL, index + i, hw_buf); 4291 if (SOC_FAILURE(rv)) { 4292 return BCM_E_MEMORY; 4293 } 4294 if (soc_mem_field32_get(unit, mem, hw_buf, valid) && 4295 _bcm_td2_l3_nat_ingress_key_match(unit, mem, hw_buf)) { 4296 rv = _bcm_td2_l3_nat_ingress_hw_to_sw(unit, mem, hw_buf, 4297 cf_array + (*cf_count)); 4298 BCM_IF_ERROR_RETURN(rv); 4299 if ((++(*cf_count)) >= cf_max) { 4300 break; 4301 } 4302 } 4303 } 4304 } 4305 return BCM_E_NONE; 4306 } 4307 #endif /* BCM_TRIDENT2_SUPPORT */ 4308 4309 /* 4310 * Function: 4311 * bcm_esw_l3_nat_ingress_conflict_get 4312 * 4313 * Description: 4314 * Given a DNAT or DNAT pool table key, return conflicts in the corresponding 4315 * table. 4316 * 4317 * Parameters: 4318 * unit - (IN) bcm device 4319 * nat_info - (IN) Destination NAT/NAPT lookup key 4320 * cf_array - (OUT) array of conflicting addresses (at most 4) 4321 * cf_max - (IN) max number of conflicts to return. 4322 * cf_count - (OUT) actual number of conflicting entries. 4323 * Returns: 4324 * BCM_E_XXX 4325 */ 4326 int 4327 bcm_esw_l3_nat_ingress_conflict_get(int unit, bcm_l3_nat_ingress_t *nat_info, 4328 bcm_l3_nat_ingress_t *cf_array, int cf_max, 4329 int *cf_count) 4330 { 4331 int rv = BCM_E_UNAVAIL; 4332 4333 #if defined(BCM_TRIDENT2_SUPPORT) 4334 if (soc_feature(unit, soc_feature_nat)) { 4335 return _bcm_td2_l3_nat_ingress_conflict_get(unit, nat_info, cf_array, 4336 cf_max, cf_count); 4337 } 4338 #endif /* BCM_TRIDENT2_SUPPORT */ 4339 4340 return rv; 4341 } 4342 #endif /* 0 */ 4343 4344 #endif /* INCLUDE_L3 */