openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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