extender.c (18041B)
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 * File: extender.c 8 * Purpose: Implements bcm_extender_forward_* APIs for Greyhound. 9 */ 10 11 #include <soc/defs.h> 12 #include <sal/core/libc.h> 13 14 #if defined(BCM_GREYHOUND_SUPPORT) && defined(INCLUDE_L3) 15 16 #include <soc/mem.h> 17 #include <soc/ism_hash.h> 18 19 #include <bcm/error.h> 20 21 #include <bcm_int/esw_dispatch.h> 22 #include <bcm_int/esw/l2.h> 23 #include <bcm_int/common/multicast.h> 24 #include <bcm_int/esw/greyhound.h> 25 26 /* 27 * Purpose: 28 * Add a downstream forwarding entry 29 * Parameters: 30 * unit - (IN) Device Number 31 * forward_entry - (IN) Forwarding entry 32 */ 33 int 34 bcm_gh_extender_forward_add(int unit, bcm_extender_forward_t *forward_entry) 35 { 36 int rv = BCM_E_NONE; 37 bcm_module_t mod_out; 38 bcm_port_t port_out; 39 bcm_trunk_t tgid_out; 40 int id_out; 41 l2x_entry_t l2x_entry; 42 int lower_th, higher_th; 43 44 if (forward_entry->name_space > 0xfff) { 45 return BCM_E_PARAM; 46 } 47 48 if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) { 49 if (forward_entry->extended_port_vid > 0x3fff) { 50 return BCM_E_PARAM; 51 } 52 53 BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, 54 forward_entry->dest_port, 55 &mod_out, &port_out, &tgid_out, &id_out)); 56 if (-1 != id_out) { 57 return BCM_E_PARAM; 58 } 59 60 sal_memset(&l2x_entry, 0, sizeof(l2x_entry)); 61 soc_L2Xm_field32_set(unit, &l2x_entry, VALIDf, 1); 62 soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf, 63 GH_L2_HASH_KEY_TYPE_PE_VID); /* PE_VID */ 64 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf, 65 forward_entry->name_space); 66 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf, 67 forward_entry->extended_port_vid); 68 if (-1 != tgid_out) { 69 BCM_IF_ERROR_RETURN(_bcm_trunk_id_validate(unit, tgid_out)); 70 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__DEST_TYPEf, 1); 71 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__TGIDf, tgid_out); 72 } else { 73 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__MODULE_IDf, mod_out); 74 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__PORT_NUMf, port_out); 75 } 76 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__STATIC_BITf, 1); 77 78 } else { /* Multicast forward entry */ 79 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 80 bcmSwitchExtenderMulticastLowerThreshold, &lower_th)); 81 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 82 bcmSwitchExtenderMulticastHigherThreshold, &higher_th)); 83 if ((forward_entry->extended_port_vid < lower_th) || 84 (forward_entry->extended_port_vid > higher_th)) { 85 return BCM_E_PARAM; 86 } 87 if (!_BCM_MULTICAST_IS_L2(forward_entry->dest_multicast)) { 88 return BCM_E_PARAM; 89 } 90 91 sal_memset(&l2x_entry, 0, sizeof(l2x_entry)); 92 soc_L2Xm_field32_set(unit, &l2x_entry, VALIDf, 1); 93 soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf, 94 GH_L2_HASH_KEY_TYPE_PE_VID); /* PE_VID */ 95 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf, 96 forward_entry->name_space); 97 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf, 98 forward_entry->extended_port_vid); 99 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__L2MC_PTRf, 100 _BCM_MULTICAST_ID_GET(forward_entry->dest_multicast)); 101 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__STATIC_BITf, 1); 102 } 103 104 if (forward_entry->flags & BCM_EXTENDER_FORWARD_COPY_TO_CPU) { 105 if (SOC_MEM_FIELD_VALID(unit, L2Xm, PE_VID__CPUf)) { 106 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__CPUf, 1); 107 } 108 } 109 110 soc_mem_lock(unit, L2Xm); 111 112 if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_REPLACE)) { 113 l2x_entry_t l2x_lookup; 114 int l2_index; 115 116 /* See if the entry already exists */ 117 rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry, 118 &l2x_lookup, &l2_index); 119 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 120 soc_mem_unlock(unit, L2Xm); 121 return rv; 122 } 123 if (BCM_SUCCESS(rv)) { 124 soc_mem_unlock(unit, L2Xm); 125 return BCM_E_EXISTS; 126 } 127 128 rv = soc_mem_insert(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry); 129 if (SOC_FAILURE(rv)) { 130 soc_mem_unlock(unit, L2Xm); 131 return rv; 132 } 133 } else { /* Replace existing entry */ 134 rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry); 135 if (SOC_FAILURE(rv)) { 136 soc_mem_unlock(unit, L2Xm); 137 return rv; 138 } 139 rv = soc_mem_insert(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry); 140 if (SOC_FAILURE(rv)) { 141 soc_mem_unlock(unit, L2Xm); 142 return rv; 143 } 144 } 145 146 soc_mem_unlock(unit, L2Xm); 147 148 return rv; 149 } 150 151 /* 152 * Purpose: 153 * Delete a downstream forwarding entry 154 * Parameters: 155 * unit - (IN) Device Number 156 * forward_entry - (IN) Forwarding entry 157 */ 158 int 159 bcm_gh_extender_forward_delete(int unit, bcm_extender_forward_t *forward_entry) 160 { 161 int rv = BCM_E_NONE; 162 l2x_entry_t l2x_entry; 163 int lower_th, higher_th; 164 165 if (forward_entry->name_space > 0xfff) { 166 return BCM_E_PARAM; 167 } 168 if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) { 169 if (forward_entry->extended_port_vid > 0x3fff) { 170 return BCM_E_PARAM; 171 } 172 } else { /* Multicast forward entry */ 173 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 174 bcmSwitchExtenderMulticastLowerThreshold, &lower_th)); 175 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 176 bcmSwitchExtenderMulticastHigherThreshold, &higher_th)); 177 if ((forward_entry->extended_port_vid < lower_th) || 178 (forward_entry->extended_port_vid > higher_th)) { 179 return BCM_E_PARAM; 180 } 181 } 182 183 sal_memset(&l2x_entry, 0, sizeof(l2x_entry)); 184 soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf, 185 GH_L2_HASH_KEY_TYPE_PE_VID); /* PE_VID */ 186 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf, 187 forward_entry->name_space); 188 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf, 189 forward_entry->extended_port_vid); 190 soc_mem_lock(unit, L2Xm); 191 rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, &l2x_entry); 192 soc_mem_unlock(unit, L2Xm); 193 194 return rv; 195 } 196 197 int 198 _bcm_gh_extender_forward_delete_all(int unit, bcm_extender_forward_t *forward_entry, void *data) 199 { 200 BCM_IF_ERROR_RETURN(bcm_gh_extender_forward_delete(unit, forward_entry)); 201 202 return BCM_E_NONE; 203 } 204 205 /* 206 * Purpose: 207 * Delete all downstream forwarding entries 208 * Parameters: 209 * unit - Device Number 210 */ 211 int 212 bcm_gh_extender_forward_delete_all(int unit) 213 { 214 int rv = BCM_E_NONE; 215 #if 1 /* TBD */ 216 BCM_IF_ERROR_RETURN(bcm_gh_extender_forward_traverse(unit, 217 _bcm_gh_extender_forward_delete_all, NULL)); 218 219 #else 220 l2_bulk_match_mask_entry_t match_mask; 221 l2_bulk_match_data_entry_t match_data; 222 int field_len; 223 224 sal_memset(&match_mask, 0, sizeof(match_mask)); 225 sal_memset(&match_data, 0, sizeof(match_data)); 226 227 soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask, VALIDf, 1); 228 soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data, VALIDf, 1); 229 230 field_len = soc_mem_field_length(unit, L2_BULK_MATCH_MASKm, KEY_TYPEf); 231 soc_mem_field32_set(unit, L2_BULK_MATCH_MASKm, &match_mask, KEY_TYPEf, 232 (1 << field_len) - 1); 233 soc_mem_field32_set(unit, L2_BULK_MATCH_DATAm, &match_data, KEY_TYPEf, 234 TR_L2_HASH_KEY_TYPE_PE_VID); 235 236 soc_mem_lock(unit, L2Xm); 237 rv = WRITE_L2_BULK_MATCH_MASKm(unit, MEM_BLOCK_ALL, 0, 238 &match_mask); 239 if (BCM_SUCCESS(rv)) { 240 rv = WRITE_L2_BULK_MATCH_DATAm(unit, MEM_BLOCK_ALL, 0, 241 &match_data); 242 } 243 if (BCM_SUCCESS(rv)) { 244 rv = soc_reg_field32_modify(unit, L2_BULK_CONTROLr, REG_PORT_ANY, 245 ACTIONf, 1); 246 } 247 if (BCM_SUCCESS(rv)) { 248 rv = soc_l2x_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 249 } 250 soc_mem_unlock(unit, L2Xm); 251 #endif 252 return rv; 253 } 254 255 /* 256 * Purpose: 257 * Get a downstream forwarding entry 258 * Parameters: 259 * unit - (IN) Device Number 260 * forward_entry - (IN/OUT) Forwarding entry 261 */ 262 int 263 bcm_gh_extender_forward_get(int unit, bcm_extender_forward_t *forward_entry) 264 { 265 int rv = BCM_E_NONE; 266 l2x_entry_t l2x_entry, l2x_entry_out; 267 int idx; 268 _bcm_gport_dest_t dest; 269 int l2mc_index; 270 int lower_th, higher_th; 271 272 if (forward_entry->name_space > 0xfff) { 273 return BCM_E_PARAM; 274 } 275 if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) { 276 if (forward_entry->extended_port_vid > 0x3fff) { 277 return BCM_E_PARAM; 278 } 279 } else { /* Multicast forward entry */ 280 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 281 bcmSwitchExtenderMulticastLowerThreshold, &lower_th)); 282 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 283 bcmSwitchExtenderMulticastHigherThreshold, &higher_th)); 284 if ((forward_entry->extended_port_vid < lower_th) || 285 (forward_entry->extended_port_vid > higher_th)) { 286 return BCM_E_PARAM; 287 } 288 } 289 290 sal_memset(&l2x_entry, 0, sizeof(l2x_entry)); 291 soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf, 292 GH_L2_HASH_KEY_TYPE_PE_VID); /* PE_VID */ 293 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__NAMESPACEf, 294 forward_entry->name_space); 295 soc_L2Xm_field32_set(unit, &l2x_entry, PE_VID__ETAG_VIDf, 296 forward_entry->extended_port_vid); 297 soc_mem_lock(unit, L2Xm); 298 rv = soc_mem_search(unit, L2Xm, MEM_BLOCK_ALL, &idx, &l2x_entry, 299 &l2x_entry_out, 0); 300 soc_mem_unlock(unit, L2Xm); 301 302 if (SOC_SUCCESS(rv)) { 303 if (!(forward_entry->flags & BCM_EXTENDER_FORWARD_MULTICAST)) { 304 if (soc_L2Xm_field32_get(unit, &l2x_entry_out, 305 PE_VID__DEST_TYPEf)) { 306 dest.tgid = soc_L2Xm_field32_get(unit, &l2x_entry_out, 307 PE_VID__TGIDf); 308 dest.gport_type = _SHR_GPORT_TYPE_TRUNK; 309 } else { 310 dest.modid = soc_L2Xm_field32_get(unit, &l2x_entry_out, 311 PE_VID__MODULE_IDf); 312 dest.port = soc_L2Xm_field32_get(unit, &l2x_entry_out, 313 PE_VID__PORT_NUMf); 314 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 315 } 316 BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest, 317 &(forward_entry->dest_port))); 318 } else { 319 l2mc_index = soc_L2Xm_field32_get(unit, &l2x_entry_out, 320 PE_VID__L2MC_PTRf); 321 _BCM_MULTICAST_GROUP_SET(forward_entry->dest_multicast, 322 _BCM_MULTICAST_TYPE_L2, l2mc_index); 323 } 324 } 325 326 return rv; 327 } 328 329 /* 330 * Purpose: 331 * Traverse all valid downstream forwarding entries and call the 332 * supplied callback routine. 333 * Parameters: 334 * unit - Device Number 335 * cb - User callback function, called once per forwarding entry. 336 * user_data - cookie 337 * Returns: 338 * BCM_E_XXX 339 */ 340 int 341 bcm_gh_extender_forward_traverse(int unit, 342 bcm_extender_forward_traverse_cb cb, 343 void *user_data) 344 { 345 int rv = BCM_E_NONE; 346 int chunk_entries, chunk_bytes; 347 uint8 *l2_tbl_chunk = NULL; 348 int chunk_idx_min, chunk_idx_max; 349 int ent_idx; 350 l2x_entry_t *l2x_entry; 351 bcm_extender_forward_t forward_entry; 352 int l2mc_index; 353 _bcm_gport_dest_t dest; 354 int lower_th, higher_th; 355 356 /* Get ETAG VID multicast range */ 357 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 358 bcmSwitchExtenderMulticastLowerThreshold, &lower_th)); 359 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 360 bcmSwitchExtenderMulticastHigherThreshold, &higher_th)); 361 362 chunk_entries = soc_property_get(unit, spn_L2DELETE_CHUNKS, 363 L2_MEM_CHUNKS_DEFAULT); 364 chunk_bytes = 4 * SOC_MEM_WORDS(unit, L2Xm) * chunk_entries; 365 l2_tbl_chunk = soc_cm_salloc(unit, chunk_bytes, "extender forward traverse"); 366 if (NULL == l2_tbl_chunk) { 367 return BCM_E_MEMORY; 368 } 369 for (chunk_idx_min = soc_mem_index_min(unit, L2Xm); 370 chunk_idx_min <= soc_mem_index_max(unit, L2Xm); 371 chunk_idx_min += chunk_entries) { 372 373 /* Read a chunk of L2 table */ 374 sal_memset(l2_tbl_chunk, 0, chunk_bytes); 375 chunk_idx_max = chunk_idx_min + chunk_entries - 1; 376 if (chunk_idx_max > soc_mem_index_max(unit, L2Xm)) { 377 chunk_idx_max = soc_mem_index_max(unit, L2Xm); 378 } 379 rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY, 380 chunk_idx_min, chunk_idx_max, l2_tbl_chunk); 381 if (SOC_FAILURE(rv)) { 382 break; 383 } 384 for (ent_idx = 0; 385 ent_idx <= (chunk_idx_max - chunk_idx_min); 386 ent_idx++) { 387 l2x_entry = soc_mem_table_idx_to_pointer(unit, L2Xm, l2x_entry_t *, 388 l2_tbl_chunk, ent_idx); 389 if (soc_L2Xm_field32_get(unit, l2x_entry, VALIDf) == 0) { 390 continue; 391 } 392 if (soc_L2Xm_field32_get(unit, l2x_entry, KEY_TYPEf) != 393 GH_L2_HASH_KEY_TYPE_PE_VID) { 394 continue; 395 } 396 397 /* Get fields of forwarding entry */ 398 bcm_extender_forward_t_init(&forward_entry); 399 forward_entry.name_space = soc_L2Xm_field32_get(unit, l2x_entry, 400 PE_VID__NAMESPACEf); 401 forward_entry.extended_port_vid = soc_L2Xm_field32_get(unit, 402 l2x_entry, PE_VID__ETAG_VIDf); 403 if ((forward_entry.extended_port_vid >= lower_th) && 404 (forward_entry.extended_port_vid <= higher_th)) { 405 /* Multicast forward entry */ 406 forward_entry.flags |= BCM_EXTENDER_FORWARD_MULTICAST; 407 l2mc_index = soc_L2Xm_field32_get(unit, l2x_entry, 408 PE_VID__L2MC_PTRf); 409 _BCM_MULTICAST_GROUP_SET(forward_entry.dest_multicast, 410 _BCM_MULTICAST_TYPE_L2, l2mc_index); 411 } else { 412 if (soc_L2Xm_field32_get(unit, l2x_entry, 413 PE_VID__DEST_TYPEf)) { 414 dest.tgid = soc_L2Xm_field32_get(unit, l2x_entry, 415 PE_VID__TGIDf); 416 dest.gport_type = _SHR_GPORT_TYPE_TRUNK; 417 } else { 418 dest.modid = soc_L2Xm_field32_get(unit, l2x_entry, 419 PE_VID__MODULE_IDf); 420 dest.port = soc_L2Xm_field32_get(unit, l2x_entry, 421 PE_VID__PORT_NUMf); 422 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 423 } 424 rv = _bcm_esw_gport_construct(unit, &dest, 425 &(forward_entry.dest_port)); 426 if (BCM_FAILURE(rv)) { 427 break; 428 } 429 } 430 431 if (SOC_MEM_FIELD_VALID(unit, L2Xm, PE_VID__CPUf)) { 432 if (soc_L2Xm_field32_get(unit, l2x_entry, PE_VID__CPUf)) { 433 forward_entry.flags |= BCM_EXTENDER_FORWARD_COPY_TO_CPU; 434 } 435 } 436 437 rv = cb(unit, &forward_entry, user_data); 438 if (BCM_FAILURE(rv)) { 439 break; 440 } 441 } 442 if (BCM_FAILURE(rv)) { 443 break; 444 } 445 } 446 soc_cm_sfree(unit, l2_tbl_chunk); 447 448 return rv; 449 } 450 451 452 /* 453 * Function: 454 * bcm_gh_etag_ethertype_set 455 * Purpose: 456 * Set ETAG Ethertype. 457 * Parameters: 458 * unit - (IN) BCM device number 459 * ethertype - (IN) Ethertype 460 * Returns: 461 * BCM_E_XXX 462 */ 463 int 464 bcm_gh_etag_ethertype_set(int unit, int ethertype) 465 { 466 467 if (ethertype < 0 || ethertype > 0xffff) { 468 return BCM_E_PARAM; 469 } 470 471 BCM_IF_ERROR_RETURN 472 (soc_reg_field32_modify(unit, PE_ETHERTYPEr, 473 REG_PORT_ANY, ETHERTYPEf, ethertype)); 474 BCM_IF_ERROR_RETURN 475 (soc_reg_field32_modify(unit, PE_ETHERTYPEr, 476 REG_PORT_ANY, ENABLEf, ethertype ? 1 : 0)); 477 478 BCM_IF_ERROR_RETURN 479 (soc_reg_field32_modify(unit, EGR_PE_ETHERTYPEr, 480 REG_PORT_ANY, ETHERTYPEf, ethertype)); 481 BCM_IF_ERROR_RETURN 482 (soc_reg_field32_modify(unit, EGR_PE_ETHERTYPEr, 483 REG_PORT_ANY, ENABLEf, ethertype ? 1 : 0)); 484 485 BCM_IF_ERROR_RETURN 486 (soc_reg_field32_modify(unit, EGR_PE_ETHERTYPE_2r, 487 REG_PORT_ANY, ETHERTYPEf, ethertype)); 488 BCM_IF_ERROR_RETURN 489 (soc_reg_field32_modify(unit, EGR_PE_ETHERTYPE_2r, 490 REG_PORT_ANY, ENABLEf, ethertype ? 1 : 0)); 491 492 return BCM_E_NONE; 493 } 494 495 /* 496 * Function: 497 * bcm_gh_etag_ethertype_get 498 * Purpose: 499 * Get ETAG Ethertype. 500 * Parameters: 501 * unit - (IN) BCM device number 502 * ethertype - (OUT) Ethertype 503 * Returns: 504 * BCM_E_XXX 505 */ 506 int 507 bcm_gh_etag_ethertype_get(int unit, int *ethertype) 508 { 509 uint32 rval; 510 511 if (ethertype == NULL) { 512 return BCM_E_PARAM; 513 } 514 515 BCM_IF_ERROR_RETURN(READ_PE_ETHERTYPEr(unit, &rval)); 516 if (soc_reg_field_get(unit, PE_ETHERTYPEr, rval, ENABLEf)) { 517 *ethertype = soc_reg_field_get(unit, PE_ETHERTYPEr, rval, ETHERTYPEf); 518 } else { 519 *ethertype = 0; 520 } 521 522 return BCM_E_NONE; 523 } 524 525 #endif /* BCM_GREYHOUND_SUPPORT && INCLUDE_L3 */