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

ct_tun.c (38386B)


      1  /*
      2   * 
      3   *
      4   *
      5   * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      6   * 
      7   * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      8   *
      9   * File:        ct_tun.c
     10   * Purpose:
     11   * Requires:    
     12   */
     13 
     14 /****************************************************************
     15  *
     16  * Packet RX tunnelling code:
     17  *
     18  * This code originally lived in BCM.  It has been moved to
     19  * be an ATP application and live in src/appl/cputrans.
     20  *
     21  * Tunnelling is meant to forward packets between two different
     22  * CPUs.  However,
     23  * the function that actually forwards the packet data is programmed
     24  * into this API with the ct_rx_tunnel_tx_set call.  Having both
     25  * tunnel send and tunnel accept running on the same CPU probably will
     26  * not work.
     27  *
     28  * Reliable and best effort tunnelling are both supported.
     29  *
     30  * The code is divided into that which runs on the slave (most of
     31  * the code) and that which runs on the master (just the unpack
     32  * routine).
     33  *
     34  * A local callback may be installed (tunnel_filter) which will be called
     35  * as a filter on packets that may be tunnelled.  The filter may
     36  * return:
     37  *
     38  *      BCM_CPU_TUNNEL_NONE                 Do not tunnel the packet
     39  *      BCM_CPU_TUNNEL_PACKET_RELIABLE      Use reliable trx
     40  *      BCM_CPU_TUNNEL_PACKET_BEST_EFFORT   Use best effort
     41  *      BCM_CPU_TUNNEL_PACKET               Use the current default mode
     42  *
     43  * The default is BCM_CPU_TUNNEL_PACKET. Otherwise, BCM_RX_NOT_HANDLED
     44  * is returned to the RX thread.
     45  *
     46  * If no filter function is installed, then all packets received by the
     47  * tunnel routine are forwarded.
     48  *
     49  * Only one set of data is supported across all local units.  This
     50  * includes the filter function, the filter cookie (if implemented),
     51  * and the TX functions.  Note that receive unit is sent to the callback.
     52  *
     53  * Packets are queued to a tunneling thread, which then transmits the
     54  * packet.
     55  *
     56  * The current implementation does alloc/frees, so will be very
     57  * slow.  Packet pools may be added in the future.
     58  * For now, BCM_RX_HANDLED is returned when tunnelled.  If a queue and
     59  * separate thread are added in the future, packets will be stolen
     60  * from BCM RX (BCM_RX_HANDLED_OWNED is returned).
     61  *
     62  * TO DO:
     63  *      Use RX pool code for tunnelled packet data.  See
     64  *      rx_tunnel_pkt and ct_rx_tunnel_done_cb.
     65  */
     66 #include <shared/bsl.h>
     67 
     68 #include <sdk_config.h>
     69 #include <assert.h>
     70 #include <sal/core/thread.h>
     71 
     72 #include <shared/util.h>
     73 #include <shared/idents.h>
     74 
     75 #include <bcm/rx.h>
     76 #include <bcm/init.h>
     77 #include <bcm/port.h>
     78 
     79 #include <appl/cputrans/ct_tun.h>
     80 
     81 #include "t_util.h"
     82 
     83 #if defined(BCM_RPC_SUPPORT)
     84 
     85 #include <appl/cputrans/atp.h>
     86 
     87 /* Filter function callback */
     88 STATIC bcm_cpu_tunnel_mode_t
     89     _ct_rx_tunnel_filter_default(int unit, bcm_pkt_t *pkt);
     90 static ct_rx_tunnel_filter_f ct_rx_tunnel_filter = _ct_rx_tunnel_filter_default;
     91 
     92 static sal_mutex_t _tunnel_cfg_lock;
     93 
     94 /* Tunnel TX queueing */
     95 
     96 #ifndef CT_TUNNEL_QUEUE_ENABLE
     97 #define CT_TUNNEL_QUEUE_ENABLE 1
     98 #endif
     99 
    100 #if CT_TUNNEL_QUEUE_ENABLE
    101 
    102 #ifndef CT_TUNNEL_QUEUE_SIZE
    103 #define CT_TUNNEL_QUEUE_SIZE 32
    104 #endif
    105 
    106 typedef struct {
    107     uint8 *data;
    108     int len;
    109     void *pkt;
    110 } ct_tunnel_q_element;
    111 
    112 static sal_thread_t _tunnel_q_thread = SAL_THREAD_ERROR;
    113 static int          _tunnel_q_top_full;  /* Pkts dropped when queue full */
    114 static int          _tunnel_q_thread_exit; /* Set to exit thread */
    115 static int          _tunnel_q_error;     /* TX error count */
    116 static sal_mutex_t  _tunnel_q_lock;      /* Queue lock */
    117 static sal_sem_t    _tunnel_q_sem;       /* Queue thread semaphore */
    118 static int          _tunnel_q_head;      /* Insertion index */
    119 static int          _tunnel_q_tail;      /* Removal index */
    120 static ct_tunnel_q_element _tunnel_q[CT_TUNNEL_QUEUE_SIZE]; /* Queue */
    121 
    122 #define TUNNEL_Q_LOCK   sal_mutex_take(_tunnel_q_lock, sal_mutex_FOREVER)
    123 #define TUNNEL_Q_UNLOCK sal_mutex_give(_tunnel_q_lock)
    124 #define TUNNEL_Q_SLEEP  sal_sem_take(_tunnel_q_sem, sal_sem_FOREVER)
    125 #define TUNNEL_Q_WAKE   sal_sem_give(_tunnel_q_sem)
    126 
    127 #ifndef TUNNEL_Q_THREAD_STACK
    128 #define TUNNEL_Q_THREAD_STACK   SAL_THREAD_STKSZ
    129 #endif
    130 
    131 #ifndef TUNNEL_Q_THREAD_PRIO
    132 #define TUNNEL_Q_THREAD_PRIO    255
    133 #endif
    134 
    135 STATIC int ct_tx_tunnel_thread_init(void);
    136 STATIC int ct_tx_tunnel_thread_stop(void);
    137 
    138 #endif
    139 
    140 #define CHECK_INIT if (_tunnel_cfg_lock == NULL &&                       \
    141         ((_tunnel_cfg_lock = sal_mutex_create("rx_tunnel")) == NULL))    \
    142         return BCM_E_MEMORY
    143 
    144 #define TUNNEL_LOCK sal_mutex_take(_tunnel_cfg_lock, sal_mutex_FOREVER)
    145 #define TUNNEL_UNLOCK sal_mutex_give(_tunnel_cfg_lock)
    146 
    147 /* These are exposed */
    148 static bcm_cpu_tunnel_mode_t ct_rx_tunnel_mode_default =
    149         BCM_CPU_TUNNEL_PACKET_BEST_EFFORT;
    150 
    151 static int ct_rx_tunnel_priority = 100;   /* Warning: Don't change when running */
    152 
    153 /* Accessors for mode and priority */
    154 int
    155 ct_rx_tunnel_mode_default_set(int mode)
    156 {
    157     switch (mode) {
    158     case BCM_CPU_TUNNEL_NONE:
    159     case BCM_CPU_TUNNEL_PACKET_RELIABLE:
    160     case BCM_CPU_TUNNEL_PACKET_BEST_EFFORT:
    161     case BCM_CPU_TUNNEL_PACKET:
    162         ct_rx_tunnel_mode_default = (bcm_cpu_tunnel_mode_t)mode;
    163         return BCM_E_NONE;
    164 
    165     default:
    166         break;
    167     }
    168 
    169     return BCM_E_PARAM;
    170 }
    171 
    172 bcm_cpu_tunnel_mode_t
    173 ct_rx_tunnel_mode_default_get(void)
    174 {
    175     return ct_rx_tunnel_mode_default;
    176 }
    177 
    178 int
    179 ct_rx_tunnel_priority_set(int priority)
    180 {
    181     ct_rx_tunnel_priority = priority;
    182 
    183     return BCM_E_NONE;
    184 }
    185 
    186 int
    187 ct_rx_tunnel_priority_get(void)
    188 {
    189     return ct_rx_tunnel_priority;
    190 }
    191 
    192 #define CT_TUNNEL_RX_REASONS_WORDS (_SHR_BITDCLSIZE(_SHR_RX_REASON_COUNT))
    193 #define CT_TUNNEL_RX_HDR_BYTES (2 + 4 + (6*1) + 2 + 1 + 2 + (2*1) + (2*4) + \
    194                                 2 + (2*1) + (CT_TUNNEL_RX_REASONS_WORDS * 4)\
    195                                  + (2*4) + 4 + \
    196                                 2 + (2*1) + 2 + (2*1) + (15*4) + (2*4))
    197 
    198 /****************************************************************
    199  *
    200  * Forward declarations
    201  */
    202 
    203 STATIC bcm_rx_t ct_tx_tunnelled_pkt_handler(cpudb_key_t src_key,
    204                                             int client_id,
    205                                             bcm_pkt_t *pkt,
    206                                             uint8 *payload,
    207                                             int payload_len,
    208                                             void *cookie);
    209 
    210 /*
    211  * Function:
    212  *      ct_rx_tunnel_header_bytes_get
    213  * Purpose:
    214  *      Returns the number of bytes in a CT tunneled packet
    215  * Returns:
    216  *      BCM_E_XXX on error (unsupported)
    217  *      Otherwise, number of bytes in the header
    218  * Notes:
    219  *      Needed by RPC rlink code
    220  */
    221 
    222 int
    223 ct_rx_tunnel_header_bytes_get(void)
    224 {
    225     return CT_TUNNEL_RX_HDR_BYTES;
    226 }
    227 
    228 
    229 /*
    230  * Tunnel pack and unpack functions
    231  *
    232  * These pack up the meta-data; for the pack function the data
    233  * is copied into the buffer as well.  For unpack, the pointers
    234  * to the data are provided, but the data is not copied from the
    235  * original buffer.
    236  */
    237 
    238 uint8 *
    239 ct_rx_tunnel_pkt_pack(bcm_pkt_t *pkt, uint8 *pkt_data)
    240 {
    241     int i;
    242 
    243 #if defined(BROADCOM_DEBUG)
    244     uint8 *pkt_data0 = pkt_data;
    245 #endif
    246     /* Change CT_TUNNEL_RX_HDR_BYTES when the packing changes. */
    247     CT_INCR_PACK_U16(pkt_data, pkt->pkt_len);
    248     CT_INCR_PACK_U32(pkt_data, pkt->rx_reason);
    249     CT_INCR_PACK_U8(pkt_data, pkt->rx_unit);
    250     CT_INCR_PACK_U8(pkt_data, pkt->rx_port);
    251     CT_INCR_PACK_U8(pkt_data, pkt->rx_cpu_cos);
    252     CT_INCR_PACK_U8(pkt_data, pkt->rx_untagged);
    253     CT_INCR_PACK_U8(pkt_data, pkt->cos);
    254     CT_INCR_PACK_U8(pkt_data, pkt->prio_int);
    255     CT_INCR_PACK_U16(pkt_data, pkt->src_port);
    256     CT_INCR_PACK_U8(pkt_data, pkt->src_mod & 0xFF);
    257     CT_INCR_PACK_U16(pkt_data, pkt->dest_port);
    258     CT_INCR_PACK_U8(pkt_data, pkt->dest_mod & 0xFF);
    259     CT_INCR_PACK_U8(pkt_data, pkt->opcode);
    260     CT_INCR_PACK_U32(pkt_data, pkt->rx_matched);
    261     CT_INCR_PACK_U32(pkt_data, pkt->flags);
    262     CT_INCR_PACK_U16(pkt_data, pkt->src_trunk);
    263 
    264     /* to maintain backwards compatibility, pack the extented src & dest mod
    265      * bits at the end of the buffer
    266      */
    267     CT_INCR_PACK_U8(pkt_data, (pkt->src_mod >> 8) & 0xFF);
    268     CT_INCR_PACK_U8(pkt_data, (pkt->dest_mod >> 8) & 0xFF);
    269 
    270     /* rx_reasons rx_classification_tag rx_timestamp */
    271     for (i=0; i<CT_TUNNEL_RX_REASONS_WORDS; i++) {
    272         CT_INCR_PACK_U32(pkt_data, (uint32)pkt->rx_reasons.pbits[i]);
    273     }
    274     CT_INCR_PACK_U32(pkt_data, pkt->rx_classification_tag);
    275     CT_INCR_PACK_U32(pkt_data, pkt->rx_timestamp);
    276 
    277     for (i=0; i<4; i++) {
    278         CT_INCR_PACK_U8(pkt_data, pkt->_vtag[i]);
    279     }
    280 
    281     CT_INCR_PACK_U16(pkt_data, pkt->vlan);
    282     CT_INCR_PACK_U8(pkt_data, pkt->vlan_pri);
    283     CT_INCR_PACK_U8(pkt_data, pkt->vlan_cfi);
    284     CT_INCR_PACK_U16(pkt_data, pkt->inner_vlan);
    285     CT_INCR_PACK_U8(pkt_data, pkt->inner_vlan_pri);
    286     CT_INCR_PACK_U8(pkt_data, pkt->inner_vlan_cfi);
    287     CT_INCR_PACK_U32(pkt_data, pkt->color);
    288     CT_INCR_PACK_U32(pkt_data, pkt->dst_gport);
    289     CT_INCR_PACK_U32(pkt_data, pkt->src_gport);
    290     CT_INCR_PACK_U32(pkt_data, pkt->multicast_group);
    291     CT_INCR_PACK_U32(pkt_data, pkt->stk_flags);
    292     CT_INCR_PACK_U32(pkt_data, pkt->stk_forward);
    293     CT_INCR_PACK_U32(pkt_data, pkt->stk_classification_tag);
    294     CT_INCR_PACK_U32(pkt_data, pkt->stk_pkt_prio);
    295     CT_INCR_PACK_U32(pkt_data, pkt->stk_dscp);
    296     CT_INCR_PACK_U32(pkt_data, pkt->stk_load_balancing_number);
    297     CT_INCR_PACK_U32(pkt_data, pkt->rx_timestamp_upper);
    298     CT_INCR_PACK_U32(pkt_data, pkt->rx_l3_intf);
    299     CT_INCR_PACK_U32(pkt_data, pkt->rx_outer_tag_action);
    300     CT_INCR_PACK_U32(pkt_data, pkt->rx_inner_tag_action);
    301     CT_INCR_PACK_U32(pkt_data, pkt->stk_encap_id);
    302 
    303     CT_INCR_PACK_U32(pkt_data, pkt->flags2);
    304 
    305     /* OAM SOMBH header fields */
    306     CT_INCR_PACK_U8(pkt_data, pkt->oam_replacement_type);
    307     CT_INCR_PACK_U8(pkt_data, pkt->oam_replacement_offset);
    308     CT_INCR_PACK_U16(pkt_data, pkt->oam_lm_counter_index);
    309 
    310 #if defined(BROADCOM_DEBUG)
    311     assert((pkt_data - pkt_data0) == CT_TUNNEL_RX_HDR_BYTES);
    312 #endif
    313 
    314     sal_memcpy(pkt_data, pkt->pkt_data[0].data, pkt->pkt_len);
    315 
    316 
    317     return pkt_data + pkt->pkt_len;
    318 }
    319 
    320 int
    321 ct_rx_tunnel_pkt_unpack(uint8 *pkt_data, int pkt_len, bcm_pkt_t *pkt,
    322                         uint8 **payload_start, int *payload_len)
    323 {
    324     uint8 tmp;
    325     int i;
    326 
    327     if (pkt_len < CT_TUNNEL_RX_HDR_BYTES) {
    328         return BCM_E_PARAM;
    329     }
    330 
    331     CT_INCR_UNPACK_U16(pkt_data, pkt->pkt_len);
    332     CT_INCR_UNPACK_U32(pkt_data, pkt->rx_reason);
    333     CT_INCR_UNPACK_U8(pkt_data, pkt->rx_unit);
    334     CT_INCR_UNPACK_U8(pkt_data, pkt->rx_port);
    335     CT_INCR_UNPACK_U8(pkt_data, pkt->rx_cpu_cos);
    336     CT_INCR_UNPACK_U8(pkt_data, pkt->rx_untagged);
    337     CT_INCR_UNPACK_U8(pkt_data, pkt->cos);
    338     CT_INCR_UNPACK_U8(pkt_data, pkt->prio_int);
    339     CT_INCR_UNPACK_U16(pkt_data, pkt->src_port);
    340     CT_INCR_UNPACK_U8(pkt_data, pkt->src_mod);
    341     CT_INCR_UNPACK_U16(pkt_data, pkt->dest_port);
    342     CT_INCR_UNPACK_U8(pkt_data, pkt->dest_mod);
    343     CT_INCR_UNPACK_U8(pkt_data, pkt->opcode);
    344     CT_INCR_UNPACK_U32(pkt_data, pkt->rx_matched);
    345     CT_INCR_UNPACK_U32(pkt_data, pkt->flags);
    346     CT_INCR_UNPACK_U16(pkt_data, pkt->src_trunk);
    347 
    348     /* to maintain backwards compatibility, pack the extented src & dest mod
    349      * bits at the end of the buffer
    350      */
    351     CT_INCR_UNPACK_U8(pkt_data, tmp);
    352     pkt->src_mod |= tmp << 8;
    353 
    354     CT_INCR_UNPACK_U8(pkt_data, tmp);
    355     pkt->dest_mod |= tmp << 8;
    356 
    357     for (i=0; i<CT_TUNNEL_RX_REASONS_WORDS; i++) {
    358         CT_INCR_UNPACK_U32(pkt_data, pkt->rx_reasons.pbits[i]);
    359     }
    360     CT_INCR_UNPACK_U32(pkt_data, pkt->rx_classification_tag);
    361     CT_INCR_UNPACK_U32(pkt_data, pkt->rx_timestamp);
    362 
    363     for (i=0; i<4; i++) {
    364         CT_INCR_UNPACK_U8(pkt_data, pkt->_vtag[i]);
    365     }
    366 
    367     CT_INCR_UNPACK_U16(pkt_data, pkt->vlan);
    368     CT_INCR_UNPACK_U8(pkt_data, pkt->vlan_pri);
    369     CT_INCR_UNPACK_U8(pkt_data, pkt->vlan_cfi);
    370     CT_INCR_UNPACK_U16(pkt_data, pkt->inner_vlan);
    371     CT_INCR_UNPACK_U8(pkt_data, pkt->inner_vlan_pri);
    372     CT_INCR_UNPACK_U8(pkt_data, pkt->inner_vlan_cfi);
    373     CT_INCR_UNPACK_U32(pkt_data, pkt->color);
    374     CT_INCR_UNPACK_U32(pkt_data, pkt->dst_gport);
    375     CT_INCR_UNPACK_U32(pkt_data, pkt->src_gport);
    376     CT_INCR_UNPACK_U32(pkt_data, pkt->multicast_group);
    377     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_flags);
    378     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_forward);
    379     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_classification_tag);
    380     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_pkt_prio);
    381     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_dscp);
    382     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_load_balancing_number);
    383     CT_INCR_UNPACK_U32(pkt_data, pkt->rx_timestamp_upper);
    384     CT_INCR_UNPACK_U32(pkt_data, pkt->rx_l3_intf);
    385     CT_INCR_UNPACK_U32(pkt_data, pkt->rx_outer_tag_action);
    386     CT_INCR_UNPACK_U32(pkt_data, pkt->rx_inner_tag_action);
    387     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_encap_id);
    388 
    389     CT_INCR_UNPACK_U32(pkt_data, pkt->flags2);
    390 
    391     /* OAM SOMBH header fields */
    392     CT_INCR_UNPACK_U8(pkt_data, pkt->oam_replacement_type);
    393     CT_INCR_UNPACK_U8(pkt_data, pkt->oam_replacement_offset);
    394     CT_INCR_UNPACK_U16(pkt_data, pkt->oam_lm_counter_index);
    395 
    396     *payload_start = pkt_data;
    397     *payload_len = pkt_len - CT_TUNNEL_RX_HDR_BYTES;
    398 
    399     return BCM_E_NONE;
    400 }
    401 
    402 
    403 static ct_rx_tunnel_direct_f _rx_tunnel_direct = NULL;
    404 
    405 int
    406 ct_rx_tunnel_direct_set(ct_rx_tunnel_direct_f dif_fn)
    407 {
    408     _rx_tunnel_direct = dif_fn;
    409 
    410     return BCM_E_NONE;
    411 }
    412 
    413 int
    414 ct_rx_tunnel_direct_get(ct_rx_tunnel_direct_f *dif_fn)
    415 {
    416     *dif_fn = _rx_tunnel_direct;
    417 
    418     return BCM_E_NONE;
    419 }
    420 
    421 /*
    422  * ct_rx_tunnel_check:
    423  *
    424  * Check if a packet should be tunnelled; if so, see if it should
    425  * be directed to some particular CPU.
    426  *
    427  * Returns BCM_CPU_TUNNEL_NONE if packet should _not_ be tunnelled;
    428  * Any other value means packet should be tunnelled.
    429  */
    430 
    431 bcm_cpu_tunnel_mode_t
    432 ct_rx_tunnel_check(int unit, bcm_pkt_t *pkt, int *no_ack, int *check_cpu,
    433                    cpudb_key_t *cpu)
    434 {
    435     bcm_cpu_tunnel_mode_t mode = BCM_CPU_TUNNEL_PACKET;
    436 
    437     if (ct_rx_tunnel_filter != NULL) {
    438         mode = ct_rx_tunnel_filter(unit, pkt);
    439     }
    440 
    441     switch (mode) {
    442     case BCM_CPU_TUNNEL_PACKET_RELIABLE:
    443         *no_ack = FALSE;
    444         break;
    445     case BCM_CPU_TUNNEL_PACKET_BEST_EFFORT:
    446         *no_ack = TRUE;
    447         break;
    448     case BCM_CPU_TUNNEL_PACKET:  /* Check if default is currently no-ack */
    449         *no_ack = (ct_rx_tunnel_mode_default ==
    450                    BCM_CPU_TUNNEL_PACKET_BEST_EFFORT);
    451         break;
    452     case BCM_CPU_TUNNEL_NONE:  /* Don't tunnel */
    453     default:    /* Bad mode; treat as none. */
    454         return BCM_CPU_TUNNEL_NONE;
    455 
    456     }
    457 
    458     if (_rx_tunnel_direct != NULL) {
    459         *check_cpu = _rx_tunnel_direct(unit, pkt, cpu);
    460     } else {
    461         *check_cpu = FALSE;
    462     }
    463 
    464     return mode;
    465 }
    466 
    467 
    468 /****************************************************************
    469  *
    470  * RX filter function accessors and default.
    471  *
    472  * Default tunnel filter callback.  This filters out packets
    473  * that come from stack ports.
    474  */
    475 
    476 STATIC bcm_cpu_tunnel_mode_t
    477 _ct_rx_tunnel_filter_default(int unit, bcm_pkt_t *pkt)
    478 {
    479     bcm_port_config_t port_config;
    480 
    481     if (bcm_port_config_get(unit, &port_config) < 0) {
    482         LOG_ERROR(BSL_LS_TKS_TUNNEL,
    483                   (BSL_META_U(unit,
    484                               "Tunnel filter: could not get port config "
    485                               " for %d\n"),
    486                    unit));
    487         return BCM_CPU_TUNNEL_NONE;
    488     }
    489 
    490     if (BCM_PBMP_MEMBER(port_config.stack_ext, pkt->rx_port)) {
    491         return BCM_CPU_TUNNEL_NONE;
    492     }
    493 
    494     return BCM_CPU_TUNNEL_PACKET;
    495 }
    496 
    497 
    498 /*
    499  * Function:
    500  *      ct_rx_tunnel_filter_set/get
    501  * Purpose:
    502  *      Set/get the RX tunnel filter function
    503  * Parameters:
    504  *      t_cb       - The function to use.  May be NULL.
    505  * Returns:
    506  *      BCM_E_NONE
    507  */
    508 
    509 int
    510 ct_rx_tunnel_filter_set(ct_rx_tunnel_filter_f t_cb)
    511 {
    512     CHECK_INIT;
    513     TUNNEL_LOCK;
    514     ct_rx_tunnel_filter = t_cb;
    515     TUNNEL_UNLOCK;
    516 
    517     return BCM_E_NONE;
    518 }
    519 
    520 
    521 int
    522 ct_rx_tunnel_filter_get(ct_rx_tunnel_filter_f *t_cb)
    523 {
    524     *t_cb = ct_rx_tunnel_filter;
    525 
    526     return BCM_E_NONE;
    527 }
    528 
    529 /****************************************************************
    530  *
    531  * Client Side RX tunnelling code.  Handle a tunnel (encapsulated)
    532  * packet.
    533  */
    534 
    535 
    536 /*
    537  * Function:
    538  *      ct_rx_tunnelled_pkt_handler
    539  * Purpose:
    540  *      Handler for RX tunnelled packets,
    541  * Parameters:
    542  *      src_key     - Source of tunnelled pkt
    543  *      payload     - Pointer to start of tunnelled encap pkt
    544  *      len         - Total length of pkt with encap header
    545  * Returns:
    546  *      BCM_E_XXX
    547  */
    548 
    549 void
    550 ct_rx_tunnelled_pkt_handler(cpudb_key_t src_key, uint8 *payload, int len)
    551 {
    552     uint8 *ap_data;
    553     int ap_len;
    554     bcm_pkt_t *rx_pkt;
    555     int rv;
    556     int bcm_unit;
    557     char keybuf[CPUDB_KEY_STRING_LEN];
    558 
    559     LOG_VERBOSE(BSL_LS_TKS_TUNNEL,
    560                 (BSL_META("Tunnel handler from " CPUDB_KEY_FMT_EOLN),
    561                  CPUDB_KEY_DISP(src_key)));
    562 
    563     if (payload == NULL || len < CT_TUNNEL_RX_HDR_BYTES) {
    564         LOG_WARN(BSL_LS_TKS_TUNNEL,
    565                  (BSL_META("Tunnel RX pkt: no payload (%p, len %d)\n"),
    566                   payload, len - CT_TUNNEL_RX_HDR_BYTES));
    567         return;
    568     }
    569 
    570     rx_pkt = NULL;
    571     rv = bcm_rx_remote_pkt_alloc(len - CT_TUNNEL_RX_HDR_BYTES, &rx_pkt);
    572     if (rv != BCM_E_NONE) {
    573         LOG_VERBOSE(BSL_LS_TKS_TUNNEL,
    574                     (BSL_META("Tunnel RX pkt: remote pkt alloc failed "
    575                               "for %d bytes\n"),
    576                      len - CT_TUNNEL_RX_HDR_BYTES));
    577         return;
    578     }
    579 
    580     rv = ct_rx_tunnel_pkt_unpack(payload, len, rx_pkt, &ap_data, &ap_len);
    581 
    582     if (rv < 0) {
    583         LOG_ERROR(BSL_LS_TKS_TUNNEL,
    584                   (BSL_META("Tunnel RX pkt: unpack failed\n")));
    585         bcm_rx_remote_pkt_free(rx_pkt);
    586         return;
    587     }
    588 
    589     rx_pkt->flags |= BCM_RX_TUNNELLED;
    590 
    591     /* Copy the data into the packet */
    592     sal_memcpy(rx_pkt->_pkt_data.data, ap_data, ap_len);
    593 
    594     /* Map the cpu/unit to the BCM unit number */
    595     cpudb_key_format(src_key, keybuf, CPUDB_KEY_STRING_LEN);
    596     bcm_unit = bcm_find("client", keybuf, rx_pkt->rx_unit);
    597     if (bcm_unit < 0) {
    598         LOG_INFO(BSL_LS_TKS_TUNNEL,
    599                  (BSL_META("Tunnel RX pkt: unit/cpu not found: %s.%d;"
    600                            CPUDB_KEY_FMT_EOLN),
    601                   keybuf, rx_pkt->rx_unit,
    602                   CPUDB_KEY_DISP(src_key)));
    603         bcm_rx_remote_pkt_free(rx_pkt);
    604         return;
    605     }
    606     /* Insert the packet into the RX queues */
    607 
    608     /* Overwrite unit number with locally meaningful unit number */
    609     rx_pkt->rx_unit = bcm_unit;
    610 
    611     LOG_VERBOSE(BSL_LS_TKS_TUNNEL,
    612                 (BSL_META("Tunnel handler bcm_u %d. u %d p %d. sm %d "
    613                           "sp %d cos %d prio_int %d.\n"),
    614                  bcm_unit, rx_pkt->rx_unit, rx_pkt->rx_port,
    615                  rx_pkt->src_mod, rx_pkt->src_port, rx_pkt->cos,
    616                  rx_pkt->prio_int));
    617 
    618     rv = bcm_rx_remote_pkt_enqueue(bcm_unit, rx_pkt);
    619     if (rv < 0) {
    620         LOG_WARN(BSL_LS_TKS_TUNNEL,
    621                  (BSL_META("Tunnel RX pkt: rx enqueue failed %d: %s\n"),
    622                   rv, bcm_errmsg(rv)));
    623         bcm_rx_remote_pkt_free(rx_pkt);
    624     }
    625 
    626     return;
    627 }
    628 
    629 
    630 
    631 
    632 /****************************************************************
    633  *
    634  * Packet TX tunnelling code
    635  *
    636  * TX Tunnelling is meant to forward packets from the master to slave
    637  * units only.  Again, the transmit function is programmable.
    638  *
    639  * Reliable and best effort tunnelling are both supported.
    640  *
    641  * The code is divided into that which runs on the slave and that
    642  * which runs on the master.
    643  *
    644  *      BCM_CPU_TUNNEL_PACKET_RELIABLE      Use reliable trx
    645  *      BCM_CPU_TUNNEL_PACKET_BEST_EFFORT   Use best effort
    646  *      BCM_CPU_TUNNEL_PACKET               Use best effort if present;
    647  *                                      otherwise use reliable.
    648  *
    649  * The current implementation does alloc/frees, so will be very
    650  * slow.  Packet pools may be added in the future.
    651  */
    652 
    653 
    654 /****************************************************************
    655  *
    656  * TUNNEL TX CODE, SOURCE (master)
    657  */
    658 
    659 /* Function called back after TX */
    660 STATIC void
    661 ct_tx_tunnel_done_cb(uint8 *pkt_data, void *cookie, int rv)
    662 {
    663     bcm_pkt_t *pkt = (bcm_pkt_t *)cookie;
    664 
    665     /* allocated in ct_tx_tunnel */
    666     atp_tx_data_free(pkt_data);
    667     if (pkt != NULL && pkt->call_back != NULL) {
    668         pkt->call_back(pkt->unit, pkt, NULL);
    669     }
    670 }
    671 
    672 /* Bytes in a packed port bitmap */
    673 #define PBMP_BYTES (4 * _SHR_PBMP_WORD_MAX)
    674 
    675 #define TUNNEL_TX_HEADER_BYTES \
    676         (2 + (2*1) + 2 + 1 + 2 + (2*1) + 4 + 1 + 1 + 4 + \
    677          (2 * PBMP_BYTES) + 1 + 1 + 4 + 2 + (13*4) + (2*4))
    678 
    679 int
    680 ct_tx_tunnel_setup(void)
    681 {
    682     int rv;
    683 
    684 #if CT_TUNNEL_QUEUE_ENABLE
    685     rv = ct_tx_tunnel_thread_init();
    686     if (rv < 0) {
    687         LOG_ERROR(BSL_LS_TKS_TUNNEL,
    688                   (BSL_META("Could not init tunnel thread %d: %s"),
    689                    rv, bcm_errmsg(rv)));
    690         return rv;
    691     }
    692 #endif
    693 
    694     rv = atp_register(
    695         SHARED_CLIENT_ID_TUNNEL_TX_PKT,
    696         ATP_F_REASSEM_BUF,
    697         ct_tx_tunnelled_pkt_handler, NULL, -1, -1);
    698     if (rv < 0) {
    699         LOG_ERROR(BSL_LS_TKS_TUNNEL,
    700                   (BSL_META("Tunnel: Failed to register for tx tunnel %d: %s\n"),
    701                    rv, bcm_errmsg(rv)));
    702         return rv;
    703     }
    704 
    705     rv = atp_register(
    706         SHARED_CLIENT_ID_TUNNEL_TX_PKT_NO_ACK,
    707         ATP_F_NO_ACK | ATP_F_REASSEM_BUF,
    708         ct_tx_tunnelled_pkt_handler, NULL, -1, -1);
    709     if (rv < 0) {
    710         LOG_ERROR(BSL_LS_TKS_TUNNEL,
    711                   (BSL_META("Tunnel: Failed to register for tx best effort %d: %s\n"),
    712                    rv, bcm_errmsg(rv)));
    713         return rv;
    714     }
    715 
    716     /* Install the CT TX tunnel routine to the BCM layer */
    717     rv = bcm_tx_cpu_tunnel_set(ct_tx_tunnel);
    718     if (rv < 0) {
    719         LOG_ERROR(BSL_LS_TKS_TUNNEL,
    720                   (BSL_META("Tunnel: Failed to register tunnel TX "
    721                             "with BCM layer %d: %s\n"),
    722                    rv, bcm_errmsg(rv)));
    723         return rv;
    724     }
    725 
    726     return BCM_E_NONE;
    727 }
    728 
    729 int
    730 ct_tx_tunnel_stop(void)
    731 {
    732     int rv;
    733 
    734     /* Unregister hook */
    735     rv = bcm_tx_cpu_tunnel_set(NULL);
    736 
    737     /* Unregister ATP */
    738     atp_unregister(SHARED_CLIENT_ID_TUNNEL_TX_PKT);
    739     atp_unregister(SHARED_CLIENT_ID_TUNNEL_TX_PKT_NO_ACK);
    740 
    741 #if CT_TUNNEL_QUEUE_ENABLE
    742     /* Stop thread */
    743     rv = ct_tx_tunnel_thread_stop();
    744 #endif
    745 
    746     return rv;
    747 }
    748 
    749 /* Pack/unpack TX tunnelled header data; return the updated data pointer */
    750 STATIC uint8 *
    751 ct_tx_tunnel_pack(uint8 *pkt_data, bcm_pkt_t *pkt, int dest_unit,
    752                   int remote_port, uint32 flags, int dlen)
    753 {
    754     uint32 word;
    755     int i;
    756     int remunit;
    757 #if defined(BROADCOM_DEBUG)
    758     uint8 *pkt_data0 = pkt_data;
    759 #endif
    760 
    761     /* Change TUNNEL_TX_HEADER_BYTES when the packing changes. */
    762     CT_INCR_PACK_U16(pkt_data, dlen);
    763     CT_INCR_PACK_U8(pkt_data, pkt->cos);
    764     CT_INCR_PACK_U8(pkt_data, pkt->prio_int);
    765     CT_INCR_PACK_U16(pkt_data, pkt->src_port);
    766     CT_INCR_PACK_U8(pkt_data, pkt->src_mod & 0xFF);
    767     CT_INCR_PACK_U16(pkt_data, pkt->dest_port);
    768     CT_INCR_PACK_U8(pkt_data, pkt->dest_mod & 0xFF);
    769     CT_INCR_PACK_U8(pkt_data, pkt->opcode);
    770     CT_INCR_PACK_U32(pkt_data, pkt->flags);
    771 
    772     (void)bcm_unit_remote_unit_get(dest_unit, &remunit);
    773     CT_INCR_PACK_U8(pkt_data, remunit);
    774     CT_INCR_PACK_U8(pkt_data, remote_port);
    775     CT_INCR_PACK_U32(pkt_data, flags);
    776 
    777     if (flags & BCM_CPU_TUNNEL_F_PBMP) {
    778         for (i = 0; i < _SHR_PBMP_WORD_MAX; i++) {
    779             word = _SHR_PBMP_WORD_GET(pkt->tx_pbmp, i);
    780             _SHR_PACK_LONG(pkt_data, word);
    781             pkt_data += 4;
    782         }
    783         for (i = 0; i < _SHR_PBMP_WORD_MAX; i++) {
    784             word = _SHR_PBMP_WORD_GET(pkt->tx_upbmp, i);
    785             _SHR_PACK_LONG(pkt_data, word);
    786             pkt_data += 4;
    787         }
    788     }
    789 
    790     /* to maintain backwards compatibility, pack the extented src & dest mod
    791      * bits at the end of the buffer
    792      */
    793     CT_INCR_PACK_U8(pkt_data, (pkt->src_mod >> 8) & 0xFF);
    794     CT_INCR_PACK_U8(pkt_data, (pkt->dest_mod >> 8) & 0xFF);
    795     
    796     for (i=0; i<4; i++) {
    797         CT_INCR_PACK_U8(pkt_data, pkt->_vtag[i]);
    798     }
    799     
    800     CT_INCR_PACK_U16(pkt_data, pkt->vlan);
    801     CT_INCR_PACK_U32(pkt_data, pkt->color);
    802     CT_INCR_PACK_U32(pkt_data, pkt->dst_gport);
    803     CT_INCR_PACK_U32(pkt_data, pkt->src_gport);
    804     CT_INCR_PACK_U32(pkt_data, pkt->multicast_group);
    805     CT_INCR_PACK_U32(pkt_data, pkt->stk_flags);
    806     CT_INCR_PACK_U32(pkt_data, pkt->stk_forward);
    807     CT_INCR_PACK_U32(pkt_data, pkt->stk_classification_tag);
    808     CT_INCR_PACK_U32(pkt_data, pkt->stk_pkt_prio);
    809     CT_INCR_PACK_U32(pkt_data, pkt->stk_dscp);
    810     CT_INCR_PACK_U32(pkt_data, pkt->stk_load_balancing_number);
    811     CT_INCR_PACK_U32(pkt_data, pkt->rx_timestamp_upper);
    812     CT_INCR_PACK_U32(pkt_data, pkt->timestamp_flags);
    813     CT_INCR_PACK_U32(pkt_data, pkt->stk_encap_id);
    814 
    815     CT_INCR_PACK_U32(pkt_data, pkt->flags2);
    816 
    817     /* OAM SOMBH header fields */
    818     CT_INCR_PACK_U8(pkt_data, pkt->oam_replacement_type);
    819     CT_INCR_PACK_U8(pkt_data, pkt->oam_replacement_offset);
    820     CT_INCR_PACK_U16(pkt_data, pkt->oam_lm_counter_index);
    821 
    822 #if defined(BROADCOM_DEBUG)
    823     assert((pkt_data - pkt_data0) == TUNNEL_TX_HEADER_BYTES);
    824 #endif
    825 
    826     return pkt_data;
    827 }
    828 
    829 STATIC uint8 *
    830 ct_tx_tunnel_unpack(uint8 *pkt_data, int len, bcm_pkt_t *pkt, int *pkt_len_p,
    831                     int *local_unit, int *local_port, uint32 *flags)
    832 {
    833     int i;
    834     uint32 word;
    835     uint8 tmp;
    836     int pkt_len;
    837 
    838     CT_INCR_UNPACK_U16(pkt_data, pkt_len);
    839     if (len < pkt_len + TUNNEL_TX_HEADER_BYTES) {
    840         return NULL;   /* Not enough bytes in packet */
    841     }
    842 
    843     *pkt_len_p = pkt_len;
    844     CT_INCR_UNPACK_U8(pkt_data, pkt->cos);
    845     CT_INCR_UNPACK_U8(pkt_data, pkt->prio_int);
    846     CT_INCR_UNPACK_U16(pkt_data, pkt->src_port);
    847     CT_INCR_UNPACK_U8(pkt_data, pkt->src_mod);
    848     CT_INCR_UNPACK_U16(pkt_data, pkt->dest_port);
    849     CT_INCR_UNPACK_U8(pkt_data, pkt->dest_mod);
    850     CT_INCR_UNPACK_U8(pkt_data, pkt->opcode);
    851     CT_INCR_UNPACK_U32(pkt_data, pkt->flags);
    852     CT_INCR_UNPACK_U8(pkt_data, *local_unit);
    853     CT_INCR_UNPACK_U8(pkt_data, *local_port);
    854     CT_INCR_UNPACK_U32(pkt_data, *flags);
    855 
    856 
    857     if (*flags & BCM_CPU_TUNNEL_F_PBMP) {
    858         for (i = 0; i < _SHR_PBMP_WORD_MAX; i++) {
    859             _SHR_UNPACK_LONG(pkt_data, word);
    860             pkt_data += 4;
    861             _SHR_PBMP_WORD_SET(pkt->tx_pbmp, i, word);
    862         }
    863         for (i = 0; i < _SHR_PBMP_WORD_MAX; i++) {
    864             _SHR_UNPACK_LONG(pkt_data, word);
    865             pkt_data += 4;
    866             _SHR_PBMP_WORD_SET(pkt->tx_upbmp, i, word);
    867         }
    868     }
    869 
    870     /* to maintain backwards compatibility, unpack the extented src & dest mod
    871      * bits at the end of the buffer
    872      */
    873     CT_INCR_UNPACK_U8(pkt_data, tmp);
    874     pkt->src_mod |= tmp << 8;
    875 
    876     CT_INCR_UNPACK_U8(pkt_data, tmp);
    877     pkt->dest_mod |= tmp << 8;
    878 
    879     for (i=0; i<4; i++) {
    880         CT_INCR_UNPACK_U8(pkt_data, pkt->_vtag[i]);
    881     }
    882 
    883     CT_INCR_UNPACK_U16(pkt_data, pkt->vlan);
    884     CT_INCR_UNPACK_U32(pkt_data, pkt->color);
    885     CT_INCR_UNPACK_U32(pkt_data, pkt->dst_gport);
    886     CT_INCR_UNPACK_U32(pkt_data, pkt->src_gport);
    887     CT_INCR_UNPACK_U32(pkt_data, pkt->multicast_group);
    888     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_flags);
    889     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_forward);
    890     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_classification_tag);
    891     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_pkt_prio);
    892     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_dscp);
    893     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_load_balancing_number);
    894     CT_INCR_UNPACK_U32(pkt_data, pkt->rx_timestamp_upper);
    895     CT_INCR_UNPACK_U32(pkt_data, pkt->timestamp_flags);
    896     CT_INCR_UNPACK_U32(pkt_data, pkt->stk_encap_id);
    897 
    898     CT_INCR_UNPACK_U32(pkt_data, pkt->flags2);
    899 
    900     /* OAM SOMBH header fields */
    901     CT_INCR_UNPACK_U8(pkt_data, pkt->oam_replacement_type);
    902     CT_INCR_UNPACK_U8(pkt_data, pkt->oam_replacement_offset);
    903     CT_INCR_UNPACK_U16(pkt_data, pkt->oam_lm_counter_index);
    904 
    905     return pkt_data;
    906 }
    907 
    908 /*
    909  * Function:
    910  *      ct_tx_tunnel
    911  * Purpose:
    912  *      Tunnel a packet out a single port via a remote CPU
    913  * Parameters:
    914  *      pkt         - The packet data and meta-data to tunnel
    915  *      dest_unit   - The BCM unit to tunnel to
    916  *      remote_port - The port on dest_unit on which packet should egress
    917  *      flags       - Indicates untagged settings
    918  *      mode        - Reliable/best effort tunnelling
    919  * Returns:
    920  *      BCM_E_XXX
    921  * Notes:
    922  *      Always sends async, but data is copied from parameter;
    923  *      If a callback is indicated in the packet, that will be made after
    924  *      local transmit
    925  *
    926  *      If flags & BCM_CPU_TUNNEL_F_PBMP is set, then remote_port is ignored
    927  *      and the port bitmaps are taken from the packet directly.
    928  */
    929 
    930 #define KEY_BUF_LEN 8
    931 int
    932 ct_tx_tunnel(bcm_pkt_t *pkt,
    933              int dest_unit,
    934              int remote_port,
    935              uint32 flags,
    936              bcm_cpu_tunnel_mode_t mode)
    937 {
    938     uint8 *pkt_data, *alloc_ptr;
    939     int len, dlen;
    940     int i;
    941     int rv;
    942     int client_id;
    943     uint32 ct_flags = 0;
    944     cpudb_key_t dest_key;
    945     char dest_key_str[CPUDB_KEY_STRING_LEN];
    946 
    947     LOG_VERBOSE(BSL_LS_TKS_TUNNEL,
    948                 (BSL_META("CT Tunnel pkt out to (%d, %d), flags 0x%x, mode %d\n"),
    949                  dest_unit, remote_port, flags, mode));
    950 
    951     if (!bcm_unit_valid(dest_unit)) {
    952         return BCM_E_PARAM;
    953     }
    954 
    955     if (bcm_unit_local(dest_unit)) {
    956         return BCM_E_PARAM;
    957     }
    958 
    959     dlen = 0;
    960     for (i = 0; i < pkt->blk_count; i++) {
    961         dlen += pkt->pkt_data[i].len;
    962     }
    963 
    964     len = dlen + TUNNEL_TX_HEADER_BYTES;
    965     /* Freed either in this function (on error) or in ct_tx_tunnel_done_cb */
    966     pkt_data = alloc_ptr = atp_tx_data_alloc(len);
    967     if (alloc_ptr == NULL) {
    968         return BCM_E_MEMORY;
    969     }
    970 
    971     /* Pack up the metadata for the packet */
    972     pkt_data = ct_tx_tunnel_pack(pkt_data, pkt, dest_unit, remote_port,
    973                                  flags, dlen);
    974 
    975     /* Copy the packet data to send out */
    976     for (i = 0; i < pkt->blk_count; i++) {
    977         sal_memcpy(pkt_data, pkt->pkt_data[i].data, pkt->pkt_data[i].len);
    978         pkt_data += pkt->pkt_data[i].len;
    979     }
    980 
    981     if (mode == BCM_CPU_TUNNEL_PACKET_RELIABLE) {
    982         client_id = SHARED_CLIENT_ID_TUNNEL_TX_PKT;
    983     } else {
    984         client_id = SHARED_CLIENT_ID_TUNNEL_TX_PKT_NO_ACK;
    985     }
    986 
    987     CPUTRANS_COS_SET(ct_flags, pkt->cos);
    988     if (pkt->flags & BCM_TX_PRIO_INT) {
    989         CPUTRANS_INT_PRIO_SET(ct_flags, pkt->prio_int);
    990     }
    991 
    992     /* Only pass the packet as a cookie if the callback is != NULL;
    993      * Otherwise app may free pkt before it's examined by callback.
    994      */
    995 
    996     rv = bcm_unit_subtype_get(dest_unit, dest_key_str,
    997                                sizeof(dest_key_str));
    998     if (rv < 0) {
    999         LOG_WARN(BSL_LS_TKS_TUNNEL,
   1000                  (BSL_META("Tunnel TX: Could not get dest key string, %d: %s\n"),
   1001                   rv, bcm_errmsg(rv)));
   1002         atp_tx_data_free(alloc_ptr);
   1003         return rv;
   1004     }
   1005 
   1006 
   1007     rv = cpudb_key_parse(dest_key_str, &dest_key);
   1008     if (rv < 0) {
   1009         LOG_WARN(BSL_LS_TKS_TUNNEL,
   1010                  (BSL_META("Tunnel TX: Could not parse dest key string, %d: %s\n"),
   1011                   rv, bcm_errmsg(rv)));
   1012         atp_tx_data_free(alloc_ptr);
   1013         return rv;
   1014     }
   1015 
   1016     LOG_VERBOSE(BSL_LS_TKS_TUNNEL,
   1017                 (BSL_META("CT Tunnel dest key %x %x %x %x %x %x\n"),
   1018                  dest_key.key[0],
   1019                  dest_key.key[1],
   1020                  dest_key.key[2],
   1021                  dest_key.key[3],
   1022                  dest_key.key[4],
   1023                  dest_key.key[5]));
   1024     rv = atp_tx(dest_key,
   1025                 client_id,
   1026                 alloc_ptr,
   1027                 len,
   1028                 ct_flags,
   1029                 ct_tx_tunnel_done_cb,
   1030                 (void *)(pkt->call_back != NULL ? pkt : NULL));
   1031 
   1032     if (rv < 0) {
   1033         LOG_VERBOSE(BSL_LS_TKS_TUNNEL,
   1034                     (BSL_META("Tunnel TX: Error sending %d: %s\n"),
   1035                      rv, bcm_errmsg(rv)));
   1036         atp_tx_data_free(alloc_ptr);
   1037     }
   1038 
   1039     return rv;
   1040 }
   1041 
   1042 /****************************************************************
   1043  *
   1044  * TUNNEL TX CODE, FORWARDER (slave)
   1045  *
   1046  *    This is the code that accepts a tunnelled packet and
   1047  * forwards it out the indicated local port.
   1048  */
   1049 
   1050 #if CT_TUNNEL_QUEUE_ENABLE
   1051 
   1052 STATIC int
   1053 ct_tx_tunnel_enqueue(void *pkt, bcm_rx_t *handled, uint8 *pkt_data, int len)
   1054 {
   1055     int head, new_head, rv;
   1056 
   1057     TUNNEL_Q_LOCK;
   1058     head = new_head = _tunnel_q_head;
   1059     rv = BCM_E_NONE;
   1060 
   1061     /* Incr new_head, handle wraparound */
   1062     if (++new_head >= CT_TUNNEL_QUEUE_SIZE) {
   1063         new_head = 0;
   1064     }
   1065 
   1066     /* Check for queue full */
   1067     if (new_head != _tunnel_q_tail) {
   1068         _tunnel_q_head = new_head;
   1069         _tunnel_q[head].data = pkt_data;
   1070         _tunnel_q[head].len  = len;
   1071         _tunnel_q[head].pkt  = pkt;
   1072     } else {
   1073         rv = BCM_E_RESOURCE;
   1074         _tunnel_q_top_full++;
   1075     }
   1076 
   1077     TUNNEL_Q_UNLOCK;
   1078 
   1079     if (BCM_SUCCESS(rv)) {
   1080         TUNNEL_Q_WAKE;
   1081         *handled = BCM_RX_HANDLED_OWNED;
   1082     } else {
   1083         *handled = BCM_RX_HANDLED;
   1084     }
   1085 
   1086     return rv;
   1087 }
   1088 
   1089 STATIC ct_tunnel_q_element *
   1090 ct_tx_tunnel_dequeue(void)
   1091 {
   1092     ct_tunnel_q_element *element = NULL;
   1093 
   1094     TUNNEL_Q_LOCK;
   1095     if (_tunnel_q_head != _tunnel_q_tail) {
   1096         element = _tunnel_q + _tunnel_q_tail;
   1097         /* Incr tail, handle wraparound */
   1098         if (++_tunnel_q_tail >= CT_TUNNEL_QUEUE_SIZE) {
   1099             _tunnel_q_tail = 0;
   1100         }
   1101     }
   1102     TUNNEL_Q_UNLOCK;
   1103 
   1104     return element;
   1105 }
   1106 
   1107 STATIC void
   1108 ct_tx_tunnel_thread(void *cookie)
   1109 {
   1110     ct_tunnel_q_element *element = NULL;
   1111     int rv;
   1112 
   1113     COMPILER_REFERENCE(cookie);
   1114     _tunnel_q_thread_exit = 0;
   1115     for (;;) {
   1116 
   1117         TUNNEL_Q_SLEEP;
   1118 
   1119         while ((element = ct_tx_tunnel_dequeue()) != NULL) {
   1120             rv = ct_tx_tunnel_forward(element->data, element->len);
   1121             atp_rx_free(element->data, element->pkt);
   1122             if (rv < 0) {
   1123                 _tunnel_q_error++;
   1124             }
   1125         }
   1126 
   1127         if (_tunnel_q_thread_exit) {
   1128             _tunnel_q_thread = SAL_THREAD_ERROR;
   1129             sal_thread_exit(0);
   1130             return;
   1131         }
   1132     }
   1133 }
   1134 
   1135 STATIC int
   1136 ct_tx_tunnel_thread_init(void)
   1137 {
   1138     if (_tunnel_q_thread != SAL_THREAD_ERROR) {
   1139         return BCM_E_BUSY;
   1140     }
   1141 
   1142     /* Reset variables */
   1143     _tunnel_q_top_full = 0;
   1144     _tunnel_q_error = 0;
   1145     _tunnel_q_head = _tunnel_q_tail = 0;
   1146 
   1147     _tunnel_q_lock = sal_mutex_create("bcm_tunnel_q");
   1148     _tunnel_q_sem = sal_sem_create("bcm_tunnel_q", sal_sem_BINARY, 0);
   1149     _tunnel_q_thread = sal_thread_create("bcmTUNQ",
   1150                                          TUNNEL_Q_THREAD_STACK,
   1151                                          TUNNEL_Q_THREAD_PRIO,
   1152                                          ct_tx_tunnel_thread,
   1153                                          NULL);
   1154     if (_tunnel_q_thread == SAL_THREAD_ERROR) {
   1155         sal_sem_destroy(_tunnel_q_sem);
   1156         sal_mutex_destroy(_tunnel_q_lock);
   1157         _tunnel_q_lock = NULL;
   1158         return BCM_E_RESOURCE;
   1159     }
   1160 
   1161     return BCM_E_NONE;
   1162 
   1163 }
   1164 
   1165 /*
   1166  * Stop the tunnel queue thread
   1167  */
   1168 STATIC int
   1169 ct_tx_tunnel_thread_stop(void)
   1170 {
   1171     if (_tunnel_q_thread == SAL_THREAD_ERROR) {
   1172         return BCM_E_NONE;
   1173     }
   1174     _tunnel_q_thread_exit = 1;
   1175     TUNNEL_Q_WAKE;
   1176     sal_thread_yield();
   1177     while (_tunnel_q_thread != SAL_THREAD_ERROR) {
   1178         TUNNEL_Q_WAKE;
   1179         sal_usleep(10000);
   1180     }
   1181     sal_sem_destroy(_tunnel_q_sem);
   1182     sal_mutex_destroy(_tunnel_q_lock);
   1183     _tunnel_q_lock = NULL;
   1184     return BCM_E_NONE;
   1185 }
   1186 
   1187 #define ct_tx_tunnel_forward_function ct_tx_tunnel_enqueue
   1188 
   1189 #else
   1190 
   1191 #define ct_tx_tunnel_forward_function ct_tx_tunnel_forward_sync
   1192 
   1193 STATIC int
   1194 ct_tx_tunnel_forward_sync(void *pkt, bcm_rx_t *handled,
   1195                           uint8 *pkt_data, int len)
   1196 {
   1197     COMPILER_REFERENCE(pkt);
   1198     *handled = BCM_RX_HANDLED;
   1199     return ct_tx_tunnel_forward(pkt_data, len);
   1200 }
   1201 
   1202 #endif /* CT_TUNNEL_QUEUE_ENABLE */
   1203 
   1204 /* ATP handler for TX tunnelled packet */
   1205 STATIC bcm_rx_t
   1206 ct_tx_tunnelled_pkt_handler(cpudb_key_t src_key,
   1207                             int client_id,
   1208                             bcm_pkt_t *pkt,
   1209                             uint8 *payload,
   1210                             int payload_len,
   1211                             void *cookie)
   1212 {
   1213     int rv;
   1214     bcm_rx_t handled;
   1215 
   1216     LOG_VERBOSE(BSL_LS_TKS_TUNNEL,
   1217                 (BSL_META("CT Tunnel pkt in from " CPUDB_KEY_FMT " cli %d, len %d\n"),
   1218                  CPUDB_KEY_DISP(src_key), client_id, payload_len));
   1219 
   1220     if (payload == NULL) {
   1221         /* Unsupported forwarding mode */
   1222         LOG_WARN(BSL_LS_TKS_TUNNEL,
   1223                  (BSL_META("Tunnel TX: Received segmented packet to "
   1224                   "forward.  Unsupported\n")));
   1225         return BCM_RX_HANDLED;
   1226     }
   1227 
   1228     rv = ct_tx_tunnel_forward_function(pkt, &handled,
   1229                                        payload, payload_len);
   1230 
   1231     if (rv < 0) {
   1232         LOG_VERBOSE(BSL_LS_TKS_TUNNEL,
   1233                     (BSL_META("Tunnel TX: Error forwarding %d: %s\n"),
   1234                      rv, bcm_errmsg(rv)));
   1235     }
   1236 
   1237     return handled;
   1238 }
   1239 
   1240 /*
   1241  * Function:
   1242  *      ct_tx_tunnel_forward
   1243  * Purpose:
   1244  *      Forward a packet received for tunnelling
   1245  * Parameters:
   1246  *      pkt_data  - The start of the encapsulated packet
   1247  *      len       - Length of encapsulated packet
   1248  * Returns:
   1249  *      BCM_E_XXX
   1250  * Notes:
   1251  *      Sends sync only.
   1252  *      Assumes data in pkt_data is DMA'able
   1253  */
   1254 
   1255 int
   1256 ct_tx_tunnel_forward(uint8 *pkt_data, int len)
   1257 {
   1258     int pkt_len;
   1259     int local_unit;
   1260     int local_port; /* Not used if PBMP flag is set */
   1261     bcm_pkt_t pkt;
   1262     uint32 flags;
   1263     int rv;
   1264 
   1265     if (len <= TUNNEL_TX_HEADER_BYTES) {
   1266         return BCM_E_PARAM;
   1267     }
   1268     sal_memset(&pkt, 0, sizeof(pkt));
   1269 
   1270     /* Unpack the metadata */
   1271     pkt_data =
   1272         ct_tx_tunnel_unpack(pkt_data, len, &pkt, &pkt_len,
   1273                             &local_unit, &local_port, &flags);
   1274     if (pkt_data == NULL) {
   1275         return BCM_E_RESOURCE;   /* Not enough bytes in packet */
   1276     }
   1277     /* pkt_data now points to start of payload to send out */
   1278 
   1279     if (!(flags & BCM_CPU_TUNNEL_F_PBMP)) {
   1280         /* Generate bitmap from single local port */
   1281         BCM_PBMP_PORT_SET(pkt.tx_pbmp, local_port);
   1282         if (flags & BCM_CPU_TUNNEL_F_UNTAGGED) {
   1283             BCM_PBMP_PORT_SET(pkt.tx_upbmp, local_port);
   1284         }
   1285     }
   1286 
   1287     BCM_PKT_ONE_BUF_SETUP(&pkt, pkt_data, pkt_len);
   1288 
   1289     /* Send synchronosly using packet data passed to us. */
   1290     rv = bcm_tx(local_unit, &pkt, NULL);
   1291 
   1292 
   1293     return rv;
   1294 }
   1295 
   1296 #endif /* BCM_RPC_SUPPORT */