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

l3.c (67196B)


      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:    bcmx/l3.c
      8  * Purpose: BCMX L3 APIs
      9  */
     10 
     11 #include <sal/core/libc.h>
     12 #include <shared/alloc.h>
     13 
     14 #include <bcm/types.h>
     15 
     16 #include <bcmx/l3.h>
     17 #include <bcmx/lport.h>
     18 #include <bcmx/bcmx.h>
     19 #include <bcmx/lplist.h>
     20 #include <bcmx/switch.h>
     21 
     22 #include "bcmx_int.h"
     23 
     24 #ifdef  INCLUDE_L3
     25 
     26 #define BCMX_L3_INIT_CHECK    BCMX_READY_CHECK
     27 
     28 #define BCMX_L3_ERROR_CHECK(_unit, _check, _rv)    \
     29     BCMX_ERROR_CHECK(_unit, _check, _rv)
     30 
     31 #define BCMX_L3_SET_ERROR_CHECK(_unit, _check, _rv)    \
     32     BCMX_SET_ERROR_CHECK(_unit, _check, _rv)
     33 
     34 #define BCMX_L3_DELETE_ERROR_CHECK(_unit, _check, _rv)    \
     35     BCMX_DELETE_ERROR_CHECK(_unit, _check, _rv)
     36 
     37 #define BCMX_L3_GET_IS_VALID(_unit, _rv)    \
     38     BCMX_ERROR_IS_VALID(_unit, _rv)
     39 
     40 
     41 #define BCMX_L3_SOURCE_BIND_T_PTR_TO_BCM(_info)    \
     42     ((bcm_l3_source_bind_t *)(_info))
     43 
     44 #define BCMX_L3_INGRESS_T_PTR_TO_BCM(_ingress)    \
     45     ((bcm_l3_ingress_t *)(_ingress))
     46 
     47 /*
     48  * Function:
     49  *     _bcmx_bcm_l3_dest
     50  * Purpose:
     51  *     Internal destination conversion routine to handle bcmx to/from bcm
     52  *     and check for egress mode to ignore invalid destinations (when indicated)
     53  * Parameters:
     54  *     dest_bcmx    - BCMX destination object to convert
     55  *     dest_bcm     - BCM destination object to convert
     56  *     flags        - Conversion flags
     57  *     to_bcm       - Indicates whether to convert destination
     58  *                    bcmx 'to' or 'from' bcm.
     59  *     egress_check - Indicates whether to ignore invalid destination
     60  *                    conversion when in L3 egress mode
     61  * Returns:
     62  *     BCM_E_NONE - Success
     63  *     BCM_E_xxx  - Failure
     64  */
     65 STATIC INLINE int
     66 _bcmx_bcm_l3_dest(_bcmx_dest_bcmx_t *dest_bcmx, _bcmx_dest_bcm_t *dest_bcm,
     67                   uint32 *flags, int to_bcm, int egress_check)
     68 {
     69     int  rv;
     70 
     71     /* Convert */
     72     if (to_bcm) {
     73         rv = _bcmx_dest_to_bcm(dest_bcmx, dest_bcm, flags);
     74     } else {
     75         rv = _bcmx_dest_from_bcm(dest_bcmx, dest_bcm, flags);
     76     }
     77 
     78     /* Ignore invalid destination conversion when in L3 egress mode */
     79     if (BCM_FAILURE(rv) && egress_check) {
     80         int l3_egress;
     81 
     82         if (BCM_SUCCESS(bcmx_switch_control_get(bcmSwitchL3EgressMode,
     83                                                 &l3_egress))) {
     84             if (l3_egress) {
     85                 rv = BCM_E_NONE;
     86             }
     87         }
     88     }
     89 
     90     return rv;
     91 }
     92 
     93 STATIC INLINE int
     94 _bcmx_l3ip_to_bcm(bcmx_l3_host_t *l3xip, bcm_l3_host_t *l3ip, int convert_port)
     95 {
     96     int                rv = BCM_E_NONE;
     97     uint32             flags = BCMX_DEST_CONVERT_DEFAULT;
     98     _bcmx_dest_bcm_t   to_bcm;
     99     _bcmx_dest_bcmx_t  from_bcmx;
    100     
    101     bcm_l3_host_t_init(l3ip);
    102     l3ip->l3a_flags = l3xip->l3a_flags;
    103 
    104     if (convert_port) {
    105         /*
    106          * Convert destination data
    107          */
    108         _bcmx_dest_bcmx_t_init(&from_bcmx);
    109     
    110         /* Set flags and data to convert */
    111         if (l3xip->l3a_flags & BCM_L3_TGID) {
    112             flags |= BCMX_DEST_TRUNK;
    113         }
    114         from_bcmx.port  = l3xip->l3a_lport;
    115         from_bcmx.trunk = l3xip->l3a_trunk;
    116 
    117         /* Convert */
    118         /* Indicate to check egress mode in case of invalid destination */
    119         rv = _bcmx_bcm_l3_dest(&from_bcmx, &to_bcm, &flags, 1, 1);
    120 
    121         /* Set converted flags and data */
    122         if (flags & BCMX_DEST_TRUNK) {
    123             l3ip->l3a_flags |= BCM_L3_TGID;
    124             l3ip->l3a_port_tgid = to_bcm.trunk;
    125         } else if (flags & BCMX_DEST_DISCARD) {
    126             l3ip->l3a_flags |= BCM_L3_DST_DISCARD;
    127         } else {
    128             l3ip->l3a_modid     = to_bcm.module_id;
    129             l3ip->l3a_port_tgid = to_bcm.module_port;
    130         }
    131     }
    132 
    133 
    134     /* Set remaining fields */
    135     l3ip->l3a_ip_addr = l3xip->l3a_ip_addr;
    136     l3ip->l3a_intf = l3xip->l3a_intf;
    137     l3ip->l3a_vrf = l3xip->l3a_vrf;
    138     sal_memcpy(l3ip->l3a_ip6_addr, l3xip->l3a_ip6_addr,
    139                sizeof(bcm_ip6_t));
    140     sal_memcpy(l3ip->l3a_nexthop_mac, l3xip->l3a_nexthop_mac,
    141                sizeof(bcm_mac_t));
    142     l3ip->l3a_ipmc_ptr = l3xip->l3a_ipmc_ptr;
    143     l3ip->l3a_pri = l3xip->l3a_pri;
    144     l3ip->l3a_lookup_class = l3xip->l3a_lookup_class;
    145 
    146     return rv;
    147 }
    148 
    149 STATIC INLINE int
    150 _bcmx_l3ip_from_bcm(bcmx_l3_host_t *l3xip, bcm_l3_host_t *l3ip)
    151 {
    152     int                rv = BCM_E_NONE;
    153     uint32             flags = BCMX_DEST_CONVERT_DEFAULT;
    154     _bcmx_dest_bcm_t   from_bcm;
    155     _bcmx_dest_bcmx_t  to_bcmx;
    156 
    157 
    158     bcmx_l3_host_t_init(l3xip);
    159     l3xip->l3a_flags = l3ip->l3a_flags;
    160 
    161     /*
    162      * Convert destination data
    163      */
    164     _bcmx_dest_bcm_t_init(&from_bcm);
    165 
    166     /* Set flags and data to convert */
    167     if (l3ip->l3a_flags & BCM_L3_TGID) {
    168         flags |= BCMX_DEST_TRUNK;
    169     }
    170     from_bcm.module_id   = l3ip->l3a_modid;
    171     from_bcm.module_port = l3ip->l3a_port_tgid;
    172     from_bcm.trunk       = l3ip->l3a_port_tgid;
    173 
    174     /* Convert */
    175     /* Indicate to check egress mode in case of invalid destination */
    176     rv = _bcmx_bcm_l3_dest(&to_bcmx, &from_bcm, &flags, 0, 1);
    177 
    178     /* Set converted flags and data */
    179     if (flags & BCMX_DEST_TRUNK) {
    180         l3xip->l3a_flags |= BCM_L3_TGID;
    181     } else if (flags & BCMX_DEST_DISCARD) {
    182         l3xip->l3a_flags |= BCM_L3_DST_DISCARD;
    183     }
    184     l3xip->l3a_lport = to_bcmx.port;
    185     l3xip->l3a_trunk = to_bcmx.trunk;
    186 
    187 
    188     /* Set remaining fields */
    189     l3xip->l3a_ip_addr = l3ip->l3a_ip_addr;
    190     l3xip->l3a_intf = l3ip->l3a_intf;
    191     l3xip->l3a_vrf = l3ip->l3a_vrf;
    192     sal_memcpy(l3xip->l3a_ip6_addr, l3ip->l3a_ip6_addr,
    193                sizeof(bcm_ip6_t));
    194     sal_memcpy(l3xip->l3a_nexthop_mac, l3ip->l3a_nexthop_mac,
    195                sizeof(bcm_mac_t));
    196     l3xip->l3a_ipmc_ptr = l3ip->l3a_ipmc_ptr;
    197     l3xip->l3a_pri = l3ip->l3a_pri;
    198     l3xip->l3a_lookup_class = l3ip->l3a_lookup_class;
    199 
    200     return rv;
    201 }
    202 
    203 STATIC INLINE int
    204 _bcmx_l3egress_to_bcm(bcmx_l3_egress_t *l3xegr, bcm_l3_egress_t *l3egr)
    205 {
    206     uint32             flags = BCMX_DEST_CONVERT_DEFAULT;
    207     _bcmx_dest_bcm_t   to_bcm;
    208     _bcmx_dest_bcmx_t  from_bcmx;
    209 
    210     bcm_l3_egress_t_init(l3egr);
    211     l3egr->flags = l3xegr->flags;
    212 
    213     /*
    214      * Convert destination data
    215      */
    216     _bcmx_dest_bcmx_t_init(&from_bcmx);
    217     
    218     /* Set flags and data to convert */
    219     if (l3xegr->flags & BCM_L3_TGID) {
    220         flags |= BCMX_DEST_TRUNK;
    221     }
    222     from_bcmx.port  = l3xegr->lport;
    223     from_bcmx.trunk = l3xegr->trunk;
    224 
    225     /* Convert */
    226     /* Return on invalid destination conversion since egress object
    227      * needs to always have a valid destination.
    228      */
    229     BCM_IF_ERROR_RETURN(_bcmx_bcm_l3_dest(&from_bcmx, &to_bcm, &flags, 1, 0));
    230 
    231     /* Set converted flags and data */
    232     if (flags & BCMX_DEST_TRUNK) {
    233         l3egr->flags |= BCM_L3_TGID;
    234     } else if (flags & BCMX_DEST_DISCARD) {
    235         l3egr->flags |= BCM_L3_DST_DISCARD;
    236     }
    237     l3egr->module = to_bcm.module_id;
    238     l3egr->port   = to_bcm.module_port;
    239     l3egr->trunk  = to_bcm.trunk;
    240 
    241 
    242     /* Set remaining fields */
    243     l3egr->intf  = l3xegr->intf; 
    244     sal_memcpy(l3egr->mac_addr, l3xegr->mac_addr, sizeof(bcm_mac_t));
    245     l3egr->vlan = l3xegr->vlan; 
    246     l3egr->mpls_flags = l3xegr->mpls_flags;
    247     l3egr->mpls_label = l3xegr->mpls_label;
    248     l3egr->mpls_qos_map_id = l3xegr->mpls_qos_map_id;
    249     l3egr->mpls_ttl = l3xegr->mpls_ttl;
    250     l3egr->mpls_pkt_pri = l3xegr->mpls_pkt_pri;
    251     l3egr->mpls_pkt_cfi = l3xegr->mpls_pkt_cfi;
    252     l3egr->mpls_exp = l3xegr->mpls_exp;
    253     l3egr->encap_id = l3xegr->encap_id;
    254     l3egr->failover_id = l3xegr->failover_id;
    255     l3egr->failover_if_id = l3xegr->failover_if_id;
    256 
    257     return BCM_E_NONE;
    258 }
    259 
    260 STATIC INLINE int
    261 _bcmx_l3egress_from_bcm(bcmx_l3_egress_t *l3xegr, bcm_l3_egress_t *l3egr)
    262 {
    263     uint32             flags = BCMX_DEST_CONVERT_DEFAULT;
    264     _bcmx_dest_bcm_t   from_bcm;
    265     _bcmx_dest_bcmx_t  to_bcmx;
    266 
    267     bcmx_l3_egress_t_init(l3xegr);
    268     l3xegr->flags = l3egr->flags;
    269 
    270     /*
    271      * Convert destination data
    272      */
    273     _bcmx_dest_bcm_t_init(&from_bcm);
    274 
    275     /* Set flags and data to convert */
    276     if (l3egr->flags & BCM_L3_TGID) {
    277         flags |= BCMX_DEST_TRUNK;
    278     }
    279     from_bcm.module_id   = l3egr->module;
    280     from_bcm.module_port = l3egr->port;
    281     from_bcm.trunk       = l3egr->trunk;
    282 
    283     /* Convert */
    284     /* Return on invalid destination conversion since egress object
    285      * needs to always have a valid destination.
    286      */
    287     BCM_IF_ERROR_RETURN(_bcmx_bcm_l3_dest(&to_bcmx, &from_bcm, &flags, 0, 0));
    288 
    289     /* Set converted flags and data */
    290     if (flags & BCMX_DEST_TRUNK) {
    291         l3xegr->flags |= BCM_L3_TGID;
    292     } else if (flags & BCMX_DEST_DISCARD) {
    293         l3xegr->flags |= BCM_L3_DST_DISCARD;
    294     }
    295     l3xegr->lport = to_bcmx.port;
    296     l3xegr->trunk = to_bcmx.trunk;
    297 
    298 
    299     /* Set remaining fields */
    300     l3xegr->intf  = l3egr->intf;
    301     sal_memcpy(l3xegr->mac_addr, l3egr->mac_addr, sizeof(bcm_mac_t));
    302     l3xegr->vlan = l3egr->vlan;
    303     l3xegr->mpls_flags = l3egr->mpls_flags;
    304     l3xegr->mpls_label = l3egr->mpls_label;
    305     l3xegr->mpls_qos_map_id = l3egr->mpls_qos_map_id;
    306     l3xegr->mpls_ttl = l3egr->mpls_ttl;
    307     l3xegr->mpls_pkt_pri = l3egr->mpls_pkt_pri;
    308     l3xegr->mpls_pkt_cfi = l3egr->mpls_pkt_cfi;
    309     l3xegr->mpls_exp = l3egr->mpls_exp;
    310     l3xegr->encap_id = l3egr->encap_id;
    311     l3xegr->failover_id = l3egr->failover_id;
    312     l3xegr->failover_if_id = l3egr->failover_if_id;
    313 
    314     return BCM_E_NONE;
    315 }
    316 
    317 
    318 STATIC INLINE int
    319 _bcmx_l3route_to_bcm(bcmx_l3_route_t *l3xrt, bcm_l3_route_t *l3rt,
    320                      int convert_port)
    321 {
    322     int                rv = BCM_E_NONE;
    323     uint32             flags = BCMX_DEST_CONVERT_DEFAULT;
    324     _bcmx_dest_bcm_t   to_bcm;
    325     _bcmx_dest_bcmx_t  from_bcmx;
    326 
    327     bcm_l3_route_t_init(l3rt);
    328     l3rt->l3a_flags = l3xrt->l3a_flags;
    329 
    330     if (convert_port) {
    331         /*
    332          * Convert destination data
    333          */
    334         _bcmx_dest_bcmx_t_init(&from_bcmx);
    335     
    336         /* Set flags and data to convert */
    337         if (l3xrt->l3a_flags & BCM_L3_TGID) {
    338             flags |= BCMX_DEST_TRUNK;
    339         }
    340         from_bcmx.port  = l3xrt->l3a_lport;
    341         from_bcmx.trunk = l3xrt->l3a_trunk;
    342 
    343         /* Convert */
    344         /* Indicate to check egress mode in case of invalid destination */
    345         rv = _bcmx_bcm_l3_dest(&from_bcmx, &to_bcm, &flags, 1, 1);
    346 
    347         /* Set converted flags and data */
    348         if (flags & BCMX_DEST_TRUNK) {
    349             l3rt->l3a_flags |= BCM_L3_TGID;
    350             l3rt->l3a_port_tgid = to_bcm.trunk;
    351         } else if (flags & BCMX_DEST_DISCARD) {
    352             l3rt->l3a_flags |= BCM_L3_DST_DISCARD;
    353         } else {
    354             l3rt->l3a_modid     = to_bcm.module_id;
    355             l3rt->l3a_port_tgid = to_bcm.module_port;
    356         }
    357     }
    358 
    359     /* Set remaining fields */
    360     l3rt->l3a_stack_port = 0;
    361     l3rt->l3a_subnet = l3xrt->l3a_subnet;
    362     l3rt->l3a_ip_mask = l3xrt->l3a_ip_mask;
    363     l3rt->l3a_intf = l3xrt->l3a_intf;
    364     l3rt->l3a_vrf = l3xrt->l3a_vrf;
    365     sal_memcpy(l3rt->l3a_ip6_net, l3xrt->l3a_ip6_net,
    366                sizeof(bcm_ip6_t));
    367     sal_memcpy(l3rt->l3a_ip6_mask, l3xrt->l3a_ip6_mask,
    368                sizeof(bcm_ip6_t));
    369     sal_memcpy(l3rt->l3a_nexthop_mac, l3xrt->l3a_nexthop_mac,
    370                sizeof(bcm_mac_t));
    371     l3rt->l3a_nexthop_ip = l3xrt->l3a_nexthop_ip;
    372     l3rt->l3a_vid = l3xrt->l3a_vid;
    373     l3rt->l3a_pri = l3xrt->l3a_pri;
    374     l3rt->l3a_tunnel_option = l3xrt->l3a_tunnel_option;
    375     l3rt->l3a_mpls_label = l3xrt->l3a_mpls_label;
    376     l3rt->l3a_lookup_class = l3xrt->l3a_lookup_class;
    377 
    378     return rv;
    379 }
    380 
    381 STATIC INLINE int
    382 _bcmx_l3route_from_bcm(bcmx_l3_route_t *l3xrt, bcm_l3_route_t *l3rt)
    383 {
    384     int                rv = BCM_E_NONE;
    385     uint32             flags = BCMX_DEST_CONVERT_DEFAULT;
    386     _bcmx_dest_bcm_t   from_bcm;
    387     _bcmx_dest_bcmx_t  to_bcmx;
    388 
    389     bcmx_l3_route_t_init(l3xrt);
    390     l3xrt->l3a_flags = l3rt->l3a_flags;
    391 
    392     /*
    393      * Convert destination data
    394      */
    395     _bcmx_dest_bcm_t_init(&from_bcm);
    396 
    397     /* Set flags and data to convert */
    398     if (l3rt->l3a_flags & BCM_L3_TGID) {
    399         flags |= BCMX_DEST_TRUNK;
    400     }
    401     from_bcm.module_id   = l3rt->l3a_modid;
    402     from_bcm.module_port = l3rt->l3a_port_tgid;
    403     from_bcm.trunk       = l3rt->l3a_port_tgid;
    404 
    405     /* Convert */
    406     /* Indicate to check egress mode in case of invalid destination */
    407     rv = _bcmx_bcm_l3_dest(&to_bcmx, &from_bcm, &flags, 0, 1);
    408 
    409     /* Set converted flags and data */
    410     if (flags & BCMX_DEST_TRUNK) {
    411         l3xrt->l3a_flags |= BCM_L3_TGID;
    412     } else if (flags & BCMX_DEST_DISCARD) {
    413         l3xrt->l3a_flags |= BCM_L3_DST_DISCARD;
    414     }
    415     l3xrt->l3a_lport = to_bcmx.port;
    416     l3xrt->l3a_trunk = to_bcmx.trunk;
    417 
    418 
    419     /* Set remaining fields */
    420     l3xrt->l3a_subnet = l3rt->l3a_subnet;
    421     l3xrt->l3a_ip_mask = l3rt->l3a_ip_mask;
    422     l3xrt->l3a_intf = l3rt->l3a_intf;
    423     l3xrt->l3a_vrf = l3rt->l3a_vrf;
    424     sal_memcpy(l3xrt->l3a_ip6_net, l3rt->l3a_ip6_net,
    425                sizeof(bcm_ip6_t));
    426     sal_memcpy(l3xrt->l3a_ip6_mask, l3rt->l3a_ip6_mask,
    427                sizeof(bcm_ip6_t));
    428     sal_memcpy(l3xrt->l3a_nexthop_mac, l3rt->l3a_nexthop_mac,
    429                sizeof(bcm_mac_t));
    430     l3xrt->l3a_nexthop_ip = l3rt->l3a_nexthop_ip;
    431     l3xrt->l3a_vid = l3rt->l3a_vid;
    432     l3xrt->l3a_pri = l3rt->l3a_pri;
    433     l3xrt->l3a_tunnel_option = l3rt->l3a_tunnel_option;
    434     l3xrt->l3a_mpls_label = l3rt->l3a_mpls_label;
    435     l3xrt->l3a_lookup_class = l3rt->l3a_lookup_class;
    436 
    437     return rv;
    438 }
    439 
    440 
    441 /*
    442  * Initialize a L3 IP struct
    443  */
    444 int
    445 bcmx_l3_host_t_init(bcmx_l3_host_t *ip)
    446 {
    447     if (ip != NULL) {
    448         sal_memset(ip, 0, sizeof(bcmx_l3_host_t));
    449         ip->l3a_vrf = BCM_L3_VRF_DEFAULT;
    450     }
    451 
    452     return BCM_E_NONE;
    453 }
    454 
    455 /*
    456  * Initialize a L3 route struct
    457  */
    458 int
    459 bcmx_l3_route_t_init(bcmx_l3_route_t *route)
    460 {
    461     if (route != NULL) {
    462         sal_memset(route, 0, sizeof(bcmx_l3_route_t));
    463         route->l3a_vrf = BCM_L3_VRF_DEFAULT;
    464     }
    465 
    466     return BCM_E_NONE;
    467 }
    468 
    469 /*
    470  * Initialize a L3 interface struct
    471  */
    472 int
    473 bcmx_l3_intf_t_init(bcmx_l3_intf_t *intf)
    474 {
    475     if (intf != NULL) {
    476         sal_memset(intf, 0, sizeof(bcmx_l3_intf_t));
    477         intf->l3a_vrf = BCM_L3_VRF_DEFAULT;
    478     }
    479 
    480     return BCM_E_NONE;
    481 }
    482 
    483 /*
    484  * Initialize a L3 egress object struct
    485  */
    486 void
    487 bcmx_l3_egress_t_init(bcmx_l3_egress_t *egr)
    488 {
    489     if (egr != NULL) {
    490         sal_memset(egr, 0, sizeof(bcmx_l3_egress_t));
    491         egr->mpls_label = BCM_MPLS_LABEL_INVALID;
    492     }
    493 }
    494 
    495 /*
    496  * Initialize a L3 source bind object struct
    497  */
    498 void bcmx_l3_source_bind_t_init(bcmx_l3_source_bind_t *info)
    499 {
    500     if (info != NULL) {
    501         bcm_l3_source_bind_t_init
    502             (BCMX_L3_SOURCE_BIND_T_PTR_TO_BCM(info));
    503     }
    504 }
    505 
    506 /*
    507  * Initialize a L3 ingress object struct
    508  */
    509 void
    510 bcmx_l3_ingress_t_init(bcmx_l3_ingress_t *ing_intf)
    511 {
    512     if (ing_intf != NULL) {
    513         bcm_l3_ingress_t_init(BCMX_L3_INGRESS_T_PTR_TO_BCM(ing_intf));
    514     }
    515 }
    516 
    517 
    518 /*
    519  * Function:
    520  *      bcmx_l3_init
    521  */
    522 
    523 int
    524 bcmx_l3_init(void)
    525 {
    526     int rv = BCM_E_UNAVAIL, tmp_rv;
    527     int i, bcm_unit;
    528 
    529     BCMX_L3_INIT_CHECK;
    530 
    531     BCMX_UNIT_ITER(bcm_unit, i) {
    532         tmp_rv = bcm_l3_init(bcm_unit);
    533         BCM_IF_ERROR_RETURN(BCMX_L3_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    534     }
    535 
    536     return rv;
    537 }
    538 
    539 
    540 /*
    541  * Function:
    542  *      bcmx_l3_cleanup
    543  */
    544 
    545 int
    546 bcmx_l3_cleanup(void)
    547 {
    548     int rv = BCM_E_UNAVAIL, tmp_rv;
    549     int i, bcm_unit;
    550 
    551     BCMX_L3_INIT_CHECK;
    552 
    553     BCMX_UNIT_ITER(bcm_unit, i) {
    554         tmp_rv = bcm_l3_cleanup(bcm_unit);
    555         BCM_IF_ERROR_RETURN(BCMX_L3_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    556     }
    557 
    558     return rv;
    559 }
    560 
    561 
    562 /*
    563  * Function:
    564  *      bcmx_l3_enable_set
    565  */
    566 
    567 int
    568 bcmx_l3_enable_set(int enable)
    569 {
    570     int rv = BCM_E_UNAVAIL, tmp_rv;
    571     int i, bcm_unit;
    572 
    573     BCMX_L3_INIT_CHECK;
    574 
    575     BCMX_UNIT_ITER(bcm_unit, i) {
    576         tmp_rv = bcm_l3_enable_set(bcm_unit, enable);
    577         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    578     }
    579 
    580     return rv;
    581 }
    582 
    583 
    584 /*
    585  * Function:
    586  *      bcmx_l3_info
    587  */
    588 
    589 int
    590 bcmx_l3_info(bcm_l3_info_t *l3info)
    591 {
    592     int rv = BCM_E_UNAVAIL, tmp_rv;
    593     int i, bcm_unit;
    594     bcm_l3_info_t tmp_l3info;
    595     int first = TRUE;
    596 
    597     BCMX_L3_INIT_CHECK;
    598 
    599     BCMX_PARAM_NULL_CHECK(l3info);
    600 
    601     BCMX_UNIT_ITER(bcm_unit, i) {
    602         tmp_rv = bcm_l3_info(bcm_unit, &tmp_l3info);
    603 
    604         if (BCMX_L3_GET_IS_VALID(bcm_unit, tmp_rv)) {
    605             rv = tmp_rv;
    606 
    607             BCM_IF_ERROR_RETURN(rv);
    608 
    609             if (first) {
    610                 *l3info = tmp_l3info;
    611                 first = FALSE;
    612                 continue;
    613             }
    614 
    615             /* Set the minimum for 'max' members */
    616             if (tmp_l3info.l3info_max_vrf < l3info->l3info_max_vrf) {
    617                 l3info->l3info_max_vrf = tmp_l3info.l3info_max_vrf;
    618             }
    619             if (tmp_l3info.l3info_max_intf < l3info->l3info_max_intf) {
    620                 l3info->l3info_max_intf = tmp_l3info.l3info_max_intf;
    621             }
    622             if (tmp_l3info.l3info_max_intf_group < l3info->l3info_max_intf_group) {
    623                 l3info->l3info_max_intf_group = tmp_l3info.l3info_max_intf_group;
    624             }
    625             if (tmp_l3info.l3info_max_host < l3info->l3info_max_host) {
    626                 l3info->l3info_max_host = tmp_l3info.l3info_max_host;
    627             }
    628             if (tmp_l3info.l3info_max_route < l3info->l3info_max_route) {
    629                 l3info->l3info_max_route = tmp_l3info.l3info_max_route;
    630             }
    631             if (tmp_l3info.l3info_max_ecmp < l3info->l3info_max_ecmp) {
    632                 l3info->l3info_max_ecmp = tmp_l3info.l3info_max_ecmp;
    633             }
    634             
    635             if (tmp_l3info.l3info_max_lpm_block < l3info->l3info_max_lpm_block) {
    636                 l3info->l3info_max_lpm_block = tmp_l3info.l3info_max_lpm_block;
    637             }
    638             if (tmp_l3info.l3info_max_l3 < l3info->l3info_max_l3) {
    639                 l3info->l3info_max_l3 = tmp_l3info.l3info_max_l3;
    640             }
    641             if (tmp_l3info.l3info_max_defip < l3info->l3info_max_defip) {
    642                 l3info->l3info_max_defip = tmp_l3info.l3info_max_defip;
    643             }
    644 
    645             if (tmp_l3info.l3info_max_nexthop < l3info->l3info_max_nexthop) {
    646                 l3info->l3info_max_nexthop = tmp_l3info.l3info_max_nexthop;
    647             }
    648             if (tmp_l3info.l3info_max_tunnel_init < l3info->l3info_max_tunnel_init) {
    649                 l3info->l3info_max_tunnel_init = tmp_l3info.l3info_max_tunnel_init;
    650             }
    651             if (tmp_l3info.l3info_max_tunnel_term < l3info->l3info_max_tunnel_term) {
    652                 l3info->l3info_max_tunnel_term = tmp_l3info.l3info_max_tunnel_term;
    653             }
    654         }
    655     }
    656 
    657     return rv;
    658 }
    659 
    660 
    661 /**************************************************************
    662  * bcmx_l3_intf_xxx
    663  */
    664 
    665 /*
    666  * Function:
    667  *     bcmx_l3_intf_create
    668  */
    669 
    670 int
    671 bcmx_l3_intf_create(bcmx_l3_intf_t *intf)
    672 {
    673     int rv = BCM_E_UNAVAIL, tmp_rv;
    674     int i, bcm_unit;
    675 
    676     BCMX_L3_INIT_CHECK;
    677 
    678     BCMX_PARAM_NULL_CHECK(intf);
    679 
    680     BCMX_UNIT_ITER(bcm_unit, i) {
    681         tmp_rv = bcm_l3_intf_create(bcm_unit, intf);
    682         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    683     }
    684 
    685     return rv;
    686 }
    687 
    688 /*
    689  * Function:
    690  *     bcmx_l3_intf_delete
    691  */
    692 
    693 int
    694 bcmx_l3_intf_delete(bcmx_l3_intf_t *intf)
    695 {
    696     int rv = BCM_E_UNAVAIL, tmp_rv;
    697     int i, bcm_unit;
    698 
    699     BCMX_L3_INIT_CHECK;
    700 
    701     BCMX_PARAM_NULL_CHECK(intf);
    702 
    703     BCMX_UNIT_ITER(bcm_unit, i) {
    704         tmp_rv = bcm_l3_intf_delete(bcm_unit, intf);
    705         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    706     }
    707 
    708     return rv;
    709 }
    710 
    711 /*
    712  * Function:
    713  *     bcmx_l3_intf_delete_all
    714  */
    715 
    716 int
    717 bcmx_l3_intf_delete_all(void)
    718 {
    719     int rv = BCM_E_UNAVAIL, tmp_rv;
    720     int i, bcm_unit;
    721 
    722     BCMX_L3_INIT_CHECK;
    723 
    724     BCMX_UNIT_ITER(bcm_unit, i) {
    725         tmp_rv = bcm_l3_intf_delete_all(bcm_unit);
    726         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    727     }
    728 
    729     return rv;
    730 }
    731 
    732 /*
    733  * Function:
    734  *     bcmx_l3_intf_find
    735  */
    736 
    737 int
    738 bcmx_l3_intf_find(bcmx_l3_intf_t *intf)
    739 {
    740     int rv;
    741     int i, bcm_unit;
    742 
    743     BCMX_L3_INIT_CHECK;
    744 
    745     BCMX_PARAM_NULL_CHECK(intf);
    746 
    747     BCMX_UNIT_ITER(bcm_unit, i) {
    748         rv = bcm_l3_intf_find(bcm_unit, intf);
    749         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
    750             return rv;
    751         }
    752     }
    753 
    754     return BCM_E_UNAVAIL;
    755 }
    756 
    757 /*
    758  * Function:
    759  *     bcmx_l3_intf_find_vlan
    760  */
    761 
    762 int
    763 bcmx_l3_intf_find_vlan(bcm_l3_intf_t *intf)
    764 {
    765     int rv;
    766     int i, bcm_unit;
    767 
    768     BCMX_L3_INIT_CHECK;
    769 
    770     BCMX_PARAM_NULL_CHECK(intf);
    771 
    772     BCMX_UNIT_ITER(bcm_unit, i) {
    773         rv = bcm_l3_intf_find_vlan(bcm_unit, intf);
    774         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
    775             return rv;
    776         }
    777     }
    778 
    779     return BCM_E_UNAVAIL;
    780 }
    781 
    782 /*
    783  * Function:
    784  *     bcmx_l3_intf_get
    785  */
    786 
    787 int
    788 bcmx_l3_intf_get(bcm_l3_intf_t *intf)
    789 {
    790     int rv;
    791     int i, bcm_unit;
    792 
    793     BCMX_L3_INIT_CHECK;
    794 
    795     BCMX_PARAM_NULL_CHECK(intf);
    796 
    797     BCMX_UNIT_ITER(bcm_unit, i) {
    798         rv = bcm_l3_intf_get(bcm_unit, intf);
    799         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
    800             return rv;
    801         }
    802     }
    803 
    804     return BCM_E_UNAVAIL;
    805 }
    806 
    807 /**************************************************************
    808  * bcmx_l3_egress_xxx
    809  */
    810 int 
    811 bcmx_l3_egress_create(uint32 flags, bcmx_l3_egress_t *egr, bcm_if_t *intf) 
    812 {
    813     int rv = BCM_E_UNAVAIL;    /* Overall operation result.           */
    814     int tmp_rv;                /* Unit operation result.              */
    815     int unit_cntr;             /* Number of devices counter.          */
    816     int bcm_unit;              /* bcm device iterator.                */
    817     bcm_l3_egress_t bcm_egr;   /* Egress object.                      */
    818     int map_local_cpu;         /* Is local CPU port mapping required? */
    819     bcmx_lport_t cpu_lport;    /* Cpu logical port.                   */
    820 
    821     BCMX_L3_INIT_CHECK;
    822 
    823     BCMX_PARAM_NULL_CHECK(egr);
    824     BCMX_PARAM_NULL_CHECK(intf);
    825 
    826     map_local_cpu = ((!(egr->flags & BCM_L3_TGID)) &&
    827                      (egr->lport == BCMX_LPORT_LOCAL_CPU));
    828 
    829     BCM_IF_ERROR_RETURN(_bcmx_l3egress_to_bcm(egr, &bcm_egr));
    830 
    831     if ((!map_local_cpu) &&
    832         (!(egr->flags & BCM_L3_TGID) && (bcm_egr.module < 0)) &&
    833         (!BCM_GPORT_IS_SET(bcm_egr.port))) {
    834         return (BCM_E_PORT);
    835     }
    836 
    837     BCMX_UNIT_ITER(bcm_unit, unit_cntr) {
    838         if (map_local_cpu) {
    839             cpu_lport = BCMX_LPORT_LOCAL_CPU_GET(bcm_unit);
    840             if (BCM_FAILURE
    841                 (_bcmx_dest_to_modid_port(cpu_lport,
    842                                           &bcm_egr.module,
    843                                           &bcm_egr.port,
    844                                           BCMX_DEST_CONVERT_DEFAULT))) {  
    845                 /* Skip if can't find local CPU port */
    846                 continue;
    847             }
    848         }
    849         tmp_rv = bcm_l3_egress_create(bcm_unit, flags, &bcm_egr, intf);
    850         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    851     }
    852 
    853     return rv;
    854 }
    855 
    856 int 
    857 bcmx_l3_egress_destroy(bcm_if_t intf)
    858 {
    859     int rv = BCM_E_UNAVAIL;    /* Overall operation result.      */
    860     int tmp_rv;                /* Unit operation result.         */
    861     int unit_cntr;             /* Number of devices counter.     */
    862     int bcm_unit;              /* bcm device iterator.           */
    863 
    864     BCMX_L3_INIT_CHECK;
    865 
    866     BCMX_UNIT_ITER(bcm_unit, unit_cntr) {
    867         tmp_rv = bcm_l3_egress_destroy(bcm_unit, intf);
    868         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    869     }
    870 
    871     return rv;
    872 }
    873 
    874 int 
    875 bcmx_l3_egress_get(bcm_if_t intf, bcmx_l3_egress_t *egr)
    876 {
    877     int unit_cntr;             /* Number of devices counter.     */
    878     int bcm_unit;              /* bcm device iterator.           */
    879     bcm_l3_egress_t bcm_egr;   /* Egress object.                 */
    880     int rv;                    /* Overall operation result.      */
    881 
    882     BCMX_L3_INIT_CHECK;
    883 
    884     BCMX_PARAM_NULL_CHECK(egr);
    885 
    886     BCMX_UNIT_ITER(bcm_unit, unit_cntr) {
    887         rv = bcm_l3_egress_get(bcm_unit, intf, &bcm_egr);
    888         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
    889             if (BCM_SUCCESS(rv)) {
    890                 rv = _bcmx_l3egress_from_bcm(egr, &bcm_egr);
    891             }
    892             return rv;
    893         }
    894     }
    895 
    896     return BCM_E_UNAVAIL;
    897 }
    898 
    899 int 
    900 bcmx_l3_egress_find(bcmx_l3_egress_t *egr, bcm_if_t *intf)
    901 {
    902     int unit_cntr;             /* Number of devices counter.          */
    903     int bcm_unit;              /* bcm device iterator.                */
    904     bcm_l3_egress_t bcm_egr;   /* Egress object.                      */
    905     int map_local_cpu;         /* Is local CPU port mapping required? */
    906     bcmx_lport_t cpu_lport;    /* Cpu logical port.                   */
    907     int rv;                    /* Overall operation result.           */
    908 
    909     BCMX_L3_INIT_CHECK;
    910 
    911     BCMX_PARAM_NULL_CHECK(egr);
    912     BCMX_PARAM_NULL_CHECK(intf);
    913 
    914     map_local_cpu = ((!(egr->flags & BCM_L3_TGID)) &&
    915                      (egr->lport == BCMX_LPORT_LOCAL_CPU));
    916 
    917     BCM_IF_ERROR_RETURN(_bcmx_l3egress_to_bcm(egr, &bcm_egr));
    918 
    919     if ((!map_local_cpu) &&
    920         (!(egr->flags & BCM_L3_TGID) && (bcm_egr.module < 0))) {
    921         return (BCM_E_PORT);
    922     }
    923 
    924     BCMX_UNIT_ITER(bcm_unit, unit_cntr) {
    925         if (map_local_cpu) {
    926             cpu_lport = BCMX_LPORT_LOCAL_CPU_GET(bcm_unit);
    927             if (BCM_FAILURE
    928                 (_bcmx_dest_to_modid_port(cpu_lport,
    929                                           &bcm_egr.module,
    930                                           &bcm_egr.port,
    931                                           BCMX_DEST_CONVERT_DEFAULT))) {
    932                 /* Skip if can't find local CPU port */
    933                 continue;
    934             }
    935         }
    936         rv = bcm_l3_egress_find(bcm_unit, &bcm_egr, intf);
    937         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
    938             return rv;
    939         }
    940     }
    941 
    942     return BCM_E_UNAVAIL;
    943 }
    944 
    945 int
    946 bcmx_l3_egress_traverse(bcm_l3_egress_traverse_cb trav_fn, void *user_data)
    947 {
    948     int unit_cntr;             /* Number of devices counter.     */
    949     int bcm_unit;              /* bcm device iterator.           */
    950     int rv;                    /* Overall operation result.      */
    951 
    952     BCMX_L3_INIT_CHECK;
    953 
    954     BCMX_LOCAL_UNIT_ITER(bcm_unit, unit_cntr) {
    955         rv = bcm_l3_egress_traverse(bcm_unit, trav_fn, user_data);
    956         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
    957             return rv;
    958         }
    959     }
    960 
    961     return BCM_E_UNAVAIL;
    962 }
    963 
    964 int 
    965 bcmx_l3_egress_multipath_create(uint32 flags, int intf_count,
    966                                 bcm_if_t *intf_array, bcm_if_t *mpintf)
    967 {
    968     int rv = BCM_E_UNAVAIL;    /* Overall operation result.      */
    969     int tmp_rv;                /* Unit operation result.         */
    970     int unit_cntr;             /* Number of devices counter.     */
    971     int bcm_unit;              /* bcm device iterator.           */
    972 
    973     BCMX_L3_INIT_CHECK;
    974 
    975     BCMX_PARAM_ARRAY_NULL_CHECK(intf_count, intf_array);
    976     BCMX_PARAM_NULL_CHECK(mpintf);
    977 
    978     BCMX_UNIT_ITER(bcm_unit, unit_cntr) {
    979         tmp_rv = bcm_l3_egress_multipath_create(bcm_unit, flags, intf_count,
    980                                                 intf_array, mpintf);
    981         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    982     }
    983 
    984     return rv;
    985 }
    986 
    987 int
    988 bcmx_l3_egress_multipath_max_create(uint32 flags,
    989                                     int max_paths, int intf_count,
    990                                     bcm_if_t *intf_array, bcm_if_t *mpintf)
    991 {
    992     int rv = BCM_E_UNAVAIL, tmp_rv;
    993     int i, bcm_unit;
    994 
    995     BCMX_L3_INIT_CHECK;
    996 
    997     BCMX_PARAM_ARRAY_NULL_CHECK(intf_count, intf_array);
    998     BCMX_PARAM_NULL_CHECK(mpintf);
    999 
   1000     BCMX_UNIT_ITER(bcm_unit, i) {
   1001         tmp_rv = bcm_l3_egress_multipath_max_create(bcm_unit, flags,
   1002                                                     max_paths, intf_count,
   1003                                                     intf_array, mpintf);
   1004         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1005     }
   1006 
   1007     return rv;
   1008 }
   1009 
   1010 int 
   1011 bcmx_l3_egress_multipath_destroy(bcm_if_t mpintf)
   1012 {
   1013     int rv = BCM_E_UNAVAIL;    /* Overall operation result.      */
   1014     int tmp_rv;                /* Unit operation result.         */
   1015     int unit_cntr;             /* Number of devices counter.     */
   1016     int bcm_unit;              /* bcm device iterator.           */
   1017 
   1018     BCMX_L3_INIT_CHECK;
   1019 
   1020     BCMX_UNIT_ITER(bcm_unit, unit_cntr) {
   1021         tmp_rv = bcm_l3_egress_multipath_destroy(bcm_unit, mpintf);
   1022         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1023     }
   1024 
   1025     return rv;
   1026 }
   1027 
   1028 int 
   1029 bcmx_l3_egress_multipath_get(bcm_if_t mpintf, int intf_size,
   1030                              bcm_if_t *intf_array, int *intf_count)
   1031 {
   1032     int unit_cntr;             /* Number of devices counter.     */
   1033     int bcm_unit;              /* bcm device iterator.           */
   1034     int rv;                    /* Overall operation result.      */
   1035 
   1036     BCMX_L3_INIT_CHECK;
   1037 
   1038     BCMX_PARAM_ARRAY_NULL_CHECK(intf_size, intf_array);
   1039     BCMX_PARAM_NULL_CHECK(intf_count);
   1040 
   1041     BCMX_UNIT_ITER(bcm_unit, unit_cntr) {
   1042         rv = bcm_l3_egress_multipath_get(bcm_unit, mpintf, intf_size,
   1043                                          intf_array, intf_count);
   1044         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
   1045             return rv;
   1046         }
   1047     }
   1048 
   1049     return BCM_E_UNAVAIL;
   1050 }
   1051 
   1052 int 
   1053 bcmx_l3_egress_multipath_add(bcm_if_t mpintf, bcm_if_t intf)
   1054 {
   1055     int rv = BCM_E_UNAVAIL;    /* Overall operation result.      */
   1056     int tmp_rv;                /* Unit operation result.         */
   1057     int unit_cntr;             /* Number of devices counter.     */
   1058     int bcm_unit;              /* bcm device iterator.           */
   1059 
   1060     BCMX_L3_INIT_CHECK;
   1061 
   1062     BCMX_UNIT_ITER(bcm_unit, unit_cntr) {
   1063         tmp_rv = bcm_l3_egress_multipath_add(bcm_unit, mpintf, intf);
   1064         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1065     }
   1066 
   1067     return rv;
   1068 }
   1069 
   1070 int 
   1071 bcmx_l3_egress_multipath_delete(bcm_if_t mpintf, bcm_if_t intf)
   1072 {
   1073     int rv = BCM_E_UNAVAIL;    /* Overall operation result.      */
   1074     int tmp_rv;                /* Unit operation result.         */
   1075     int unit_cntr;             /* Number of devices counter.     */
   1076     int bcm_unit;              /* bcm device iterator.           */
   1077 
   1078     BCMX_L3_INIT_CHECK;
   1079 
   1080     BCMX_UNIT_ITER(bcm_unit, unit_cntr) {
   1081         tmp_rv = bcm_l3_egress_multipath_delete(bcm_unit, mpintf, intf);
   1082         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1083     }
   1084 
   1085     return rv;
   1086 }
   1087 
   1088 int 
   1089 bcmx_l3_egress_multipath_find(int intf_count, bcm_if_t *intf_array, 
   1090                               bcm_if_t *mpintf)
   1091 {
   1092     int unit_cntr;             /* Number of devices counter.          */
   1093     int bcm_unit;              /* bcm device iterator.                */
   1094     int rv;                    /* Overall operation result.      */
   1095 
   1096     BCMX_L3_INIT_CHECK;
   1097 
   1098     BCMX_PARAM_ARRAY_NULL_CHECK(intf_count, intf_array);
   1099     BCMX_PARAM_NULL_CHECK(mpintf);
   1100 
   1101     BCMX_UNIT_ITER(bcm_unit, unit_cntr) {
   1102         rv = bcm_l3_egress_multipath_find(bcm_unit, intf_count,
   1103                                           intf_array, mpintf);
   1104         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
   1105             return rv;
   1106         }
   1107     }
   1108 
   1109     return BCM_E_UNAVAIL;
   1110 }
   1111 
   1112 int
   1113 bcmx_l3_egress_multipath_traverse(bcm_l3_egress_multipath_traverse_cb trav_fn,
   1114                                   void *user_data)
   1115 {
   1116     int unit_cntr;             /* Number of devices counter.     */
   1117     int bcm_unit;              /* bcm device iterator.           */
   1118     int rv;                    /* Overall operation result.      */
   1119 
   1120     BCMX_L3_INIT_CHECK;
   1121 
   1122     BCMX_LOCAL_UNIT_ITER(bcm_unit, unit_cntr) {
   1123         rv = bcm_l3_egress_multipath_traverse(bcm_unit, trav_fn, user_data);
   1124         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
   1125             return rv;
   1126         }
   1127     }
   1128 
   1129     return BCM_E_UNAVAIL;
   1130 }
   1131 
   1132 
   1133 /**************************************************************
   1134  * bcmx_l3_ingress_xxx
   1135  */
   1136 /*
   1137  * Function:
   1138  *     bcmx_l3_ingress_create
   1139  * Purpose:
   1140  *     Create an Ingress Interface object.
   1141  * Parameters:
   1142  *     ing_intf - Ingress Interface information.
   1143  *     intf_id  - (IN/OUT) L3 Ingress interface id pointing to Ingress object.
   1144  *                This is an IN argument if either BCM_L3_INGRESS_REPLACE
   1145  *                or BCM_L3_INGRESS_WITH_ID are given in flags.
   1146  * Returns:
   1147  *     BCM_E_XXX
   1148  */
   1149 int
   1150 bcmx_l3_ingress_create(bcmx_l3_ingress_t *ing_intf, bcm_if_t *intf_id)
   1151 {
   1152     int     rv = BCM_E_UNAVAIL, tmp_rv;
   1153     int     i, bcm_unit;
   1154     bcmx_l3_ingress_t  tmp_ing_intf;
   1155 
   1156     BCMX_L3_INIT_CHECK;
   1157 
   1158     BCMX_PARAM_NULL_CHECK(ing_intf);
   1159     BCMX_PARAM_NULL_CHECK(intf_id);
   1160 
   1161     tmp_ing_intf = *ing_intf;
   1162     BCMX_UNIT_ITER(bcm_unit, i) {
   1163 
   1164         tmp_rv = bcm_l3_ingress_create(bcm_unit,
   1165                                        BCMX_L3_INGRESS_T_PTR_TO_BCM
   1166                                        (&tmp_ing_intf),
   1167                                        intf_id);
   1168         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1169 
   1170         /*
   1171          * Use the ID from first successful 'create' if group ID
   1172          * is not specified.
   1173          */
   1174         if (!(tmp_ing_intf.flags & BCM_L3_INGRESS_WITH_ID)) {
   1175             if (BCM_SUCCESS(tmp_rv)) {
   1176                 tmp_ing_intf.flags |= BCM_L3_INGRESS_WITH_ID;
   1177             }
   1178         }
   1179     }
   1180 
   1181     return rv;
   1182 }
   1183 
   1184 /*
   1185  * Function:
   1186  *     bcmx_l3_ingress_destroy
   1187  * Purpose:
   1188  *     Destroy an Ingress Interface object.
   1189  * Parameters:
   1190  *     intf_id  - L3 Ingress interface id pointing to Ingress object.
   1191  * Returns:
   1192  *     BCM_E_XXX
   1193  */
   1194 int
   1195 bcmx_l3_ingress_destroy(bcm_if_t intf_id)
   1196 {
   1197     int  rv = BCM_E_UNAVAIL, tmp_rv;
   1198     int  i, bcm_unit;
   1199 
   1200     BCMX_L3_INIT_CHECK;
   1201 
   1202     BCMX_UNIT_ITER(bcm_unit, i) {
   1203         tmp_rv = bcm_l3_ingress_destroy(bcm_unit, intf_id);
   1204         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1205     }
   1206 
   1207     return rv;
   1208 }
   1209 
   1210 /*
   1211  * Function:
   1212  *     bcmx_l3_ingress_get
   1213  * Purpose:
   1214  *     Get an Ingress Interface object.
   1215  * Parameters:
   1216  *     intf_id  - L3 Ingress interface id pointing to Ingress object.
   1217  *     ing_intf - (OUT) Ingress Interface object properties.
   1218  * Returns:
   1219  *     BCM_E_XXX
   1220  */
   1221 int
   1222 bcmx_l3_ingress_get(bcm_if_t intf, bcmx_l3_ingress_t *ing_intf)
   1223 {
   1224     int  rv;
   1225     int  i, bcm_unit;
   1226 
   1227     BCMX_L3_INIT_CHECK;
   1228 
   1229     BCMX_PARAM_NULL_CHECK(ing_intf);
   1230 
   1231     BCMX_UNIT_ITER(bcm_unit, i) {
   1232         rv = bcm_l3_ingress_get(bcm_unit, intf,
   1233                                 BCMX_L3_INGRESS_T_PTR_TO_BCM(ing_intf));
   1234         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
   1235             return rv;
   1236         }
   1237     }
   1238 
   1239     return BCM_E_UNAVAIL;
   1240 }
   1241 
   1242 /*
   1243  * Function:
   1244  *     bcmx_l3_ingress_find
   1245  * Purpose:
   1246  *     Find the Ingress interface id.
   1247  * Parameters:
   1248  *     ing_intf - Ingress Interface information.
   1249  *     intf_id  - (OUT) L3 Ingress interface id pointing to Ingress object.
   1250  * Returns:
   1251  *     BCM_E_XXX
   1252  */
   1253 int
   1254 bcmx_l3_ingress_find(bcmx_l3_ingress_t *ing_intf, bcm_if_t *intf_id)
   1255 {
   1256     int  rv;
   1257     int  i, bcm_unit;
   1258 
   1259     BCMX_L3_INIT_CHECK;
   1260 
   1261     BCMX_PARAM_NULL_CHECK(ing_intf);
   1262     BCMX_PARAM_NULL_CHECK(intf_id);
   1263 
   1264     BCMX_UNIT_ITER(bcm_unit, i) {
   1265         rv = bcm_l3_ingress_find(bcm_unit,
   1266                                  BCMX_L3_INGRESS_T_PTR_TO_BCM(ing_intf),
   1267                                  intf_id);
   1268         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
   1269             return rv;
   1270         }
   1271     }
   1272 
   1273     return BCM_E_UNAVAIL;
   1274 }
   1275 
   1276 
   1277 /*
   1278  *  IPv6 prefix map APIs.
   1279  */
   1280 /**************************************************************
   1281  * bcmx_l3_ip6_prefix_map APIs
   1282  */
   1283 int bcmx_l3_ip6_prefix_map_get(int map_size, 
   1284                                bcm_ip6_t *ip6_array, int *ip6_count) 
   1285 {
   1286     int unit_cntr;             /* Number of devices counter.     */
   1287     int bcm_unit;              /* bcm device iterator.           */
   1288     int rv;                    /* Overall operation result.      */
   1289 
   1290     BCMX_L3_INIT_CHECK;
   1291 
   1292     BCMX_PARAM_ARRAY_NULL_CHECK(map_size, ip6_array);
   1293     BCMX_PARAM_NULL_CHECK(ip6_count);
   1294 
   1295     BCMX_LOCAL_UNIT_ITER(bcm_unit, unit_cntr) {
   1296         rv = bcm_l3_ip6_prefix_map_get(bcm_unit, map_size, 
   1297                                        ip6_array, ip6_count);
   1298         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
   1299             return rv;
   1300         }
   1301     }
   1302 
   1303     return BCM_E_UNAVAIL;
   1304 }
   1305 
   1306 int bcmx_l3_ip6_prefix_map_add(bcm_ip6_t ip6_addr) 
   1307 {
   1308     int rv = BCM_E_UNAVAIL;    /* Overall operation result.      */
   1309     int tmp_rv;                /* Unit operation result.         */
   1310     int unit_cntr;             /* Number of devices counter.     */
   1311     int bcm_unit;              /* bcm device iterator.           */
   1312 
   1313     BCMX_L3_INIT_CHECK;
   1314 
   1315     BCMX_LOCAL_UNIT_ITER(bcm_unit, unit_cntr) {
   1316         tmp_rv = bcm_l3_ip6_prefix_map_add(bcm_unit, ip6_addr);
   1317         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1318     }
   1319 
   1320     return rv;
   1321 }
   1322 
   1323 int bcmx_l3_ip6_prefix_map_delete(bcm_ip6_t ip6_addr) 
   1324 {
   1325     int rv = BCM_E_UNAVAIL;    /* Overall operation result.      */
   1326     int tmp_rv;                /* Unit operation result.         */
   1327     int unit_cntr;             /* Number of devices counter.     */
   1328     int bcm_unit;              /* bcm device iterator.           */
   1329 
   1330     BCMX_L3_INIT_CHECK;
   1331 
   1332     BCMX_LOCAL_UNIT_ITER(bcm_unit, unit_cntr) {
   1333         tmp_rv = bcm_l3_ip6_prefix_map_delete(bcm_unit, ip6_addr);
   1334         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1335     }
   1336 
   1337     return rv;
   1338 }
   1339 
   1340 int bcmx_l3_ip6_prefix_map_delete_all(void) 
   1341 {
   1342     int rv = BCM_E_UNAVAIL;    /* Overall operation result.      */
   1343     int tmp_rv;                /* Unit operation result.         */
   1344     int unit_cntr;             /* Number of devices counter.     */
   1345     int bcm_unit;              /* bcm device iterator.           */
   1346 
   1347     BCMX_L3_INIT_CHECK;
   1348 
   1349     BCMX_LOCAL_UNIT_ITER(bcm_unit, unit_cntr) {
   1350         tmp_rv = bcm_l3_ip6_prefix_map_delete_all(bcm_unit);
   1351         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1352     }
   1353 
   1354     return rv;
   1355 }
   1356 
   1357 /**************************************************************
   1358  * bcmx_l3_host_xxx
   1359  */
   1360 
   1361 /*
   1362  * Function:
   1363  *     bcmx_l3_host_find
   1364  */
   1365 
   1366 int
   1367 bcmx_l3_host_find(bcmx_l3_host_t *info)
   1368 {
   1369     int rv = BCM_E_UNAVAIL, tmp_rv;
   1370     int i, bcm_unit;
   1371     bcm_l3_host_t bcm_l3;
   1372     uint32 merged_flags = 0;
   1373 
   1374     BCMX_L3_INIT_CHECK;
   1375 
   1376     BCMX_PARAM_NULL_CHECK(info);
   1377 
   1378     BCM_IF_ERROR_RETURN(_bcmx_l3ip_to_bcm(info, &bcm_l3, FALSE));
   1379 
   1380     BCMX_UNIT_ITER(bcm_unit, i) {
   1381         tmp_rv = bcm_l3_host_find(bcm_unit, &bcm_l3);
   1382         if (BCMX_L3_GET_IS_VALID(bcm_unit, tmp_rv)) {
   1383             rv = tmp_rv;
   1384             if (BCM_SUCCESS(rv)) {
   1385                 merged_flags |= bcm_l3.l3a_flags;
   1386             } else {
   1387                 break;
   1388             }
   1389         }
   1390         /* bcm_l3_host_find() may overwrite input flags */
   1391         bcm_l3.l3a_flags = info->l3a_flags;
   1392     }
   1393     
   1394     if (BCM_SUCCESS(rv)) {
   1395         bcm_l3.l3a_flags  |= merged_flags;
   1396         BCM_IF_ERROR_RETURN(_bcmx_l3ip_from_bcm(info, &bcm_l3));
   1397     }
   1398 
   1399     return rv;
   1400 }
   1401 
   1402 /*
   1403  * Function:
   1404  *     bcmx_l3_host_add
   1405  */
   1406 
   1407 int
   1408 bcmx_l3_host_add(bcmx_l3_host_t *info)
   1409 {
   1410     int rv = BCM_E_UNAVAIL, tmp_rv;
   1411     int i, bcm_unit;
   1412     bcm_l3_host_t bcm_l3;
   1413     int map_local_cpu;  /* Is local CPU port mapping required? */
   1414     bcmx_lport_t cpu_lport;
   1415 
   1416     BCMX_L3_INIT_CHECK;
   1417 
   1418     BCMX_PARAM_NULL_CHECK(info);
   1419 
   1420     map_local_cpu = ((!(info->l3a_flags & BCM_L3_TGID)) &&
   1421                      (info->l3a_lport == BCMX_LPORT_LOCAL_CPU));
   1422     BCM_IF_ERROR_RETURN(_bcmx_l3ip_to_bcm(info, &bcm_l3, TRUE));
   1423 
   1424     BCMX_UNIT_ITER(bcm_unit, i) {
   1425         if (map_local_cpu) {
   1426             cpu_lport = BCMX_LPORT_LOCAL_CPU_GET(bcm_unit);
   1427             if (BCM_FAILURE
   1428                 (_bcmx_dest_to_modid_port(cpu_lport,
   1429                                           &bcm_l3.l3a_modid,
   1430                                           &bcm_l3.l3a_port_tgid,
   1431                                           BCMX_DEST_CONVERT_DEFAULT))) {
   1432                 /* Skip if can't find local CPU port */
   1433                 continue;
   1434             }
   1435         }
   1436         tmp_rv = bcm_l3_host_add(bcm_unit, &bcm_l3);
   1437         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1438     }
   1439 
   1440     return rv;
   1441 }
   1442 
   1443 /*
   1444  * Function:
   1445  *     bcmx_l3_host_delete
   1446  */
   1447 
   1448 int
   1449 bcmx_l3_host_delete(bcmx_l3_host_t *ip_addr)
   1450 {
   1451     int rv = BCM_E_UNAVAIL, tmp_rv;
   1452     int i, bcm_unit;
   1453     bcm_l3_host_t bcm_l3;
   1454 
   1455     BCMX_L3_INIT_CHECK;
   1456 
   1457     BCMX_PARAM_NULL_CHECK(ip_addr);
   1458 
   1459     BCM_IF_ERROR_RETURN(_bcmx_l3ip_to_bcm(ip_addr, &bcm_l3, FALSE));
   1460 
   1461     BCMX_UNIT_ITER(bcm_unit, i) {
   1462         tmp_rv = bcm_l3_host_delete(bcm_unit, &bcm_l3);
   1463         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1464     }
   1465 
   1466     return rv;
   1467 }
   1468 
   1469 /*
   1470  * Function:
   1471  *     bcmx_l3_host_delete_by_network
   1472  */
   1473 
   1474 int
   1475 bcmx_l3_host_delete_by_network(bcmx_l3_route_t *route)
   1476 {
   1477     int rv = BCM_E_UNAVAIL, tmp_rv;
   1478     int i, bcm_unit;
   1479     bcm_l3_route_t l3_route;
   1480 
   1481     BCMX_L3_INIT_CHECK;
   1482 
   1483     BCMX_PARAM_NULL_CHECK(route);
   1484 
   1485     BCM_IF_ERROR_RETURN(_bcmx_l3route_to_bcm(route, &l3_route, FALSE));
   1486 
   1487     BCMX_UNIT_ITER(bcm_unit, i) {
   1488         tmp_rv = bcm_l3_host_delete_by_network(bcm_unit, &l3_route);
   1489         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1490     }
   1491 
   1492     return rv;
   1493 }
   1494 
   1495 /*
   1496  * Function:
   1497  *     bcmx_l3_host_delete_by_interface
   1498  */
   1499 
   1500 int
   1501 bcmx_l3_host_delete_by_interface(bcmx_l3_host_t *info)
   1502 {
   1503     int rv = BCM_E_UNAVAIL, tmp_rv;
   1504     int i, bcm_unit;
   1505     bcm_l3_host_t bcm_l3;
   1506 
   1507     BCMX_L3_INIT_CHECK;
   1508 
   1509     BCMX_PARAM_NULL_CHECK(info);
   1510 
   1511     BCM_IF_ERROR_RETURN(_bcmx_l3ip_to_bcm(info, &bcm_l3, FALSE));
   1512 
   1513     BCMX_UNIT_ITER(bcm_unit, i) {
   1514         tmp_rv = bcm_l3_host_delete_by_interface(bcm_unit, &bcm_l3);
   1515         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1516     }
   1517 
   1518     return rv;
   1519 }
   1520 
   1521 /*
   1522  * Function:
   1523  *     bcmx_l3_host_delete_all
   1524  */
   1525 
   1526 int
   1527 bcmx_l3_host_delete_all(bcmx_l3_host_t *info)
   1528 {
   1529     int rv = BCM_E_UNAVAIL, tmp_rv;
   1530     int i, bcm_unit;
   1531     bcm_l3_host_t bcm_l3;
   1532 
   1533     BCMX_L3_INIT_CHECK;
   1534 
   1535     BCMX_PARAM_NULL_CHECK(info);
   1536 
   1537     BCM_IF_ERROR_RETURN(_bcmx_l3ip_to_bcm(info, &bcm_l3, FALSE));
   1538 
   1539     BCMX_UNIT_ITER(bcm_unit, i) {
   1540         tmp_rv = bcm_l3_host_delete_all(bcm_unit, &bcm_l3);
   1541         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1542     }
   1543 
   1544     return rv;
   1545 }
   1546 
   1547 /*
   1548  * Function:
   1549  *     bcmx_l3_host_conflict_get
   1550  */
   1551 
   1552 int
   1553 bcmx_l3_host_conflict_get(bcm_l3_key_t *ipkey,
   1554                           bcm_l3_key_t *cf_array,
   1555                           int cf_max,
   1556                           int *cf_count)
   1557 {
   1558     int rv;
   1559     int i, bcm_unit;
   1560 
   1561     BCMX_L3_INIT_CHECK;
   1562 
   1563     BCMX_PARAM_NULL_CHECK(ipkey);
   1564     BCMX_PARAM_NULL_CHECK(cf_count);
   1565     BCMX_PARAM_ARRAY_NULL_CHECK(cf_max, cf_array);
   1566 
   1567     BCMX_UNIT_ITER(bcm_unit, i) {
   1568         rv = bcm_l3_host_conflict_get(bcm_unit, ipkey,
   1569                                           cf_array, cf_max, cf_count);
   1570         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
   1571             return rv;
   1572         }
   1573     }
   1574 
   1575     return BCM_E_UNAVAIL;
   1576 }
   1577 
   1578 /*
   1579  * Function:
   1580  *     bcmx_l3_host_age
   1581  */
   1582 
   1583 int
   1584 bcmx_l3_host_age(uint32 flags,
   1585                  bcm_l3_host_traverse_cb age_cb,
   1586                  void *user_data)
   1587 {
   1588     return BCM_E_UNAVAIL;
   1589 }
   1590 
   1591 /*
   1592  * Function:
   1593  *    bcmx_l3_host_traverse
   1594  */
   1595 
   1596 int
   1597 bcmx_l3_host_traverse(uint32 flags,
   1598                       uint32 start,
   1599                       uint32 end,
   1600                       bcm_l3_host_traverse_cb cb,
   1601                       void *user_data)
   1602 {
   1603     int rv;
   1604     int i, bcm_unit;
   1605 
   1606     BCMX_L3_INIT_CHECK;
   1607 
   1608     BCMX_LOCAL_UNIT_ITER(bcm_unit, i) {
   1609         rv = bcm_l3_host_traverse(bcm_unit,
   1610                                   flags, start, end,
   1611                                   cb, user_data);
   1612         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
   1613             return rv;
   1614         }
   1615     }
   1616 
   1617     return BCM_E_UNAVAIL;
   1618 }
   1619 
   1620 /*
   1621  * Function:
   1622  *     bcmx_l3_host_invalidate_entry
   1623  */
   1624 
   1625 int
   1626 bcmx_l3_host_invalidate_entry(bcm_ip_t info)
   1627 {
   1628     int rv = BCM_E_UNAVAIL, tmp_rv;
   1629     int i, bcm_unit;
   1630 
   1631     BCMX_L3_INIT_CHECK;
   1632 
   1633     BCMX_UNIT_ITER(bcm_unit, i) {
   1634         tmp_rv = bcm_l3_host_invalidate_entry(bcm_unit, info);
   1635         BCM_IF_ERROR_RETURN(BCMX_L3_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1636     }
   1637 
   1638     return rv;
   1639 }
   1640 
   1641 /*
   1642  * Function:
   1643  *     bcmx_l3_host_validate_entry
   1644  */
   1645 
   1646 int
   1647 bcmx_l3_host_validate_entry(bcm_ip_t info)
   1648 {
   1649     int rv = BCM_E_UNAVAIL, tmp_rv;
   1650     int i, bcm_unit;
   1651 
   1652     BCMX_L3_INIT_CHECK;
   1653 
   1654     BCMX_UNIT_ITER(bcm_unit, i) {
   1655         tmp_rv = bcm_l3_host_validate_entry(bcm_unit, info);
   1656         BCM_IF_ERROR_RETURN(BCMX_L3_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1657     }
   1658 
   1659     return rv;
   1660 }
   1661 
   1662 /**************************************************************
   1663  * bcmx_l3_route_xxx
   1664  */
   1665 
   1666 /*
   1667  * Function:
   1668  *     bcmx_l3_route_add
   1669  */
   1670 
   1671 int
   1672 bcmx_l3_route_add(bcmx_l3_route_t *info)
   1673 {
   1674     int rv = BCM_E_UNAVAIL, tmp_rv;
   1675     int i, bcm_unit;
   1676     bcm_l3_route_t l3_route;
   1677     int map_local_cpu;  /* Is local CPU port mapping required? */
   1678     bcmx_lport_t cpu_lport;
   1679 
   1680     BCMX_L3_INIT_CHECK;
   1681 
   1682     BCMX_PARAM_NULL_CHECK(info);
   1683 
   1684     map_local_cpu = ((!(info->l3a_flags & BCM_L3_TGID)) &&
   1685                      (info->l3a_lport == BCMX_LPORT_LOCAL_CPU));
   1686 
   1687     BCM_IF_ERROR_RETURN(_bcmx_l3route_to_bcm(info, &l3_route, TRUE));
   1688 
   1689     BCMX_UNIT_ITER(bcm_unit, i) {
   1690         if (map_local_cpu) {
   1691             cpu_lport = BCMX_LPORT_LOCAL_CPU_GET(bcm_unit);
   1692             if (BCM_FAILURE
   1693                 (_bcmx_dest_to_modid_port(cpu_lport,
   1694                                           &l3_route.l3a_modid,
   1695                                           &l3_route.l3a_port_tgid,
   1696                                           BCMX_DEST_CONVERT_DEFAULT))) {
   1697                 /* Skip if can't find local CPU port */
   1698                 continue;
   1699             }
   1700         }
   1701         tmp_rv = bcm_l3_route_add(bcm_unit, &l3_route);
   1702         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1703     }
   1704 
   1705     return rv;
   1706 }
   1707 
   1708 /*
   1709  * Function:
   1710  *     bcmx_l3_route_delete
   1711  */
   1712 
   1713 int
   1714 bcmx_l3_route_delete(bcmx_l3_route_t *info)
   1715 {
   1716     int rv = BCM_E_UNAVAIL, tmp_rv;
   1717     int i, bcm_unit;
   1718     bcm_l3_route_t l3_route;
   1719 
   1720     BCMX_L3_INIT_CHECK;
   1721 
   1722     BCMX_PARAM_NULL_CHECK(info);
   1723 
   1724     /* See bcm_l3_route_delete()
   1725        l3a_port_tgid is an input field if BCM_L3_MULTIPATH
   1726        is set. */
   1727     BCM_IF_ERROR_RETURN
   1728         (_bcmx_l3route_to_bcm(info, &l3_route,
   1729                               info->l3a_flags & BCM_L3_MULTIPATH));
   1730 
   1731     BCMX_UNIT_ITER(bcm_unit, i) {
   1732         tmp_rv = bcm_l3_route_delete(bcm_unit, &l3_route);
   1733         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1734     }
   1735 
   1736     return rv;
   1737 }
   1738 
   1739 /*
   1740  * Function:
   1741  *     bcmx_l3_route_delete_by_interface
   1742  */
   1743 
   1744 int
   1745 bcmx_l3_route_delete_by_interface(bcmx_l3_route_t *info)
   1746 {
   1747     int rv = BCM_E_UNAVAIL, tmp_rv;
   1748     int i, bcm_unit;
   1749     bcm_l3_route_t l3_route;
   1750 
   1751     BCMX_L3_INIT_CHECK;
   1752 
   1753     BCMX_PARAM_NULL_CHECK(info);
   1754 
   1755     BCM_IF_ERROR_RETURN(_bcmx_l3route_to_bcm(info, &l3_route, FALSE));
   1756 
   1757     BCMX_UNIT_ITER(bcm_unit, i) {
   1758         tmp_rv = bcm_l3_route_delete_by_interface(bcm_unit, &l3_route);
   1759         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1760     }
   1761 
   1762     return rv;
   1763 }
   1764 
   1765 /*
   1766  * Function:
   1767  *     bcmx_l3_route_delete_all
   1768  */
   1769 
   1770 int
   1771 bcmx_l3_route_delete_all(bcmx_l3_route_t *info)
   1772 {
   1773     int rv = BCM_E_UNAVAIL, tmp_rv;
   1774     int i, bcm_unit;
   1775     bcm_l3_route_t l3_route;
   1776 
   1777     BCMX_L3_INIT_CHECK;
   1778 
   1779     BCMX_PARAM_NULL_CHECK(info);
   1780 
   1781     BCM_IF_ERROR_RETURN(_bcmx_l3route_to_bcm(info, &l3_route, FALSE));
   1782 
   1783     BCMX_UNIT_ITER(bcm_unit, i) {
   1784         tmp_rv = bcm_l3_route_delete_all(bcm_unit, &l3_route);
   1785         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1786     }
   1787 
   1788     return rv;
   1789 }
   1790 
   1791 /*
   1792  * Function:
   1793  *     bcmx_l3_route_get
   1794  */
   1795 
   1796 int
   1797 bcmx_l3_route_get(bcmx_l3_route_t *info)
   1798 {
   1799     int rv = BCM_E_UNAVAIL, tmp_rv;
   1800     int i, bcm_unit;
   1801     bcm_l3_route_t l3_route;
   1802     uint32 merged_flags = 0;
   1803 
   1804     BCMX_L3_INIT_CHECK;
   1805 
   1806     BCMX_PARAM_NULL_CHECK(info);
   1807 
   1808     BCM_IF_ERROR_RETURN(_bcmx_l3route_to_bcm(info, &l3_route, FALSE));
   1809 
   1810     BCMX_UNIT_ITER(bcm_unit, i) {
   1811         tmp_rv = bcm_l3_route_get(bcm_unit, &l3_route);
   1812         if (BCMX_L3_GET_IS_VALID(bcm_unit, tmp_rv)) {
   1813             rv = tmp_rv;
   1814             if (BCM_SUCCESS(tmp_rv)) {
   1815                 merged_flags |= l3_route.l3a_flags;
   1816             } else {
   1817                 break;
   1818             }
   1819         }
   1820         /* bcm_l3_route_get() may overwrite input flags */
   1821         l3_route.l3a_flags = info->l3a_flags;
   1822     }
   1823 
   1824     if (BCM_SUCCESS(rv)) {
   1825         l3_route.l3a_flags  |= merged_flags;
   1826         BCM_IF_ERROR_RETURN(_bcmx_l3route_from_bcm(info, &l3_route));
   1827     }
   1828 
   1829     return rv;
   1830 }
   1831 
   1832 /*
   1833  * Function:
   1834  *     bcmx_l3_route_multipath_get
   1835  */
   1836 
   1837 int
   1838 bcmx_l3_route_multipath_get(bcmx_l3_route_t *the_route,
   1839                             bcmx_l3_route_t *path_array,
   1840                             int max_path,
   1841                             int *path_count)
   1842 {
   1843     int rv = BCM_E_UNAVAIL, tmp_rv;
   1844     int i, bcm_unit;
   1845     bcm_l3_route_t l3_route, *l3_route_array, *l3p;
   1846     int num_bcm_path = 0;
   1847 
   1848     BCMX_L3_INIT_CHECK;
   1849 
   1850     BCMX_PARAM_NULL_CHECK(the_route);
   1851     BCMX_PARAM_NULL_CHECK(path_count);
   1852     BCMX_PARAM_ARRAY_NULL_CHECK(max_path, path_array);
   1853 
   1854     BCM_IF_ERROR_RETURN(_bcmx_l3route_to_bcm(the_route, &l3_route, FALSE));
   1855 
   1856     l3_route_array = sal_alloc(sizeof(bcm_l3_route_t) * max_path,
   1857                                "BCMX_L3_RGAP");
   1858     if (l3_route_array == NULL) {
   1859         return BCM_E_MEMORY;
   1860     }
   1861 
   1862     /* Init route array structs */
   1863     for (i=0; i<max_path; i++ ) {
   1864         bcm_l3_route_t_init(l3_route_array + i);
   1865     }
   1866 
   1867     l3p = l3_route_array;
   1868 
   1869     BCMX_UNIT_ITER(bcm_unit, i) {
   1870         tmp_rv = bcm_l3_route_multipath_get(bcm_unit, &l3_route,
   1871                                            l3p,
   1872                                            max_path,
   1873                                            &num_bcm_path);
   1874         if (BCMX_L3_GET_IS_VALID(bcm_unit, tmp_rv)) {
   1875             rv = tmp_rv;
   1876             break;
   1877         }
   1878     }
   1879 
   1880     if (BCM_SUCCESS(rv)) {
   1881         /* Convert bcm routes to bcmx */
   1882         for (i=0, l3p=l3_route_array; i<num_bcm_path; i++) {
   1883             rv = _bcmx_l3route_from_bcm(path_array+i, l3p+i);
   1884         }
   1885     } else {
   1886         num_bcm_path = 0;
   1887     }
   1888 
   1889     *path_count = num_bcm_path;
   1890     sal_free(l3_route_array);
   1891 
   1892     return rv;
   1893 }
   1894 
   1895 /*
   1896  * Function:
   1897  *     bcmx_l3_route_age
   1898  */
   1899 
   1900 int
   1901 bcmx_l3_route_age(uint32 flags,
   1902                   bcm_l3_route_traverse_cb age_out,
   1903                   void *user_data)
   1904 {
   1905     return BCM_E_UNAVAIL;
   1906 }
   1907 
   1908 /*
   1909  * Function:
   1910  *     bcmx_l3_route_traverse
   1911  */
   1912 
   1913 int
   1914 bcmx_l3_route_traverse(uint32 flags,
   1915                        uint32 start,
   1916                        uint32 end,
   1917                        bcm_l3_route_traverse_cb trav_fn,
   1918                        void *user_data)
   1919 {
   1920     int rv;
   1921     int i, bcm_unit;
   1922 
   1923     BCMX_L3_INIT_CHECK;
   1924 
   1925     BCMX_LOCAL_UNIT_ITER(bcm_unit, i) {
   1926         rv = bcm_l3_route_traverse(bcm_unit,
   1927                                    flags, start, end,
   1928                                    trav_fn, user_data);
   1929         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
   1930             return rv;
   1931         }
   1932     }
   1933 
   1934     return BCM_E_UNAVAIL;
   1935 }
   1936 
   1937 /*
   1938  * Function:
   1939  *     bcmx_l3_route_max_ecmp_set
   1940  */
   1941 
   1942 int
   1943 bcmx_l3_route_max_ecmp_set(int max)
   1944 {
   1945     int rv = BCM_E_UNAVAIL, tmp_rv;
   1946     int i, bcm_unit;
   1947 
   1948     BCMX_L3_INIT_CHECK;
   1949 
   1950     BCMX_UNIT_ITER(bcm_unit, i) {
   1951         tmp_rv = bcm_l3_route_max_ecmp_set(bcm_unit, max);
   1952         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   1953     }
   1954 
   1955     return rv;
   1956 }
   1957 
   1958 /*
   1959  * Function:
   1960  *     bcmx_l3_route_max_ecmp_get
   1961  */
   1962 
   1963 int
   1964 bcmx_l3_route_max_ecmp_get(int *max)
   1965 {
   1966     int rv = BCM_E_UNAVAIL, tmp_rv;
   1967     int i, bcm_unit;
   1968     int tmp_max;
   1969 
   1970     BCMX_L3_INIT_CHECK;
   1971 
   1972     BCMX_PARAM_NULL_CHECK(max);
   1973 
   1974     /* Get the minimum value of all units */
   1975     *max = 0;
   1976     BCMX_UNIT_ITER(bcm_unit, i) {
   1977         tmp_rv = bcm_l3_route_max_ecmp_get(bcm_unit, &tmp_max);
   1978 
   1979         if (BCMX_L3_GET_IS_VALID(bcm_unit, tmp_rv)) {
   1980             rv = tmp_rv;
   1981             BCM_IF_ERROR_RETURN(rv);
   1982             if ((*max == 0) || (tmp_max < *max)) {
   1983                 *max = tmp_max;
   1984             }
   1985         }
   1986     }
   1987 
   1988     return rv;
   1989 }
   1990 
   1991 /**************************************************************
   1992  * bcmx_l3_defip_xxx (superseded by bcmx_l3_route_xxx)
   1993  */
   1994 
   1995 
   1996 /*
   1997  * Function:
   1998  *      bcmx_l3_vrf_stat_enable_set
   1999  * Purpose:
   2000  *      Enable/disable packet and byte counters for the selected VRF.
   2001  * Parameters:
   2002  *      vrf    - Virtual router instance
   2003  *      enable - Non-zero to enable counter collection, zero to disable
   2004  * Returns:
   2005  *      BCM_E_XXX
   2006  * Notes:
   2007  */
   2008 int
   2009 bcmx_l3_vrf_stat_enable_set(bcm_vrf_t vrf, int enable)
   2010 {
   2011     int  rv = BCM_E_UNAVAIL, tmp_rv;
   2012     int  i, bcm_unit;
   2013 
   2014     BCMX_L3_INIT_CHECK;
   2015 
   2016     BCMX_UNIT_ITER(bcm_unit, i) {
   2017         tmp_rv = bcm_l3_vrf_stat_enable_set(bcm_unit, vrf, enable);
   2018         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   2019     }
   2020 
   2021     return rv;
   2022 }
   2023 
   2024 /*
   2025  * Function:
   2026  *      bcmx_l3_vrf_stat_get
   2027  * Purpose:
   2028  *      Get 64-bit counter value for specified VRF statistic type.
   2029  * Parameters:
   2030  *      vrf  - Virtual router instance
   2031  *      stat - Type of the counter to retrieve
   2032  *      val  - (OUT) Pointer to a counter value
   2033  * Returns:
   2034  *      BCM_E_XXX
   2035  * Notes:
   2036  */
   2037 int
   2038 bcmx_l3_vrf_stat_get(bcm_vrf_t vrf, bcm_l3_vrf_stat_t stat, uint64 *val)
   2039 {
   2040     int     rv = BCM_E_UNAVAIL, tmp_rv;
   2041     int     i, bcm_unit;
   2042     uint64  tmp_val;
   2043 
   2044     BCMX_L3_INIT_CHECK;
   2045 
   2046     BCMX_PARAM_NULL_CHECK(val);
   2047 
   2048     COMPILER_64_ZERO(*val);
   2049     BCMX_UNIT_ITER(bcm_unit, i) {
   2050         tmp_rv = bcm_l3_vrf_stat_get(bcm_unit, vrf, stat, &tmp_val);
   2051 
   2052         if (BCMX_L3_GET_IS_VALID(bcm_unit, tmp_rv)) {
   2053             rv = tmp_rv;
   2054             if (BCM_SUCCESS(tmp_rv)) {
   2055                 COMPILER_64_ADD_64(*val, tmp_val);
   2056             } else {
   2057                 break;
   2058             }
   2059         }
   2060     }
   2061 
   2062     return rv;
   2063 }
   2064      
   2065 /*
   2066  * Function:
   2067  *      bcmx_l3_vrf_stat_get32
   2068  * Purpose:
   2069  *      Get lower 32-bit counter value for specified VRF statistic
   2070  *      type.
   2071  * Parameters:
   2072  *      vrf  - Virtual router instance
   2073  *      stat - Type of the counter to retrieve
   2074  *      val  - (OUT) Pointer to a counter value
   2075  * Returns:
   2076  *      BCM_E_XXX
   2077  * Notes:
   2078  */
   2079 int
   2080 bcmx_l3_vrf_stat_get32(bcm_vrf_t vrf, bcm_l3_vrf_stat_t stat, uint32 *val)
   2081 {
   2082     int     rv = BCM_E_UNAVAIL, tmp_rv;
   2083     int     i, bcm_unit;
   2084     uint32  tmp_val;
   2085 
   2086     BCMX_L3_INIT_CHECK;
   2087 
   2088     BCMX_PARAM_NULL_CHECK(val);
   2089 
   2090     *val = 0;
   2091     BCMX_UNIT_ITER(bcm_unit, i) {
   2092         tmp_rv = bcm_l3_vrf_stat_get32(bcm_unit, vrf, stat, &tmp_val);
   2093 
   2094         if (BCMX_L3_GET_IS_VALID(bcm_unit, tmp_rv)) {
   2095             rv = tmp_rv;
   2096             if (BCM_SUCCESS(tmp_rv)) {
   2097                 *val += tmp_val;
   2098             } else {
   2099                 break;
   2100             }
   2101         }
   2102     }
   2103 
   2104     return rv;
   2105 }
   2106 
   2107 /*
   2108  * Function:
   2109  *      bcmx_l3_vrf_stat_set
   2110  * Purpose:
   2111  *      Set 64-bit counter value for specified VRF statistic type.
   2112  * Parameters:
   2113  *      vrf  - Virtual router instance
   2114  *      stat - Type of the counter to set
   2115  *      val  - New counter value
   2116  * Returns:
   2117  *      BCM_E_XXX
   2118  * Notes:
   2119  */
   2120 int
   2121 bcmx_l3_vrf_stat_set(bcm_vrf_t vrf, bcm_l3_vrf_stat_t stat, uint64 val)
   2122 {
   2123     int  rv = BCM_E_UNAVAIL, tmp_rv;
   2124     int  i, bcm_unit;
   2125 
   2126     BCMX_L3_INIT_CHECK;
   2127 
   2128     BCMX_UNIT_ITER(bcm_unit, i) {
   2129         tmp_rv = bcm_l3_vrf_stat_set(bcm_unit, vrf, stat, val);
   2130         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   2131     }
   2132 
   2133     return rv;
   2134 }
   2135 
   2136 /*
   2137  * Function:
   2138  *      bcmx_l3_vrf_stat_set32
   2139  * Purpose:
   2140  *      Set 32-bit counter value for specified VRF statistic type.
   2141  * Parameters:
   2142  *      vrf  - Virtual router instance
   2143  *      stat - Type of the counter to set
   2144  *      val  - New counter value
   2145  * Returns:
   2146  *      BCM_E_XXX
   2147  * Notes:
   2148  */
   2149 int
   2150 bcmx_l3_vrf_stat_set32(bcm_vrf_t vrf, bcm_l3_vrf_stat_t stat, uint32 val)
   2151 {
   2152     int  rv = BCM_E_UNAVAIL, tmp_rv;
   2153     int  i, bcm_unit;
   2154 
   2155     BCMX_L3_INIT_CHECK;
   2156 
   2157     BCMX_UNIT_ITER(bcm_unit, i) {
   2158         tmp_rv = bcm_l3_vrf_stat_set32(bcm_unit, vrf, stat, val);
   2159         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   2160     }
   2161 
   2162     return rv;
   2163 }
   2164 
   2165 /*
   2166  * Function:
   2167  *      bcmx_l3_vrf_stat_multi_get
   2168  * Purpose:
   2169  *      Get 64-bit counter value for multiple VRF statistic types.
   2170  * Parameters:
   2171  *      vrf       - Virtual router instance
   2172  *      nstat     - Number of elements in stat array
   2173  *      stat_arr  - Collected statistics descriptors array
   2174  *      value_arr - (OUT) Collected counters values
   2175  * Returns:
   2176  *      BCM_E_XXX
   2177  * Notes:
   2178  */
   2179 int
   2180 bcmx_l3_vrf_stat_multi_get(bcm_vrf_t vrf, int nstat, 
   2181                            bcm_l3_vrf_stat_t *stat_arr, uint64 *value_arr)
   2182 {
   2183     int     rv = BCM_E_UNAVAIL, tmp_rv;
   2184     int     i, bcm_unit;
   2185     uint64  *tmp_val;
   2186 
   2187     BCMX_L3_INIT_CHECK;
   2188 
   2189     BCMX_PARAM_ARRAY_NULL_CHECK(nstat, stat_arr);
   2190     BCMX_PARAM_ARRAY_NULL_CHECK(nstat, value_arr);
   2191 
   2192     tmp_val = sal_alloc(sizeof(uint64) * nstat, "bcmx l3 vrf stat");
   2193     if (tmp_val == NULL) {
   2194         return BCM_E_MEMORY;
   2195     }
   2196 
   2197     for (i = 0; i < nstat; i++) {
   2198         COMPILER_64_ZERO(value_arr[i]);
   2199     }
   2200     BCMX_UNIT_ITER(bcm_unit, i) {
   2201         tmp_rv = bcm_l3_vrf_stat_multi_get(bcm_unit, vrf, nstat,
   2202                                            stat_arr, tmp_val);
   2203         if (BCMX_L3_GET_IS_VALID(bcm_unit, tmp_rv)) {
   2204             rv = tmp_rv;
   2205             if (BCM_SUCCESS(tmp_rv)) {
   2206                 for (i = 0; i < nstat; i++) {
   2207                     COMPILER_64_ADD_64(value_arr[i], tmp_val[i]);
   2208                 }
   2209             } else {
   2210                 break;
   2211             }
   2212         }
   2213     }
   2214 
   2215     sal_free(tmp_val);
   2216 
   2217     return rv;
   2218 }
   2219      
   2220 /*
   2221  * Function:
   2222  *      bcmx_l3_vrf_stat_multi_get32
   2223  * Purpose:
   2224  *      Get lower 32-bit counter value for multiple VRF statistic types.
   2225  * Parameters:
   2226  *      vrf       - Virtual router instance
   2227  *      nstat     - Number of elements in stat array
   2228  *      stat_arr  - Collected statistics descriptors array
   2229  *      value_arr - (OUT) Collected counters values
   2230  * Returns:
   2231  *      BCM_E_XXX
   2232  * Notes:
   2233  */
   2234 int
   2235 bcmx_l3_vrf_stat_multi_get32(bcm_vrf_t vrf, int nstat,
   2236                              bcm_l3_vrf_stat_t *stat_arr, uint32 *value_arr)
   2237 {
   2238     int     rv = BCM_E_UNAVAIL, tmp_rv;
   2239     int     i, bcm_unit;
   2240     uint32  *tmp_val;
   2241 
   2242     BCMX_L3_INIT_CHECK;
   2243 
   2244     BCMX_PARAM_ARRAY_NULL_CHECK(nstat, stat_arr);
   2245     BCMX_PARAM_ARRAY_NULL_CHECK(nstat, value_arr);
   2246 
   2247     tmp_val = sal_alloc(sizeof(uint32) * nstat, "bcmx l3 vrf stat");
   2248     if (tmp_val == NULL) {
   2249         return BCM_E_MEMORY;
   2250     }
   2251 
   2252     for (i = 0; i < nstat; i++) {
   2253         value_arr[i] = 0;
   2254     }
   2255     BCMX_UNIT_ITER(bcm_unit, i) {
   2256         tmp_rv = bcm_l3_vrf_stat_multi_get32(bcm_unit, vrf, nstat,
   2257                                              stat_arr, tmp_val);
   2258         if (BCMX_L3_GET_IS_VALID(bcm_unit, tmp_rv)) {
   2259             rv = tmp_rv;
   2260             if (BCM_SUCCESS(tmp_rv)) {
   2261                 for (i = 0; i < nstat; i++) {
   2262                     value_arr[i] += tmp_val[i];
   2263                 }
   2264             } else {
   2265                 break;
   2266             }
   2267         }
   2268     }
   2269 
   2270     sal_free(tmp_val);
   2271 
   2272     return rv;
   2273 }
   2274      
   2275 /*
   2276  * Function:
   2277  *      bcmx_l3_vrf_stat_multi_set
   2278  * Purpose:
   2279  *      Set 64-bit counter value for multiple VRF statistic types.
   2280  * Parameters:
   2281  *      vrf       - Virtual router instance
   2282  *      nstat     - Number of elements in stat array
   2283  *      stat_arr  - New statistics descriptors array
   2284  *      value_arr - New counters values to set
   2285  * Returns:
   2286  *      BCM_E_XXX
   2287  * Notes:
   2288  */
   2289 int
   2290 bcmx_l3_vrf_stat_multi_set(bcm_vrf_t vrf, int nstat,
   2291                            bcm_l3_vrf_stat_t *stat_arr, uint64 *value_arr)
   2292 {
   2293     int  rv = BCM_E_UNAVAIL, tmp_rv;
   2294     int  i, bcm_unit;
   2295 
   2296     BCMX_L3_INIT_CHECK;
   2297 
   2298     BCMX_PARAM_ARRAY_NULL_CHECK(nstat, stat_arr);
   2299     BCMX_PARAM_ARRAY_NULL_CHECK(nstat, value_arr);
   2300 
   2301     BCMX_UNIT_ITER(bcm_unit, i) {
   2302         tmp_rv = bcm_l3_vrf_stat_multi_set(bcm_unit, vrf, nstat,
   2303                                            stat_arr, value_arr);
   2304         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   2305     }
   2306 
   2307     return rv;
   2308 }
   2309 
   2310 /*
   2311  * Function:
   2312  *      bcmx_l3_vrf_stat_multi_set32
   2313  * Purpose:
   2314  *      Set lower 32-bit counter value for multiple VRF statistic types.
   2315  * Parameters:
   2316  *      vrf       - Virtual router instance
   2317  *      nstat     - Number of elements in stat array
   2318  *      stat_arr  - New statistics descriptors array
   2319  *      value_arr - New counters values to set
   2320  * Returns:
   2321  *      BCM_E_XXX
   2322  * Notes:
   2323  */
   2324 int
   2325 bcmx_l3_vrf_stat_multi_set32(bcm_vrf_t vrf, int nstat,
   2326                              bcm_l3_vrf_stat_t *stat_arr, uint32 *value_arr)
   2327 {
   2328     int  rv = BCM_E_UNAVAIL, tmp_rv;
   2329     int  i, bcm_unit;
   2330 
   2331     BCMX_L3_INIT_CHECK;
   2332 
   2333     BCMX_PARAM_ARRAY_NULL_CHECK(nstat, stat_arr);
   2334     BCMX_PARAM_ARRAY_NULL_CHECK(nstat, value_arr);
   2335 
   2336     BCMX_UNIT_ITER(bcm_unit, i) {
   2337         tmp_rv = bcm_l3_vrf_stat_multi_set32(bcm_unit, vrf, nstat,
   2338                                              stat_arr, value_arr);
   2339         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   2340     }
   2341 
   2342     return rv;
   2343 }
   2344 
   2345 
   2346 /*
   2347  * Function:
   2348  *      bcmx_l3_source_bind_enable_set
   2349  * Purpose:
   2350  *      Enable or disable l3 source binding checks on an ingress port.
   2351  * Parameters:
   2352  *      port   - Packet ingress logical port
   2353  *      enable - Non-zero to enable l3 source binding checks,
   2354  *               zero to disable.
   2355  * Returns:
   2356  *      BCM_E_XXX
   2357  * Notes:
   2358  */
   2359 int
   2360 bcmx_l3_source_bind_enable_set(bcm_gport_t port, int enable)
   2361 {
   2362     int         bcm_unit;
   2363     bcm_port_t  bcm_port;
   2364 
   2365     BCMX_L3_INIT_CHECK;
   2366 
   2367     BCM_IF_ERROR_RETURN
   2368         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
   2369                                  BCMX_DEST_CONVERT_DEFAULT));
   2370 
   2371     return bcm_l3_source_bind_enable_set(bcm_unit, port, enable);
   2372 }
   2373 
   2374 /*
   2375  * Function:
   2376  *      bcmx_l3_source_bind_enable_get
   2377  * Purpose:
   2378  *      Retrieve whether l3 source binding checks are performed on an
   2379  *      ingress port.
   2380  * Parameters:
   2381  *      port   - Packet ingress port.
   2382  *      enable - (OUT) Non-zero if l3 source binding checks are enabled,
   2383  *               zero if disabled.
   2384  * Returns:
   2385  *      BCM_E_XXX
   2386  * Notes:
   2387  */
   2388 int
   2389 bcmx_l3_source_bind_enable_get(bcm_gport_t port, int *enable)
   2390 {
   2391     int         bcm_unit;
   2392     bcm_port_t  bcm_port;
   2393 
   2394     BCMX_L3_INIT_CHECK;
   2395 
   2396     BCMX_PARAM_NULL_CHECK(enable);
   2397 
   2398     BCM_IF_ERROR_RETURN
   2399         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
   2400                                  BCMX_DEST_CONVERT_DEFAULT));
   2401 
   2402     return bcm_l3_source_bind_enable_get(bcm_unit, port, enable);
   2403 }
   2404 
   2405 /*
   2406  * Function:
   2407  *      bcmx_l3_source_bind_add
   2408  * Purpose:
   2409  *      Add or replace an L3 source binding.
   2410  * Parameters:
   2411  *      info - L3 source binding information
   2412  * Returns:
   2413  *      BCM_E_XXX
   2414  * Notes:
   2415  */
   2416 int
   2417 bcmx_l3_source_bind_add(bcmx_l3_source_bind_t *info)
   2418 {
   2419     int  rv = BCM_E_UNAVAIL, tmp_rv;
   2420     int  i, bcm_unit;
   2421 
   2422     BCMX_L3_INIT_CHECK;
   2423 
   2424     BCMX_PARAM_NULL_CHECK(info);
   2425 
   2426     BCMX_UNIT_ITER(bcm_unit, i) {
   2427         tmp_rv = bcm_l3_source_bind_add(bcm_unit, info);
   2428         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   2429     }
   2430 
   2431     return rv;
   2432 }
   2433 
   2434 /*
   2435  * Function:
   2436  *      bcmx_l3_source_bind_delete
   2437  * Purpose:
   2438  *      Remove an existing L3 source binding.
   2439  * Parameters:
   2440  *      info - L3 source binding information
   2441  * Returns:
   2442  *      BCM_E_XXX
   2443  * Notes:
   2444  */
   2445 int
   2446 bcmx_l3_source_bind_delete(bcmx_l3_source_bind_t *info)
   2447 {
   2448     int  rv = BCM_E_UNAVAIL, tmp_rv;
   2449     int  i, bcm_unit;
   2450 
   2451     BCMX_L3_INIT_CHECK;
   2452 
   2453     BCMX_PARAM_NULL_CHECK(info);
   2454 
   2455     BCMX_UNIT_ITER(bcm_unit, i) {
   2456         tmp_rv = bcm_l3_source_bind_delete(bcm_unit, info);
   2457         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   2458     }
   2459 
   2460     return rv;
   2461 }
   2462 
   2463 /*
   2464  * Function:
   2465  *      bcmx_l3_source_bind_delete_all
   2466  * Purpose:
   2467  *      Remove all existing L3 source bindings.
   2468  * Parameters:
   2469  *      none
   2470  * Returns:
   2471  *      BCM_E_XXX
   2472  * Notes:
   2473  */
   2474 int
   2475 bcmx_l3_source_bind_delete_all(void)
   2476 {
   2477     int  rv = BCM_E_UNAVAIL, tmp_rv;
   2478     int  i, bcm_unit;
   2479 
   2480     BCMX_L3_INIT_CHECK;
   2481 
   2482     BCMX_UNIT_ITER(bcm_unit, i) {
   2483         tmp_rv = bcm_l3_source_bind_delete_all(bcm_unit);
   2484         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   2485     }
   2486 
   2487     return rv;
   2488 }
   2489 
   2490 /*
   2491  * Function:
   2492  *      bcmx_l3_source_bind_get
   2493  * Purpose:
   2494  *      Retrieve the details of an existing L3 source binding.
   2495  * Parameters:
   2496  *      info - (IN/OUT) L3 source binding information
   2497  * Returns:
   2498  *      BCM_E_XXX
   2499  * Notes:
   2500  *      Returns data from first successful call.
   2501  */
   2502 int
   2503 bcmx_l3_source_bind_get(bcmx_l3_source_bind_t *info)
   2504 {
   2505     int  rv;
   2506     int  i, bcm_unit;
   2507 
   2508     BCMX_L3_INIT_CHECK;
   2509 
   2510     BCMX_PARAM_NULL_CHECK(info);
   2511 
   2512     BCMX_UNIT_ITER(bcm_unit, i) {
   2513         rv = bcm_l3_source_bind_get(bcm_unit,
   2514                                     BCMX_L3_SOURCE_BIND_T_PTR_TO_BCM(info));
   2515         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
   2516             return rv;
   2517         }
   2518     }
   2519 
   2520     return BCM_E_UNAVAIL;
   2521 }
   2522 
   2523 /*
   2524  * Function:
   2525  *      bcmx_l3_vrrp_add
   2526  * Purpose:
   2527  *      Add VRID for the given VSI. Adding a VRID using this API means
   2528  *      the physical node has become the master for the virtual router.
   2529  * Parameters:
   2530  *      vlan - VLAN/VSI
   2531  *      vrid - VRID Virtual router ID to be added
   2532  * Returns:
   2533  *      BCM_E_XXX
   2534  */
   2535 int
   2536 bcmx_l3_vrrp_add(bcm_vlan_t vlan, uint32 vrid)
   2537 {
   2538     int  rv = BCM_E_UNAVAIL, tmp_rv;
   2539     int  i, bcm_unit;
   2540 
   2541     BCMX_L3_INIT_CHECK;
   2542 
   2543     BCMX_UNIT_ITER(bcm_unit, i) {
   2544         tmp_rv = bcm_l3_vrrp_add(bcm_unit, vlan, vrid);
   2545         BCM_IF_ERROR_RETURN(BCMX_L3_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   2546     }
   2547 
   2548     return rv;
   2549 }
   2550 
   2551 /*
   2552  * Function:
   2553  *      bcmx_l3_vrrp_delete
   2554  * Purpose:
   2555  *      Delete VRID for a particulat VLAN/VSI.
   2556  * Parameters:
   2557  *      vlan - VLAN/VSI
   2558  *      vrid - VRID Virtual router ID to be deleted
   2559  * Returns:
   2560  *      BCM_E_XXX
   2561  */
   2562 int
   2563 bcmx_l3_vrrp_delete(bcm_vlan_t vlan, uint32 vrid)
   2564 {
   2565     int  rv = BCM_E_UNAVAIL, tmp_rv;
   2566     int  i, bcm_unit;
   2567 
   2568     BCMX_L3_INIT_CHECK;
   2569 
   2570     BCMX_UNIT_ITER(bcm_unit, i) {
   2571         tmp_rv = bcm_l3_vrrp_delete(bcm_unit, vlan, vrid);
   2572         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   2573     }
   2574 
   2575     return rv;
   2576 }
   2577 
   2578 /*
   2579  * Function:
   2580  *      bcmx_l3_vrrp_delete_all
   2581  * Purpose:
   2582  *      Delete all the VRIDs for a particular VLAN/VSI.
   2583  * Parameters:
   2584  *      vlan - VLAN/VSI
   2585  * Returns:
   2586  *      BCM_E_XXX
   2587  */
   2588 int
   2589 bcmx_l3_vrrp_delete_all(bcm_vlan_t vlan)
   2590 {
   2591     int  rv = BCM_E_UNAVAIL, tmp_rv;
   2592     int  i, bcm_unit;
   2593 
   2594     BCMX_L3_INIT_CHECK;
   2595 
   2596     BCMX_UNIT_ITER(bcm_unit, i) {
   2597         tmp_rv = bcm_l3_vrrp_delete_all(bcm_unit, vlan);
   2598         BCM_IF_ERROR_RETURN(BCMX_L3_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
   2599     }
   2600 
   2601     return rv;
   2602 }
   2603 
   2604 /*
   2605  * Function:
   2606  *      bcmx_l3_vrrp_get
   2607  * Purpose:
   2608  *      Get all the VRIDs for which the physical node is master for
   2609  *      the virtual routers on the given VLAN/VSI.
   2610  * Parameters:
   2611  *      vlan       - VLAN/VSI
   2612  *      alloc_size - Size of vrid_array
   2613  *      vrid_array - (OUT) Pointer to the array to which the VRIDs will be copied
   2614  *      count      - (OUT) Number of VRIDs returned
   2615  * Returns:
   2616  *      BCM_E_XXX
   2617  */
   2618 int
   2619 bcmx_l3_vrrp_get(bcm_vlan_t vlan, int alloc_size, int *vrid_array, int *count)
   2620 {
   2621     int  rv;
   2622     int  i, bcm_unit;
   2623 
   2624     BCMX_L3_INIT_CHECK;
   2625 
   2626     BCMX_PARAM_ARRAY_NULL_CHECK(alloc_size, vrid_array);
   2627     BCMX_PARAM_NULL_CHECK(count);
   2628 
   2629     BCMX_UNIT_ITER(bcm_unit, i) {
   2630         rv = bcm_l3_vrrp_get(bcm_unit, vlan, alloc_size, vrid_array, count);
   2631         if (BCMX_L3_GET_IS_VALID(bcm_unit, rv)) {
   2632             return rv;
   2633         }
   2634     }
   2635 
   2636     return BCM_E_UNAVAIL;
   2637 }
   2638 
   2639 #endif  /* INCLUDE_L3 */