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

tunnel.c (15197B)


      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 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/tunnel.h>
     18 #include <bcmx/lport.h>
     19 #include <bcmx/bcmx.h>
     20 #include <bcmx/lplist.h>
     21 
     22 #include "bcmx_int.h"
     23 
     24 #ifdef  INCLUDE_L3
     25 
     26 #define BCMX_TUNNEL_INIT_CHECK    BCMX_READY_CHECK
     27 
     28 #define BCMX_TUNNEL_SET_ERROR_CHECK(_unit, _check, _rv)    \
     29     BCMX_SET_ERROR_CHECK(_unit, _check, _rv)
     30 
     31 #define BCMX_TUNNEL_DELETE_ERROR_CHECK(_unit, _check, _rv)    \
     32     BCMX_DELETE_ERROR_CHECK(_unit, _check, _rv)
     33 
     34 #define BCMX_TUNNEL_GET_IS_VALID(_unit, _rv)    \
     35     BCMX_ERROR_IS_VALID(_unit, _rv)
     36 
     37 
     38 STATIC INLINE void
     39 _bcmx_tunnel_to_bcm(bcmx_tunnel_terminator_t *l3xtun,
     40                     bcm_tunnel_terminator_t *l3tun)
     41 {
     42     bcm_tunnel_terminator_t_init(l3tun);
     43     l3tun->flags = l3xtun->flags;
     44     l3tun->vrf = l3xtun->vrf;
     45     l3tun->sip = l3xtun->sip;
     46     l3tun->dip = l3xtun->dip;
     47     l3tun->sip_mask = l3xtun->sip_mask;
     48     l3tun->dip_mask = l3xtun->dip_mask;
     49     sal_memcpy(l3tun->sip6, l3xtun->sip6, sizeof(bcm_ip6_t));
     50     sal_memcpy(l3tun->dip6, l3xtun->dip6, sizeof(bcm_ip6_t));
     51     sal_memcpy(l3tun->sip6_mask, l3xtun->sip6_mask, sizeof(bcm_ip6_t));
     52     sal_memcpy(l3tun->dip6_mask, l3xtun->dip6_mask, sizeof(bcm_ip6_t));
     53     l3tun->udp_dst_port = l3xtun->udp_dst_port;
     54     l3tun->udp_src_port = l3xtun->udp_src_port;
     55     l3tun->type = l3xtun->type;
     56     l3tun->vlan = l3xtun->vlan;
     57     l3tun->remote_port = l3xtun->remote_port;
     58     l3tun->tunnel_id = l3xtun->tunnel_id;
     59     l3tun->if_class = l3xtun->if_class;
     60 }
     61 
     62 STATIC INLINE void
     63 _bcmx_tunnel_from_bcm(bcm_tunnel_terminator_t *l3tun,
     64                       bcmx_tunnel_terminator_t *l3xtun)
     65 {
     66     bcmx_tunnel_terminator_t_init(l3xtun);
     67     l3xtun->flags = l3tun->flags;
     68     l3xtun->vrf = l3tun->vrf;
     69     l3xtun->sip = l3tun->sip;
     70     l3xtun->dip = l3tun->dip;
     71     l3xtun->sip_mask = l3tun->sip_mask;
     72     l3xtun->dip_mask = l3tun->dip_mask;
     73     sal_memcpy(l3xtun->sip6, l3tun->sip6, sizeof(bcm_ip6_t));
     74     sal_memcpy(l3xtun->dip6, l3tun->dip6, sizeof(bcm_ip6_t));
     75     sal_memcpy(l3xtun->sip6_mask, l3tun->sip6_mask, sizeof(bcm_ip6_t));
     76     sal_memcpy(l3xtun->dip6_mask, l3tun->dip6_mask, sizeof(bcm_ip6_t));
     77     l3xtun->udp_dst_port = l3tun->udp_dst_port;
     78     l3xtun->udp_src_port = l3tun->udp_src_port;
     79     l3xtun->type = l3tun->type;
     80     l3xtun->vlan = l3tun->vlan;
     81     l3xtun->remote_port = l3tun->remote_port;
     82     l3xtun->tunnel_id = l3tun->tunnel_id;
     83     l3xtun->if_class = l3tun->if_class;
     84 }
     85 
     86 /*
     87  * Initialize a tunneling terminator structure
     88  *
     89  * Notes:
     90  *     Memory is allocated for the port list member in this
     91  *     call.  The corresponding 'free' API needs to be called
     92  *     when structure is no longer needed.
     93 */
     94 void
     95 bcmx_tunnel_terminator_t_init(bcmx_tunnel_terminator_t *info)
     96 {
     97     if (info != NULL) {
     98         sal_memset(info, 0, sizeof(bcmx_tunnel_terminator_t));
     99         info->vrf = BCM_L3_VRF_DEFAULT;
    100         bcmx_lplist_t_init(&info->ports);
    101     }
    102 }
    103 
    104 /*
    105  * Free memory allocated by the tunneling terminator initialization routine
    106  */
    107 void
    108 bcmx_tunnel_terminator_t_free(bcmx_tunnel_terminator_t *info)
    109 {
    110     if (info != NULL) {
    111         bcmx_lplist_free(&info->ports);
    112     }
    113 }
    114 
    115 /*
    116  * Initialize a tunneling header (initiator) structure
    117  */
    118 void
    119 bcmx_tunnel_initiator_t_init(bcmx_tunnel_initiator_t *tunnel)
    120 {
    121     if (tunnel != NULL) {
    122         sal_memset(tunnel, 0, sizeof(bcmx_tunnel_initiator_t));
    123     }
    124 }
    125 
    126 /*
    127  * Initialize a tunnel configuration structure
    128  */
    129 void
    130 bcmx_tunnel_config_t_init(bcmx_tunnel_config_t *tconfig)
    131 {
    132     if (tconfig != NULL) {
    133         sal_memset(tconfig, 0, sizeof(bcmx_tunnel_config_t));
    134     }
    135 }
    136 
    137 /**************************************************************
    138  * bcmx_tunnel_xxx
    139  */
    140 
    141 /*
    142  * Function:
    143  *     bcmx_tunnel_terminator_add
    144  */
    145 
    146 int
    147 bcmx_tunnel_terminator_add(bcmx_tunnel_terminator_t *info)
    148 {
    149     int rv = BCM_E_UNAVAIL, tmp_rv;
    150     int i, bcm_unit;
    151     bcm_tunnel_terminator_t bcm_tunnel;
    152 
    153     BCMX_TUNNEL_INIT_CHECK;
    154 
    155     BCMX_PARAM_NULL_CHECK(info);
    156 
    157     _bcmx_tunnel_to_bcm(info, &bcm_tunnel);
    158     BCMX_UNIT_ITER(bcm_unit, i) {
    159         BCMX_LPLIST_TO_PBMP(info->ports, bcm_unit, bcm_tunnel.pbmp);
    160         if(BCM_PBMP_NOT_NULL(bcm_tunnel.pbmp)) {
    161             tmp_rv = bcm_tunnel_terminator_add(bcm_unit, &bcm_tunnel);
    162             BCM_IF_ERROR_RETURN
    163                 (BCMX_TUNNEL_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    164         }
    165     }
    166     return rv;
    167 }
    168 
    169 /*
    170  * Function:
    171  *     bcmx_tunnel_terminator_delete
    172  */
    173 
    174 int
    175 bcmx_tunnel_terminator_delete(bcmx_tunnel_terminator_t *info)
    176 {
    177     int rv = BCM_E_UNAVAIL, tmp_rv;
    178     int i, bcm_unit;
    179     bcm_tunnel_terminator_t bcm_tunnel;
    180 
    181     BCMX_TUNNEL_INIT_CHECK;
    182 
    183     BCMX_PARAM_NULL_CHECK(info);
    184 
    185     _bcmx_tunnel_to_bcm(info, &bcm_tunnel);
    186     BCMX_UNIT_ITER(bcm_unit, i) {
    187         BCMX_LPLIST_TO_PBMP(info->ports, bcm_unit, bcm_tunnel.pbmp);
    188         if(BCM_PBMP_NOT_NULL(bcm_tunnel.pbmp)) {
    189             tmp_rv = bcm_tunnel_terminator_delete(bcm_unit, &bcm_tunnel);
    190             BCM_IF_ERROR_RETURN
    191                 (BCMX_TUNNEL_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    192         }
    193     }
    194 
    195     return rv;
    196 }
    197 
    198 /*
    199  * Function:
    200  *     bcmx_tunnel_terminator_update
    201  */
    202 
    203 int
    204 bcmx_tunnel_terminator_update(bcmx_tunnel_terminator_t *info)
    205 {
    206     int rv = BCM_E_UNAVAIL, tmp_rv;
    207     int i, bcm_unit;
    208     bcm_tunnel_terminator_t bcm_tunnel;
    209 
    210     BCMX_TUNNEL_INIT_CHECK;
    211 
    212     BCMX_PARAM_NULL_CHECK(info);
    213 
    214     _bcmx_tunnel_to_bcm(info, &bcm_tunnel);
    215     BCMX_UNIT_ITER(bcm_unit, i) {
    216         BCMX_LPLIST_TO_PBMP(info->ports, bcm_unit, bcm_tunnel.pbmp);
    217         if(BCM_PBMP_NOT_NULL(bcm_tunnel.pbmp)) {
    218             tmp_rv = bcm_tunnel_terminator_update(bcm_unit, &bcm_tunnel);
    219             BCM_IF_ERROR_RETURN
    220                 (BCMX_TUNNEL_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    221         }
    222     }
    223 
    224     return rv;
    225 }
    226 
    227 /*
    228  * Function:
    229  *     bcmx_tunnel_terminator_get
    230  */
    231 
    232 int
    233 bcmx_tunnel_terminator_get(bcmx_tunnel_terminator_t *info)
    234 {
    235     int rv = BCM_E_UNAVAIL, tmp_rv;
    236     int i, bcm_unit;
    237     bcm_tunnel_terminator_t bcm_tunnel;
    238 
    239     BCMX_TUNNEL_INIT_CHECK;
    240 
    241     BCMX_PARAM_NULL_CHECK(info);
    242 
    243     _bcmx_tunnel_to_bcm(info, &bcm_tunnel);
    244     BCMX_UNIT_ITER(bcm_unit, i) {
    245         tmp_rv = bcm_tunnel_terminator_get(bcm_unit, &bcm_tunnel);
    246 
    247         /* Ignore those units that don't have tunnel terminator ports */
    248         if (tmp_rv == BCM_E_NOT_FOUND) {
    249             if (rv == BCM_E_UNAVAIL) {
    250                 rv = tmp_rv;
    251             }
    252             continue;
    253         }
    254 
    255         if (BCMX_TUNNEL_GET_IS_VALID(bcm_unit, tmp_rv)) {
    256             rv = tmp_rv;
    257             if (BCM_SUCCESS(tmp_rv)) {
    258                 rv = BCMX_LPLIST_PBMP_ADD(&info->ports, bcm_unit,
    259                                           bcm_tunnel.pbmp);
    260             } else {
    261                 break;
    262             }
    263         }
    264     }
    265     if (BCM_SUCCESS(rv)) {
    266         _bcmx_tunnel_from_bcm(&bcm_tunnel, info);
    267     }
    268 
    269     return rv;
    270 }
    271 
    272 
    273 /*
    274  * Function:
    275  *     bcmx_tunnel_initiator_set
    276  */
    277 
    278 int
    279 bcmx_tunnel_initiator_set(bcmx_l3_intf_t *intf,
    280                           bcmx_tunnel_initiator_t *tunnel)
    281 {
    282     int rv = BCM_E_UNAVAIL, tmp_rv;
    283     int i, bcm_unit;
    284 
    285     BCMX_TUNNEL_INIT_CHECK;
    286 
    287     BCMX_PARAM_NULL_CHECK(intf);
    288     BCMX_PARAM_NULL_CHECK(tunnel);
    289 
    290     BCMX_UNIT_ITER(bcm_unit, i) {
    291         tmp_rv = bcm_tunnel_initiator_set(bcm_unit, intf, tunnel);
    292         BCM_IF_ERROR_RETURN(BCMX_TUNNEL_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    293     }
    294 
    295     return rv;
    296 }
    297 
    298 /*
    299  * Function:
    300  *     bcmx_tunnel_initiator_clear
    301  */
    302 
    303 int
    304 bcmx_tunnel_initiator_clear(bcmx_l3_intf_t *intf)
    305 {
    306     int rv = BCM_E_UNAVAIL, tmp_rv;
    307     int i, bcm_unit;
    308 
    309     BCMX_TUNNEL_INIT_CHECK;
    310 
    311     BCMX_PARAM_NULL_CHECK(intf);
    312 
    313     BCMX_UNIT_ITER(bcm_unit, i) {
    314         tmp_rv = bcm_tunnel_initiator_clear(bcm_unit, intf);
    315         BCM_IF_ERROR_RETURN
    316             (BCMX_TUNNEL_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    317     }
    318 
    319     return rv;
    320 }
    321 
    322 /*
    323  * Function:
    324  *     bcmx_tunnel_initiator_get
    325  */
    326 
    327 int
    328 bcmx_tunnel_initiator_get(bcmx_l3_intf_t *intf,
    329                              bcmx_tunnel_initiator_t *tunnel)
    330 {
    331     int rv;
    332     int i, bcm_unit;
    333 
    334     BCMX_TUNNEL_INIT_CHECK;
    335 
    336     BCMX_PARAM_NULL_CHECK(intf);
    337     BCMX_PARAM_NULL_CHECK(tunnel);
    338 
    339     BCMX_UNIT_ITER(bcm_unit, i) {
    340         rv = bcm_tunnel_initiator_get(bcm_unit, intf, tunnel);
    341         if (BCMX_TUNNEL_GET_IS_VALID(bcm_unit, rv)) {
    342             return rv;
    343         }
    344     }
    345 
    346     return BCM_E_UNAVAIL;
    347 }
    348 
    349 
    350 /*
    351  * Function: 
    352  *      bcmx_tunnel_dscp_map_create
    353  * Purpose:
    354  *      Create a tunnel DSCP map instance.
    355  * Parameters:
    356  *      flags        - (IN)  BCM_L3_XXX
    357  *      dscp_map_id  - (OUT) Allocated DSCP map ID
    358  * Returns:
    359  *      BCM_E_XXX
    360  */
    361 int
    362 bcmx_tunnel_dscp_map_create(uint32 flags, int *dscp_map_id)
    363 {
    364     int rv = BCM_E_UNAVAIL, tmp_rv;
    365     int i, bcm_unit;
    366 
    367     BCMX_TUNNEL_INIT_CHECK;
    368 
    369     BCMX_PARAM_NULL_CHECK(dscp_map_id);
    370 
    371     BCMX_UNIT_ITER(bcm_unit, i) {
    372         tmp_rv = bcm_tunnel_dscp_map_create(bcm_unit, flags, dscp_map_id);
    373         BCM_IF_ERROR_RETURN(BCMX_TUNNEL_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    374     }
    375 
    376     return rv;
    377 }
    378 
    379 
    380 /*
    381  * Function:
    382  *      bcmx_tunnel_dscp_map_destroy
    383  * Purpose:
    384  *      Destroy an existing tunnel DSCP map instance.
    385  * Parameters:
    386  *      dscp_map_id - (IN) DSCP map ID
    387  * Returns:
    388  *      BCM_E_XXX
    389  */
    390 int
    391 bcmx_tunnel_dscp_map_destroy(int dscp_map_id)
    392 {
    393     int rv = BCM_E_UNAVAIL, tmp_rv;
    394     int i, bcm_unit;
    395 
    396     BCMX_TUNNEL_INIT_CHECK;
    397 
    398     BCMX_UNIT_ITER(bcm_unit, i) {
    399         tmp_rv = bcm_tunnel_dscp_map_destroy(bcm_unit, dscp_map_id);
    400         BCM_IF_ERROR_RETURN
    401             (BCMX_TUNNEL_DELETE_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    402     }
    403 
    404     return rv;
    405 }
    406 
    407 
    408 /*
    409  * Function:
    410  *      bcmx_tunnel_dscp_map_set
    411  * Purpose:
    412  *      Set the mapping of { internal priority, color }
    413  *      to a DSCP value for outer tunnel headers
    414  *      in the specified DSCP map instance.
    415  * Parameters:
    416  *      dscp_map_id  - (IN) DSCP map ID
    417  *      dscp_map     - (IN) tunnel DSCP info
    418  * Returns:
    419  *      BCM_E_XXX
    420  */
    421 int
    422 bcmx_tunnel_dscp_map_set(int dscp_map_id,
    423                             bcm_tunnel_dscp_map_t *dscp_map)
    424 {
    425     int rv = BCM_E_UNAVAIL, tmp_rv;
    426     int i, bcm_unit;
    427 
    428     BCMX_TUNNEL_INIT_CHECK;
    429 
    430     BCMX_PARAM_NULL_CHECK(dscp_map);
    431 
    432     BCMX_UNIT_ITER(bcm_unit, i) {
    433         tmp_rv = bcm_tunnel_dscp_map_set(bcm_unit, dscp_map_id, dscp_map);
    434         BCM_IF_ERROR_RETURN(BCMX_TUNNEL_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    435     }
    436 
    437     return rv;
    438 }
    439 
    440 
    441 /*
    442  * Function:
    443  *      bcmx_tunnel_dscp_map_get
    444  * Purpose:
    445  *      Get the tunnel DSCP map information for the specified
    446  *      DSCP map instance.
    447  * Parameters:
    448  *      dscp_map_id  - (IN)  DSCP map ID
    449  *      dscp_map     - (OUT) Returning DSCP map info
    450  * Returns:
    451  *      BCM_E_XXX
    452  */     
    453 int
    454 bcmx_tunnel_dscp_map_get(int dscp_map_id,
    455                             bcm_tunnel_dscp_map_t *dscp_map)
    456 {
    457     int    rv;
    458     int    i, bcm_unit;
    459 
    460     BCMX_TUNNEL_INIT_CHECK;
    461 
    462     BCMX_PARAM_NULL_CHECK(dscp_map);
    463 
    464     BCMX_UNIT_ITER(bcm_unit, i) {
    465         rv = bcm_tunnel_dscp_map_get(bcm_unit, dscp_map_id, dscp_map);
    466         if (BCMX_TUNNEL_GET_IS_VALID(bcm_unit, rv)) {
    467             return rv;
    468         }
    469     }
    470 
    471     return BCM_E_UNAVAIL;
    472 }
    473 
    474 
    475 /*
    476  * Function:
    477  *      bcmx_tunnel_dscp_map_port_set
    478  * Purpose:
    479  *      Set the mapping of { internal priority, color }
    480  *      to a DSCP value for outer tunnel headers
    481  *      for a specific egress port.
    482  * Parameters:
    483  *      port         - (IN) Egress port number.
    484  *      dscp_map     - (IN) tunnel DSCP info
    485  * Returns:
    486  *      BCM_E_XXX
    487  */
    488 int
    489 bcmx_tunnel_dscp_map_port_set(bcmx_lport_t port, 
    490                               bcm_tunnel_dscp_map_t *dscp_map)
    491 {
    492     int         bcm_unit;
    493     bcm_port_t  bcm_port;
    494 
    495     BCMX_TUNNEL_INIT_CHECK;
    496 
    497     BCMX_PARAM_NULL_CHECK(dscp_map);
    498 
    499     BCM_IF_ERROR_RETURN
    500         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    501                                  BCMX_DEST_CONVERT_DEFAULT));
    502 
    503     return  bcm_tunnel_dscp_map_set(bcm_unit, bcm_port,
    504                                     dscp_map);
    505 }
    506 
    507 
    508 /*
    509  * Function:
    510  *      bcmx_tunnel_dscp_map_port_get
    511  * Purpose:
    512  *      Get the tunnel DSCP map information for the specified
    513  *      egress port
    514  * Parameters:
    515  *      port         - (IN)  Egress port number
    516  *      dscp_map     - (OUT) Returning DSCP map info
    517  * Returns:
    518  *      BCM_E_XXX
    519  */     
    520 int
    521 bcmx_tunnel_dscp_map_port_get(bcmx_lport_t port,
    522                               bcm_tunnel_dscp_map_t *dscp_map)
    523 {
    524     int         bcm_unit;
    525     bcm_port_t  bcm_port;
    526 
    527     BCMX_TUNNEL_INIT_CHECK;
    528 
    529     BCMX_PARAM_NULL_CHECK(dscp_map);
    530 
    531     BCM_IF_ERROR_RETURN
    532         (_bcmx_dest_to_unit_port(port, &bcm_unit, &bcm_port,
    533                                  BCMX_DEST_CONVERT_DEFAULT));
    534 
    535     return  bcm_tunnel_dscp_map_get(bcm_unit, bcm_port,
    536                                     dscp_map);
    537 }
    538 
    539 
    540 /*
    541  * Function:
    542  *     bcmx_tunnel_config_set
    543  */
    544 
    545 int
    546 bcmx_tunnel_config_set(bcmx_tunnel_config_t *tconfig)
    547 {
    548     int rv = BCM_E_UNAVAIL, tmp_rv;
    549     int i, bcm_unit;
    550 
    551     BCMX_TUNNEL_INIT_CHECK;
    552 
    553     BCMX_PARAM_NULL_CHECK(tconfig);
    554 
    555     BCMX_UNIT_ITER(bcm_unit, i) {
    556         tmp_rv = bcm_tunnel_config_set(bcm_unit, tconfig);
    557         BCM_IF_ERROR_RETURN(BCMX_TUNNEL_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    558     }
    559 
    560     return rv;
    561 }
    562 
    563 /*
    564  * Function:
    565  *     bcmx_tunnel_config_get
    566  */
    567 
    568 int
    569 bcmx_tunnel_config_get(bcmx_tunnel_config_t *tconfig)
    570 {
    571     int rv;
    572     int i, bcm_unit;
    573 
    574     BCMX_TUNNEL_INIT_CHECK;
    575 
    576     BCMX_UNIT_ITER(bcm_unit, i) {
    577         rv = bcm_tunnel_config_get(bcm_unit, tconfig);
    578         if (BCMX_TUNNEL_GET_IS_VALID(bcm_unit, rv)) {
    579             return rv;
    580         }
    581     }
    582 
    583     return BCM_E_UNAVAIL;
    584 }
    585 
    586 
    587 /*
    588  * Function:
    589  *     bcmx_tunnel_terminator_vlan_set
    590  * Purpose:
    591  *     Set the allowed VLANs for a WLAN tunnel.
    592  * Parameters:
    593  *     tunnel   - Tunnel ID
    594  *     vlan_vec - VLAN vector
    595  * Returns:
    596  *     BCM_E_XXX
    597  */
    598 int
    599 bcmx_tunnel_terminator_vlan_set(bcm_gport_t tunnel,
    600                                 bcm_vlan_vector_t vlan_vec)
    601 {
    602     int  rv = BCM_E_UNAVAIL, tmp_rv;
    603     int  i, bcm_unit;
    604 
    605     BCMX_TUNNEL_INIT_CHECK;
    606 
    607     BCMX_UNIT_ITER(bcm_unit, i) {
    608         tmp_rv = bcm_tunnel_terminator_vlan_set(bcm_unit, tunnel, vlan_vec);
    609         BCM_IF_ERROR_RETURN(BCMX_TUNNEL_SET_ERROR_CHECK(bcm_unit, tmp_rv, &rv));
    610     }
    611 
    612     return rv;
    613 }
    614 
    615 /*
    616  * Function:
    617  *     bcmx_tunnel_terminator_vlan_get
    618  * Purpose:
    619  *     Get the allowed VLANs for a WLAN tunnel.
    620  * Parameters:
    621  *     tunnel   - Tunnel ID
    622  *     vlan_vec - (OUT) VLAN vector
    623  * Returns:
    624  *     BCM_E_XXX
    625  */
    626 int
    627 bcmx_tunnel_terminator_vlan_get(bcm_gport_t tunnel, 
    628                                 bcm_vlan_vector_t *vlan_vec)
    629 {
    630     int  rv;
    631     int  i, bcm_unit;
    632 
    633     BCMX_TUNNEL_INIT_CHECK;
    634 
    635     BCMX_PARAM_NULL_CHECK(vlan_vec);
    636 
    637     BCMX_UNIT_ITER(bcm_unit, i) {
    638         rv = bcm_tunnel_terminator_vlan_get(bcm_unit, tunnel, vlan_vec);
    639         if (BCMX_TUNNEL_GET_IS_VALID(bcm_unit, rv)) {
    640             return rv;
    641         }
    642     }
    643 
    644     return BCM_E_UNAVAIL;
    645 }
    646 
    647 #endif  /* INCLUDE_L3 */