mpls.c (27025B)
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: mpls.c 8 * Purpose: Manages Tomahawk3 MPLS functions 9 */ 10 #include <soc/defs.h> 11 #include <sal/core/libc.h> 12 #include <shared/bsl.h> 13 #if defined(BCM_TOMAHAWK3_SUPPORT) && defined(BCM_MPLS_SUPPORT) && \ 14 defined(INCLUDE_L3) 15 16 #include <soc/drv.h> 17 #include <soc/scache.h> 18 #include <soc/hash.h> 19 #include <soc/util.h> 20 #include <soc/triumph.h> 21 22 #include <bcm/error.h> 23 #include <bcm/mpls.h> 24 25 26 #include <bcm_int/esw/mbcm.h> 27 #include <bcm_int/esw/l3.h> 28 #include <bcm_int/esw/firebolt.h> 29 #include <bcm_int/esw/triumph.h> 30 #include <bcm_int/esw/trx.h> 31 #include <bcm_int/esw/xgs3.h> 32 #include <bcm_int/esw/mpls.h> 33 #include <bcm_int/esw/stack.h> 34 #include <bcm_int/common/multicast.h> 35 #include <bcm_int/esw/virtual.h> 36 #include <bcm_int/esw/port.h> 37 #if defined(BCM_TOMAHAWK_SUPPORT) 38 #include <bcm_int/esw/ecn.h> 39 #endif 40 #include <bcm_int/esw/vlan.h> 41 #ifdef BCM_TRIUMPH2_SUPPORT 42 #include <bcm_int/esw/triumph2.h> 43 #endif 44 #if defined(BCM_TRIUMPH3_SUPPORT) 45 #include <bcm_int/esw/triumph3.h> 46 #endif /* BCM_TRIUMPH3_SUPPORT*/ 47 #ifdef BCM_KATANA2_SUPPORT 48 #include <bcm_int/esw/katana2.h> 49 #include <soc/katana2.h> 50 #endif 51 #include <bcm_int/esw/xgs5.h> 52 #if defined(BCM_SABER2_SUPPORT) 53 #include <soc/saber2.h> 54 #endif /* BCM_SABER2_SUPPORT */ 55 56 #include <bcm_int/esw_dispatch.h> 57 #include <bcm_int/api_xlate_port.h> 58 #include <bcm_int/esw/failover.h> 59 60 extern uint32 nh_entry_type_field; 61 #ifdef BCM_WARM_BOOT_SUPPORT 62 #include <bcm_int/esw/switch.h> 63 #endif 64 #define ECN_MAP_ID_INVALID 0xffffffff 65 66 /* 67 * Function: 68 * bcm_th3_mpls_l3_nh_info_get 69 * Purpose: 70 * Get Tunnel_switch info for a specific EGR_NH Index 71 * Parameters: 72 * IN : Unit 73 * OUT : Tunnel switch object pointer 74 * IN : nh_index 75 * Returns: 76 * BCM_E_XXX 77 */ 78 79 int 80 bcm_th3_mpls_l3_nh_info_get(int unit, bcm_mpls_tunnel_switch_t *info, int nh_index) 81 { 82 egr_l3_next_hop_entry_t egr_nh; 83 int ix; 84 int ecn_map_index; 85 int ecn_map_pri; 86 info->egress_if = nh_index + BCM_XGS3_EGRESS_IDX_MIN(unit); 87 88 BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY, 89 nh_index, &egr_nh)); 90 91 if (soc_feature(unit, soc_feature_mpls_nh_ttl_control)) { 92 if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, 93 MPLS__DISABLE_TTL_DECREMENTf)) { 94 info->flags |= BCM_MPLS_SWITCH_KEEP_TTL; 95 } 96 } 97 98 if (_BCM_MPLS_ACTION_PRESERVED == soc_mem_field32_get(unit, 99 EGR_L3_NEXT_HOPm, &egr_nh, MPLS__MPLS_LABEL_ACTIONf)) { 100 info->egress_label.flags |= BCM_MPLS_EGRESS_LABEL_PRESERVE; 101 info->egress_label.label = BCM_MPLS_LABEL_INVALID; 102 } else { 103 info->egress_label.label = 104 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 105 &egr_nh, MPLS__MPLS_LABELf); 106 } 107 108 info->egress_label.ttl = 109 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 110 &egr_nh, MPLS__MPLS_TTLf); 111 if (info->egress_label.ttl) { 112 info->egress_label.flags |= BCM_MPLS_EGRESS_LABEL_TTL_SET; 113 } else { 114 info->egress_label.flags |= BCM_MPLS_EGRESS_LABEL_TTL_DECREMENT; 115 } 116 if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 117 &egr_nh, MPLS__MPLS_EXP_SELECTf) == 0x0) { 118 /* Use the specified EXP, PRI and CFI */ 119 info->egress_label.flags |= BCM_MPLS_EGRESS_LABEL_EXP_SET; 120 info->egress_label.flags |= BCM_MPLS_EGRESS_LABEL_PRI_SET; 121 info->egress_label.exp = 122 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 123 &egr_nh, MPLS__MPLS_EXPf); 124 info->egress_label.pkt_pri = 125 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 126 &egr_nh, MPLS__NEW_PRIf); 127 info->egress_label.pkt_cfi = 128 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 129 &egr_nh, MPLS__NEW_CFIf); 130 } else if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 131 &egr_nh, MPLS__MPLS_EXP_SELECTf) == 0x1) { 132 /* Use EXP-map for EXP, PRI and CFI */ 133 info->egress_label.flags |= BCM_MPLS_EGRESS_LABEL_EXP_REMARK; 134 info->egress_label.flags |= BCM_MPLS_EGRESS_LABEL_PRI_REMARK; 135 ix = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 136 &egr_nh, MPLS__MPLS_EXP_MAPPING_PTRf); 137 BCM_IF_ERROR_RETURN( 138 _egr_qos_hw_idx2id(unit, ix, &info->egress_label.qos_map_id)); 139 } else if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 140 &egr_nh, MPLS__MPLS_EXP_SELECTf) == 0x3) { 141 /* Use EXP from incoming MPLS label. If no incoming label, use the specified 142 * EXP value. Use EXP-map for PRI/CFI. 143 */ 144 info->egress_label.flags |= BCM_MPLS_EGRESS_LABEL_EXP_COPY; 145 info->egress_label.flags |= BCM_MPLS_EGRESS_LABEL_PRI_REMARK; 146 info->egress_label.exp = 147 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 148 &egr_nh, MPLS__MPLS_EXPf); 149 ix = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 150 &egr_nh, MPLS__MPLS_EXP_MAPPING_PTRf); 151 BCM_IF_ERROR_RETURN( 152 _egr_qos_hw_idx2id(unit, ix, &info->egress_label.qos_map_id)); 153 } 154 155 if (soc_feature(unit, soc_feature_mpls_ecn) && 156 soc_feature(unit, soc_feature_ecn_wred)) { 157 ecn_map_index = soc_mem_field32_get(unit, 158 EGR_L3_NEXT_HOPm, 159 &egr_nh, 160 MPLS__INT_CN_TO_EXP_MAPPING_PTRf); 161 if (bcmi_xgs5_ecn_map_used_get(unit, ecn_map_index, 162 _bcmEcnmapTypeIntcn2Exp)) { 163 info->egress_label.int_cn_map_id = 164 _BCM_XGS5_MPLS_ECN_MAP_TYPE_INTCN2EXP | ecn_map_index; 165 ecn_map_pri = soc_mem_field32_get(unit, 166 EGR_L3_NEXT_HOPm, 167 &egr_nh, 168 MPLS__INT_CN_TO_EXP_PRIORITYf); 169 if (ecn_map_pri) { 170 info->egress_label.flags |= 171 BCM_MPLS_EGRESS_LABEL_ECN_EXP_MAP_TRUST; 172 } 173 info->egress_label.flags |= 174 BCM_MPLS_EGRESS_LABEL_INT_CN_TO_EXP_MAP; 175 } 176 } 177 return BCM_E_NONE; 178 } 179 180 /* 181 * Function: 182 * _bcm_th3_mpls_egr_nh_label_set 183 * Purpose: 184 * Set EGR_NH entry 185 * Parameters: 186 * IN : Unit 187 * IN : egr_obj 188 * Returns: 189 * BCM_E_XXX 190 */ 191 int 192 _bcm_th3_mpls_egr_nh_label_set (int unit, 193 bcm_mpls_tunnel_switch_t *info, 194 bcm_l3_egress_t *egr_obj, 195 int label_action, 196 int hw_map_idx, 197 egr_l3_next_hop_entry_t *pegr_nh) 198 { 199 bcm_mpls_label_t mpls_label = BCM_MPLS_LABEL_INVALID; 200 uint8 mpls_ttl = 0; 201 uint32 mpls_flags = 0; 202 uint8 mpls_exp = 0; 203 uint8 mpls_pkt_pri = 0; 204 uint8 mpls_pkt_cfi = 0; 205 int mpls_ecn_map_id = ECN_MAP_ID_INVALID; 206 int mpls_int_cn_map_id = ECN_MAP_ID_INVALID; 207 208 if (info != NULL) { 209 mpls_label = info->egress_label.label; 210 mpls_ttl = info->egress_label.ttl; 211 mpls_flags = info->egress_label.flags; 212 mpls_pkt_pri = info->egress_label.pkt_pri; 213 mpls_pkt_cfi = info->egress_label.pkt_cfi; 214 mpls_exp = info->egress_label.exp; 215 if (soc_feature(unit, soc_feature_mpls_ecn) && 216 (mpls_flags & BCM_MPLS_EGRESS_LABEL_INT_CN_TO_EXP_MAP)) { 217 mpls_int_cn_map_id = info->egress_label.int_cn_map_id; 218 } 219 } else if (egr_obj != NULL) { 220 mpls_label = egr_obj->mpls_label; 221 mpls_ttl = egr_obj->mpls_ttl; 222 mpls_flags = egr_obj->mpls_flags; 223 mpls_pkt_pri = egr_obj->mpls_pkt_pri; 224 mpls_pkt_cfi = egr_obj->mpls_pkt_cfi; 225 mpls_exp = egr_obj->mpls_exp; 226 if (soc_feature(unit, soc_feature_mpls_ecn)) { 227 if (mpls_flags & BCM_MPLS_EGRESS_LABEL_INT_CN_TO_EXP_MAP) { 228 mpls_int_cn_map_id = egr_obj->mpls_ecn_map_id; 229 } 230 if (mpls_flags & BCM_MPLS_EGRESS_LABEL_ECN_TO_EXP_MAP) { 231 mpls_ecn_map_id = egr_obj->mpls_ecn_map_id; 232 } 233 } 234 } 235 236 if ((mpls_exp > 7) || (mpls_pkt_pri > 7) || 237 (mpls_pkt_cfi > 1)) { 238 return BCM_E_PARAM; 239 } 240 241 if (_BCM_MPLS_EGRESS_LABEL_PRESERVE(unit, mpls_flags)) { 242 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 243 pegr_nh, MPLS__MPLS_LABEL_ACTIONf, 244 _BCM_MPLS_ACTION_PRESERVED); 245 } else { 246 if (BCM_XGS3_L3_MPLS_LBL_VALID(mpls_label)) { 247 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 248 pegr_nh, MPLS__MPLS_LABELf, 249 mpls_label); 250 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 251 pegr_nh, MPLS__MPLS_LABEL_ACTIONf, 252 label_action); 253 254 } else { 255 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 256 pegr_nh, MPLS__MPLS_LABEL_ACTIONf, 257 _BCM_MPLS_ACTION_NOOP); 258 } 259 } 260 if (mpls_flags & BCM_MPLS_EGRESS_LABEL_TTL_SET) { 261 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 262 pegr_nh, MPLS__MPLS_TTLf, 263 mpls_ttl); 264 } else { 265 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 266 pegr_nh, MPLS__MPLS_TTLf, 0x0); 267 } 268 if ((mpls_flags & BCM_MPLS_EGRESS_LABEL_EXP_SET) || 269 (mpls_flags & BCM_MPLS_EGRESS_LABEL_PRI_SET)) { 270 271 if ((mpls_flags & BCM_MPLS_EGRESS_LABEL_EXP_REMARK) || 272 (mpls_flags & BCM_MPLS_EGRESS_LABEL_EXP_COPY) || 273 (mpls_flags & BCM_MPLS_EGRESS_LABEL_PRI_REMARK)) { 274 return BCM_E_PARAM; 275 } 276 /* Use the specified EXP, PRI and CFI */ 277 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 278 pegr_nh, MPLS__MPLS_EXP_SELECTf, 279 0x0); /* USE_FIXED */ 280 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 281 pegr_nh, MPLS__MPLS_EXPf, 282 mpls_exp); 283 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 284 pegr_nh, MPLS__NEW_PRIf, 285 mpls_pkt_pri); 286 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 287 pegr_nh, MPLS__NEW_CFIf, 288 mpls_pkt_cfi); 289 } else if (mpls_flags & BCM_MPLS_EGRESS_LABEL_EXP_REMARK) { 290 if (mpls_flags & BCM_MPLS_EGRESS_LABEL_PRI_SET) { 291 return BCM_E_PARAM; 292 } 293 /* Use EXP-map for EXP, PRI and CFI */ 294 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 295 pegr_nh, MPLS__MPLS_EXP_SELECTf, 296 0x1); /* USE_MAPPING */ 297 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 298 pegr_nh, MPLS__MPLS_EXP_MAPPING_PTRf, 299 hw_map_idx); 300 } else if ((label_action != _BCM_MPLS_ACTION_SWAP) && 301 (mpls_flags & BCM_MPLS_EGRESS_LABEL_EXP_COPY) ) { 302 /* Use EXP from incoming label. If there is no incoming label, 303 * use the specified EXP value. Use EXP-map for PRI/CFI. 304 */ 305 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 306 pegr_nh, MPLS__MPLS_EXP_SELECTf, 307 0x2); /* USE_INNER */ 308 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 309 pegr_nh, MPLS__MPLS_EXPf, 310 mpls_exp); 311 312 /* Use EXP-PRI-map for PRI/CFI */ 313 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 314 pegr_nh, MPLS__MPLS_EXP_MAPPING_PTRf, 315 hw_map_idx); 316 } else if ((label_action == _BCM_MPLS_ACTION_SWAP) && 317 (mpls_flags & BCM_MPLS_EGRESS_LABEL_EXP_COPY) ) { 318 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 319 pegr_nh, MPLS__MPLS_EXP_SELECTf, 320 0x3); /* USE_SWAP */ 321 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 322 pegr_nh, MPLS__MPLS_EXPf, mpls_exp); 323 /* Use EXP-PRI-map for PRI/CFI */ 324 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 325 pegr_nh, MPLS__MPLS_EXP_MAPPING_PTRf, 326 hw_map_idx); 327 } 328 if (soc_feature(unit, soc_feature_mpls_ecn)) { 329 if ((mpls_flags & BCM_MPLS_EGRESS_LABEL_INT_CN_TO_EXP_MAP) && 330 (mpls_int_cn_map_id != ECN_MAP_ID_INVALID)) { 331 int ecn_map_index; 332 int ecn_map_type; 333 int ecn_map_num; 334 int ecn_map_hw_idx; 335 ecn_map_type = mpls_int_cn_map_id & 336 _BCM_XGS5_MPLS_ECN_MAP_TYPE_MASK; 337 ecn_map_index = mpls_int_cn_map_id & 338 _BCM_XGS5_MPLS_ECN_MAP_NUM_MASK; 339 ecn_map_num = 340 soc_mem_index_count(unit, EGR_INT_CN_TO_EXP_MAPPING_TABLEm) / 341 _BCM_ECN_MAX_ENTRIES_PER_MAP; 342 if (ecn_map_type != _BCM_XGS5_MPLS_ECN_MAP_TYPE_INTCN2EXP) { 343 return BCM_E_PARAM; 344 } 345 if (ecn_map_index >= ecn_map_num) { 346 return BCM_E_PARAM; 347 } 348 BCM_IF_ERROR_RETURN( 349 bcmi_ecn_map_id2hw_idx(unit, mpls_int_cn_map_id, &ecn_map_hw_idx)); 350 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 351 pegr_nh, MPLS__INT_CN_TO_EXP_MAPPING_PTRf, 352 ecn_map_hw_idx); 353 if (mpls_flags & BCM_MPLS_EGRESS_LABEL_ECN_EXP_MAP_TRUST) { 354 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 355 pegr_nh, MPLS__INT_CN_TO_EXP_PRIORITYf, 1); 356 357 } else { 358 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 359 pegr_nh, MPLS__INT_CN_TO_EXP_PRIORITYf, 0); 360 } 361 } 362 if ((mpls_flags & BCM_MPLS_EGRESS_LABEL_ECN_TO_EXP_MAP) && 363 (mpls_ecn_map_id != ECN_MAP_ID_INVALID)) { 364 int ecn_map_index; 365 int ecn_map_type; 366 int ecn_map_num; 367 int ecn_map_hw_idx; 368 ecn_map_type = mpls_ecn_map_id & 369 _BCM_XGS5_MPLS_ECN_MAP_TYPE_MASK; 370 ecn_map_index = mpls_ecn_map_id & 371 _BCM_XGS5_MPLS_ECN_MAP_NUM_MASK; 372 ecn_map_num = 373 soc_mem_index_count(unit, EGR_IP_ECN_TO_EXP_MAPPING_TABLEm) / 374 _BCM_ECN_MAX_ENTRIES_PER_MAP; 375 if (ecn_map_type != _BCM_XGS5_MPLS_ECN_MAP_TYPE_ECN2EXP) { 376 return BCM_E_PARAM; 377 } 378 if (ecn_map_index >= ecn_map_num) { 379 return BCM_E_PARAM; 380 } 381 BCM_IF_ERROR_RETURN( 382 bcmi_ecn_map_id2hw_idx(unit, mpls_ecn_map_id, &ecn_map_hw_idx)); 383 384 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 385 pegr_nh, MPLS__IP_ECN_TO_EXP_MAPPING_PTRf, 386 ecn_map_hw_idx); 387 if (mpls_flags & BCM_MPLS_EGRESS_LABEL_ECN_EXP_MAP_TRUST) { 388 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 389 pegr_nh, MPLS__IP_ECN_TO_EXP_PRIORITYf, 1); 390 391 } else { 392 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 393 pegr_nh, MPLS__IP_ECN_TO_EXP_PRIORITYf, 0); 394 395 } 396 397 } 398 } 399 return BCM_E_NONE; 400 } 401 402 /* 403 * Function: 404 * bcm_th3_mpls_l3_label_add 405 * Purpose: 406 * Updates Inner_LABEL for a specific EGR_NH Index 407 * Parameters: 408 * IN : Unit 409 * IN : mpls_label 410 * IN : nh_index 411 * Returns: 412 * BCM_E_XXX 413 */ 414 415 int 416 bcm_th3_mpls_l3_label_add (int unit, bcm_l3_egress_t *egr, int nh_index, uint32 flags) 417 { 418 int rv=BCM_E_NONE; 419 egr_l3_next_hop_entry_t egr_nh; 420 uint32 entry_type; 421 int hw_map_idx, num_mpls_map; 422 423 /* Retrieve EGR L3 NHOP Entry */ 424 BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY, 425 nh_index, &egr_nh)); 426 427 BCM_IF_ERROR_RETURN(bcm_tr_mpls_get_entry_type(unit, nh_index, &entry_type)); 428 if ((entry_type == 1) && (egr->mpls_label != BCM_MPLS_LABEL_INVALID) && (flags & BCM_L3_REPLACE)) { 429 /* Be sure that the existing entry is already setup to 430 * egress into an MPLS tunnel. If not, return BCM_E_PARAM. 431 */ 432 entry_type = 433 soc_EGR_L3_NEXT_HOPm_field32_get(unit, &egr_nh, nh_entry_type_field); 434 435 if (entry_type != 0x1) { /* != MPLS_MACDA_PROFILE */ 436 return BCM_E_PARAM; 437 } 438 439 }else if ((entry_type == 1) && (egr->mpls_label == BCM_MPLS_LABEL_INVALID) && (flags & BCM_L3_REPLACE)) { 440 rv = bcm_tr_mpls_l3_label_delete (unit, nh_index); 441 return rv; 442 } 443 444 /* Retrieve hardware index for mapping pointer */ 445 if ((egr->mpls_flags & BCM_MPLS_EGRESS_LABEL_EXP_SET) || 446 (egr->mpls_flags & BCM_MPLS_EGRESS_LABEL_PRI_SET)) { 447 /* Mapping pointer not used */ 448 hw_map_idx = -1; 449 } else { 450 num_mpls_map = soc_mem_index_count(unit, EGR_MPLS_EXP_MAPPING_1m) / 64; 451 rv = _egr_qos_id2hw_idx(unit,egr->mpls_qos_map_id,&hw_map_idx); 452 if ((rv != BCM_E_NONE) || hw_map_idx < 0 || hw_map_idx >= num_mpls_map) { 453 if (egr->mpls_flags & BCM_MPLS_EGRESS_LABEL_EXP_REMARK) { 454 return rv = BCM_E_PARAM; 455 } else { 456 hw_map_idx = 0; /* use default */ 457 } 458 } 459 } 460 461 /* Program the EGR_L3_NEXT_HOP table entry */ 462 rv = _bcm_th3_mpls_egr_nh_label_set(unit, NULL, egr, 463 _BCM_MPLS_ACTION_PUSH, hw_map_idx, 464 &egr_nh); 465 if (rv < 0){ 466 return rv; 467 } 468 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, 469 &egr_nh, nh_entry_type_field, 470 entry_type); 471 472 if (soc_feature(unit, soc_feature_mpls_nh_ttl_control)) { 473 if (egr->flags & BCM_L3_KEEP_TTL) { 474 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 475 MPLS__DISABLE_TTL_DECREMENTf, 1); 476 } else { 477 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 478 MPLS__DISABLE_TTL_DECREMENTf, 0); 479 } 480 } 481 rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm, 482 MEM_BLOCK_ALL, nh_index, &egr_nh); 483 484 if (rv < 0) { 485 return rv; 486 } 487 #ifdef BCM_WARM_BOOT_SUPPORT 488 SOC_CONTROL_LOCK(unit); 489 SOC_CONTROL(unit)->scache_dirty = 1; 490 SOC_CONTROL_UNLOCK(unit); 491 #endif 492 493 return rv; 494 495 } 496 497 /* 498 * Function: 499 * bcm_th3_mpls_swap_nh_info_add 500 * Purpose: 501 * Add SWAP_LABEL for a specific EGR_NH Index 502 * Parameters: 503 * IN : Unit 504 * IN : Egress object Pointer 505 * IN : nh_index 506 * Returns: 507 * BCM_E_XXX 508 */ 509 510 int 511 bcm_th3_mpls_swap_nh_info_add (int unit, bcm_l3_egress_t *egr, int nh_index, uint32 flags) 512 { 513 int rv=BCM_E_NONE; 514 int hw_map_idx, num_mpls_map; 515 ing_l3_next_hop_entry_t ing_nh; 516 egr_l3_next_hop_entry_t egr_nh; 517 518 /* TH3 doesnt support EGR_MPLS_VC_AND_SWAP_LABEL_TABLEm*/ 519 520 sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t)); 521 522 BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 523 nh_index, &ing_nh)); 524 BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY, 525 nh_index, &egr_nh)); 526 527 /* Check for egr->flags & BCM_L3_REPLACE */ 528 if (flags & BCM_L3_REPLACE) { 529 if (!(egr->mpls_flags & BCM_MPLS_EGRESS_LABEL_TTL_SET)) { 530 egr->mpls_ttl = soc_mem_field32_get(unit, 531 EGR_L3_NEXT_HOPm, 532 &egr_nh, MPLS__MPLS_TTLf); 533 if (egr->mpls_ttl) { 534 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_TTL_SET; 535 } 536 } 537 } 538 /* Retrieve hardware index for mapping pointer */ 539 if ((egr->mpls_flags & BCM_MPLS_EGRESS_LABEL_EXP_SET) || 540 (egr->mpls_flags & BCM_MPLS_EGRESS_LABEL_PRI_SET)) { 541 /* Mapping pointer not used */ 542 hw_map_idx = -1; 543 } else { 544 num_mpls_map = soc_mem_index_count(unit, EGR_MPLS_EXP_MAPPING_1m) / 64; 545 rv = _egr_qos_id2hw_idx(unit,egr->mpls_qos_map_id,&hw_map_idx); 546 if ((rv != BCM_E_NONE) || hw_map_idx < 0 || hw_map_idx >= num_mpls_map) { 547 if (egr->mpls_flags & BCM_MPLS_EGRESS_LABEL_EXP_REMARK) { 548 return rv = BCM_E_PARAM; 549 } else { 550 hw_map_idx = 0; /* use default */ 551 } 552 } 553 } 554 rv = _bcm_th3_mpls_egr_nh_label_set(unit, NULL, 555 egr, _BCM_MPLS_EGRESS_LABEL_PRESERVE(unit, egr->mpls_flags) ? 556 _BCM_MPLS_ACTION_PRESERVED : _BCM_MPLS_ACTION_SWAP, 557 hw_map_idx, &egr_nh); 558 559 BCM_IF_ERROR_RETURN(rv); 560 561 /* Write EGR_L3_NEXT_HOP entry */ 562 rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm, 563 MEM_BLOCK_ALL, nh_index, &egr_nh); 564 BCM_IF_ERROR_RETURN(rv); 565 566 /* Write ING_L3_NEXT_HOP entry */ 567 568 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, 569 &ing_nh, ENTRY_TYPEf, 0x1); /* MPLS L3_OIF */ 570 rv = soc_mem_write (unit, ING_L3_NEXT_HOPm, 571 MEM_BLOCK_ALL, nh_index, &ing_nh); 572 return rv; 573 } 574 575 /* 576 * Function: 577 * bcm_th3_mpls_swap_nh_info_get 578 * Purpose: 579 * Get Label_Swap info within Egress Object for a specific EGR_NH Index 580 * Parameters: 581 * IN : Unit 582 * OUT : Egress object Pointer 583 * IN : nh_index 584 * Returns: 585 * BCM_E_XXX 586 */ 587 588 int 589 bcm_th3_mpls_swap_nh_info_get(int unit, bcm_l3_egress_t *egr, int nh_index) 590 { 591 egr_l3_next_hop_entry_t egr_nh; 592 int ix; 593 uint32 label_action = 0; 594 uint32 label_select = 0; 595 596 BCM_IF_ERROR_RETURN (soc_mem_read(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY, 597 nh_index, &egr_nh)); 598 599 label_action = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 600 &egr_nh, MPLS__MPLS_LABEL_ACTIONf); 601 602 if (label_action == _BCM_MPLS_ACTION_SWAP || 603 (soc_feature(unit, soc_feature_mpls_swap_label_preserve) && 604 ((label_action == _BCM_MPLS_ACTION_PRESERVED) || label_select))) { /* SWAP */ 605 606 if (soc_feature(unit, soc_feature_mpls_swap_label_preserve) && 607 ((label_action == _BCM_MPLS_ACTION_PRESERVED) || label_select)) { 608 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_PRESERVE; 609 egr->mpls_label = BCM_MPLS_LABEL_INVALID; 610 } else { 611 egr->mpls_label = 612 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 613 &egr_nh, MPLS__MPLS_LABELf); 614 } 615 egr->mpls_ttl = 616 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 617 &egr_nh,MPLS__MPLS_TTLf); 618 if (egr->mpls_ttl) { 619 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_TTL_SET; 620 } else { 621 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_TTL_DECREMENT; 622 } 623 if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 624 &egr_nh, MPLS__MPLS_EXP_SELECTf) == 0x0) { 625 /* Use the specified EXP, PRI and CFI */ 626 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_EXP_SET; 627 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_PRI_SET; 628 egr->mpls_exp = 629 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 630 &egr_nh, MPLS__MPLS_EXPf); 631 egr->mpls_pkt_pri = 632 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 633 &egr_nh, MPLS__NEW_PRIf); 634 egr->mpls_pkt_cfi = 635 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 636 &egr_nh, MPLS__NEW_CFIf); 637 } else if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 638 &egr_nh, MPLS__MPLS_EXP_SELECTf) == 0x1) { 639 /* Use EXP-map for EXP, PRI and CFI */ 640 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_EXP_REMARK; 641 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_PRI_REMARK; 642 ix = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 643 &egr_nh, MPLS__MPLS_EXP_MAPPING_PTRf); 644 BCM_IF_ERROR_RETURN( 645 _egr_qos_hw_idx2id(unit, ix, &egr->mpls_qos_map_id)); 646 } else if (soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 647 &egr_nh, MPLS__MPLS_EXP_SELECTf) == 0x3) { 648 /* Use EXP from incoming MPLS label. If no incoming label, use the specified 649 * EXP value. Use EXP-map for PRI/CFI. 650 */ 651 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_EXP_COPY; 652 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_PRI_REMARK; 653 egr->mpls_exp = 654 soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 655 &egr_nh, MPLS__MPLS_EXPf); 656 ix = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 657 &egr_nh, MPLS__MPLS_EXP_MAPPING_PTRf); 658 BCM_IF_ERROR_RETURN( 659 _egr_qos_hw_idx2id(unit, ix, &egr->mpls_qos_map_id)); 660 } 661 if (soc_feature(unit, soc_feature_mpls_ecn)) { 662 int ecn_map_id; 663 int ecn_map_pri; 664 int ecn_map_hw_idx; 665 int rv; 666 ecn_map_hw_idx = soc_mem_field32_get(unit, 667 EGR_L3_NEXT_HOPm, &egr_nh, 668 MPLS__INT_CN_TO_EXP_MAPPING_PTRf); 669 ecn_map_pri = soc_mem_field32_get(unit, 670 EGR_L3_NEXT_HOPm, &egr_nh, 671 MPLS__INT_CN_TO_EXP_PRIORITYf); 672 rv = bcmi_ecn_map_hw_idx2id(unit, ecn_map_hw_idx, 673 _BCM_XGS5_MPLS_ECN_MAP_TYPE_INTCN2EXP, 674 &ecn_map_id); 675 if (BCM_SUCCESS(rv)) { 676 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_INT_CN_TO_EXP_MAP; 677 egr->mpls_ecn_map_id = ecn_map_id; 678 if (ecn_map_pri) { 679 egr->mpls_flags |= BCM_MPLS_EGRESS_LABEL_ECN_EXP_MAP_TRUST; 680 } 681 } 682 } 683 } else { 684 egr->mpls_label = BCM_MPLS_LABEL_INVALID; 685 } 686 return BCM_E_NONE; 687 } 688 689 690 #endif