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

pkt.c (18923B)


      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 
      8 #include <shared/alloc.h>
      9 #include <sal/core/libc.h>
     10 
     11 #include <soc/cm.h>
     12 #include <soc/drv.h>
     13 
     14 #include <bcm/error.h>
     15 #include <bcm/types.h>
     16 #include <bcm/rx.h>
     17 #include <bcm/pkt.h>
     18 #include <bcm_int/control.h>
     19 #if defined(INCLUDE_L3) && defined(BCM_FIREBOLT_SUPPORT)
     20 #include <bcm_int/esw/firebolt.h>
     21 #include <bcm_int/esw/l3.h>
     22 #endif
     23 
     24 #define UNIT_VALID(unit) \
     25 { \
     26   if (!BCM_UNIT_VALID(unit)) { return BCM_E_UNIT; } \
     27 }
     28 
     29 /*
     30  * Function:
     31  *      bcm_pkt_byte_index
     32  * Purpose:
     33  *      Return a pointer to a location in a packet
     34  * Parameters:
     35  *      pkt - The packet of interest
     36  *      n   - Byte offset in the packet
     37  *      len - (OUT) number of bytes left in this allocation block
     38  *      blk - (OUT) if not NULL, gets the pointer to the current block
     39  *      location - (OUT) pointer to the requested byte
     40  * Returns:
     41  *      BCM_E_XXX
     42  */
     43 
     44 int
     45 bcm_pkt_byte_index(bcm_pkt_t *pkt, int n, int *len, int *blk_idx,
     46                    uint8 **location)
     47 {
     48     int cnt = 0;
     49     int blk = 0;
     50     uint8 *ptr = NULL;
     51     int offset;
     52 
     53     for (blk = 0; blk < pkt->blk_count; blk++) {
     54         if (cnt + pkt->pkt_data[blk].len > n) {
     55             offset = n - cnt;
     56             ptr = &pkt->pkt_data[blk].data[offset];
     57             if (len) {
     58                 *len = pkt->pkt_data[blk].len - offset;
     59             }
     60             if (blk_idx) {
     61                 *blk_idx = blk;
     62             }
     63             break;
     64         } else {
     65             cnt += pkt->pkt_data[blk].len;
     66         }
     67     }
     68 
     69     *location = ptr;
     70     return (NULL !=ptr) ? BCM_E_NONE : BCM_E_NOT_FOUND;
     71 }
     72 
     73 
     74 /*
     75  * Function:
     76  *      bcm_pkt_memcpy
     77  * Purpose:
     78  *
     79  * Parameters:
     80  *      pkt - Packet to copy into
     81  *      dest_byte - Integer offset into packet
     82  *      src - Source buffer to copy from
     83  *      len - Number of bytes to copy
     84  * Returns:
     85  *      Number of bytes actually copied
     86  */
     87 
     88 int
     89 bcm_pkt_memcpy(bcm_pkt_t *pkt, int dest_byte, uint8 *src, int len)
     90 {
     91     int blk;
     92     uint8 *ptr = NULL;
     93     int blk_bytes, rv;
     94     int copied = 0;
     95     
     96     rv = bcm_pkt_byte_index(pkt, dest_byte, &blk_bytes, &blk, &ptr);
     97 
     98     if ((BCM_E_NONE == rv) && (ptr)) {
     99         while (1) {
    100             if (blk_bytes > 0) {
    101                 if (len - copied <= blk_bytes) { /* Last block */
    102                     sal_memcpy(ptr, &src[copied], len - copied);
    103                     copied = len;
    104                     break;
    105                 }
    106                 sal_memcpy(ptr, &src[copied], blk_bytes);
    107                 copied += blk_bytes;
    108             }
    109             if (++blk >= pkt->blk_count) {
    110                 break;
    111             }
    112             ptr = pkt->pkt_data[blk].data;
    113             blk_bytes = pkt->pkt_data[blk].len;
    114         }
    115     }
    116 
    117     return copied;
    118 }
    119 
    120 /*
    121  * Function:
    122  *      bcm_pkt_t_init
    123  * Purpose:
    124  *      Initialize packet structure.
    125  * Parameters:
    126  *      pkt - Pointer to packet structure.
    127  * Returns:
    128  *      NONE
    129  */
    130 void
    131 bcm_pkt_t_init(bcm_pkt_t *pkt)
    132 {
    133     if (pkt != NULL) {
    134         sal_memset(pkt, 0, sizeof (*pkt));
    135     }
    136     return;
    137 }
    138 
    139 /*
    140  * Function:
    141  *      bcm_pkt_blk_t_init
    142  * Purpose:
    143  *      Initialize packet block structure.
    144  * Parameters:
    145  *      pkt_blk - Pointer to packet block structure.
    146  * Returns:
    147  *      NONE
    148  */
    149 void
    150 bcm_pkt_blk_t_init(bcm_pkt_blk_t *pkt_blk)
    151 {
    152     if (pkt_blk != NULL) {
    153         sal_memset(pkt_blk, 0, sizeof (*pkt_blk));
    154     }
    155     return;
    156 }
    157 
    158 /*
    159  * Function:
    160  *      bcm_pkt_clear
    161  * Purpose:
    162  *      Clear a packet structure and install its data buffer
    163  * Parameters:
    164  *      unit - for what unit is this being set up
    165  *      pkt - pointer to pointer packet to setup.  (*pkt) may be NULL
    166  *      blks - Pointer to array of gather blocks for the packet
    167  *      blk_count - Number of elts in the array
    168  *      flags - flags for CRC and VLAN tag.  See notes.
    169  *      pkt_buf (OUT) - pkt, or allocated packet if pkt is NULL
    170  * Returns:
    171  *      Pointer to packet or NULL if cannot allocate new packet.
    172  * Notes:
    173  *      If pkt is null, allocate a new one with sal_alloc.
    174  *
    175  *      Flags can be the bitwise or of:
    176  *        BCM_TX_CRC_NONE        No action on CRC
    177  *        BCM_TX_CRC_ALLOC       CRC is not in packet; allocate
    178  *        BCM_TX_CRC_REGEN       Regenerate the CRC on egress
    179  *        BCM_TX_CRC_APPEND      Allocate and regenerate (same as alloc)
    180  *        BCM_PKT_F_NO_VTAG      Packet does not contain vlan tag
    181  *
    182  *      In addition, the following may be used to override normal
    183  *      behavior, but are not generally advertised or documented.
    184  *        BCM_TX_CRC_FORCE_ERROR Force an error in the CRC (unsupported)
    185  *        BCM_PKT_F_HGHDR        HiGig header setup for packet DMA
    186  *        BCM_PKT_F_SLTAG        SL tag setup for packet DMA
    187  *
    188  *      The payload length of the packet is set as large as possible
    189  *      assuming the allocation blocks contain the MAC addresses and
    190  *      (unless NO_VTAG is specified) the VLAN tag; if CRC append (or alloc)
    191  *      is indicated, the CRC is assumed NOT to be part of the gather
    192  *      blocks.
    193  */
    194 
    195 int
    196 bcm_pkt_clear(int unit, bcm_pkt_t *pkt, bcm_pkt_blk_t *blks, int blk_count,
    197               uint32 flags, bcm_pkt_t **pkt_buf)
    198 {
    199     int rv, i;
    200     int bytes = 0;
    201     int local_alloc = FALSE;
    202 
    203     UNIT_VALID(unit);
    204 
    205     if (pkt == NULL) {  /* Allocate new packet */
    206         local_alloc = TRUE;
    207         if ((pkt = sal_alloc(sizeof(bcm_pkt_t), "pkt_setup")) == NULL) {
    208             *pkt_buf = NULL;
    209             return BCM_E_MEMORY;
    210         }
    211     }
    212     sal_memset(pkt, 0, sizeof(bcm_pkt_t));
    213     pkt->unit = unit;
    214 
    215     if (blk_count == 0) {
    216         /*
    217          * Permit allocation of an empty packet structure.
    218          * A single buffer can be added alter using the
    219          * BCM_PKT_ONE_BUF_SETUP macro.
    220          */
    221         bcm_pkt_flags_init(unit, pkt, flags);
    222     } else {
    223         for (i = 0; i < blk_count; i++) {
    224             bytes += blks[i].len;
    225         }
    226 
    227         if (bytes < BCM_PKT_ALLOC_MIN) {
    228             *pkt_buf = NULL;
    229             if (local_alloc) {
    230                 sal_free(pkt);
    231             }
    232             return BCM_E_MEMORY;
    233         }
    234 
    235         pkt->pkt_data = blks;
    236         pkt->blk_count = blk_count;
    237 
    238         rv = bcm_pkt_flags_len_setup(unit, pkt, bytes, -1, flags);
    239         if (BCM_FAILURE(rv)) {
    240             *pkt_buf = NULL;
    241             if (local_alloc) {
    242                 sal_free(pkt);
    243             }
    244             return rv;
    245         }
    246     }
    247 
    248     *pkt_buf = pkt;
    249     return BCM_E_NONE;
    250 }
    251 
    252 /*
    253  * Function:
    254  *      bcm_pkt_flags_len_setup
    255  * Purpose:
    256  *      Install data in a packet without clearing fields
    257  * Parameters:
    258  *      unit - for what unit is this being set up
    259  *      pkt - the packet to setup
    260  *      buf - buffer to use; must be non-null
    261  *      alloc_bytes - buffer length (allocated)
    262  *      payload_len - Length of payload.  See notes
    263  *      flags - See above.
    264  * Returns:
    265  *      >= 0:  Payload length
    266  *      < 0:   BCM_E_XXX
    267  * Notes:
    268  *      If payload_len < 0, this means make payload as large as possible.
    269  *
    270  *      The payload_len is checked because space for the VLAN tag,
    271  *      HiGig header and SL tag is always allocated.
    272  *
    273  *      The payload length includes everything in the packet EXCEPT:
    274  *          dest and src MAC;
    275  *          VLAN tag (4 bytes)
    276  *          CRC
    277  *          SL Tag
    278  *          HiGig header
    279  *      The txrx length includes all of the above.
    280  *      The packet length value depends on the format indications.
    281  *      It will exclude the VLAN tag if indicated in flags; it will
    282  *      exclude the CRC if CRC_ALLOC is indicated.
    283  *
    284  *      Valid values for CRC are:
    285  *         BCM_TX_CRC_NONE, BCM_TX_CRC_ALLOC, BCM_TX_CRC_REGEN,
    286  *         BCM_TX_CRC_APPEND.  These maybe combined with
    287  *         BCM_TX_CRC_FORCE_ERROR,
    288  */
    289 
    290 int
    291 bcm_pkt_flags_len_setup(int unit, bcm_pkt_t *pkt, int alloc_bytes,
    292                         int payload_len, uint32 flags)
    293 {
    294     UNIT_VALID(unit);
    295 
    296     if (payload_len < 0) {
    297         payload_len = alloc_bytes - BCM_PKT_ALLOC_MIN;
    298     } else if (payload_len > alloc_bytes - BCM_PKT_ALLOC_MIN) {
    299         return BCM_E_PARAM;
    300     }
    301 
    302     bcm_pkt_flags_init(unit, pkt, flags);
    303 
    304     return payload_len;
    305 }
    306 
    307 
    308 int
    309 bcm_pkt_flags_init(int unit, bcm_pkt_t *pkt, uint32 flags)
    310 {
    311     int rv;
    312 
    313     BCM_UNIT_BUSY(unit);
    314     if (BCM_UNIT_VALID(unit)) {
    315         pkt->flags = flags;
    316         pkt->unit = unit;   /* Set unit as well */
    317 
    318         if (BCM_IS_LOCAL(unit)) {
    319             if (SOC_UNIT_VALID(unit) && SOC_IS_XGS12_FABRIC(unit)) {
    320                 pkt->flags |= BCM_PKT_F_HGHDR;
    321             }
    322             /* Was SL flags handling, but SL is no longer supported */
    323         }
    324         rv = BCM_E_NONE;
    325         
    326     } else {
    327         rv = BCM_E_UNIT;
    328     }
    329     BCM_UNIT_IDLE(unit);
    330     
    331     return rv;
    332 }
    333 
    334 
    335 
    336 
    337 
    338 /****************************************************************
    339  *
    340  * Default allocate and free routines.  Uses soc_cm_ shared
    341  * memory routines.  These use single data buffers and do
    342  * runtime allocation and free.
    343  */
    344 
    345 #define DEFAULT_ALLOCATOR_UNIT 0
    346 #define NO_ALLOCATOR_UNIT -1
    347 
    348 /*
    349   Return a local unit number (or NO_ALLOCATOR_UNIT) that can allocate
    350   a buffer for the given unit.
    351 
    352   For local units, the unit returned is the unit passed. For remote
    353   units, return DEFAULT_ALLOCATOR_UNIT if DEFAULT_ALLOCATOR_UNIT unit
    354   itself is valid and local, otherwise return NO_ALLOCATOR_UNIT (which
    355   usually means tunneling to a remote unit when there are no local
    356   units, which is a valid configuration).
    357 
    358 */
    359 
    360 static int
    361 _bcm_pkt_allocator_unit(int unit)
    362 {
    363     /* allocation unit */
    364     if (BCM_IS_REMOTE(unit)) {
    365         unit = (BCM_UNIT_VALID(DEFAULT_ALLOCATOR_UNIT) &&
    366                 BCM_IS_LOCAL(DEFAULT_ALLOCATOR_UNIT)) ?
    367             DEFAULT_ALLOCATOR_UNIT : NO_ALLOCATOR_UNIT;
    368     }
    369 
    370     return unit;
    371 }
    372  
    373 /* could be bcm_pkt_blk_t_alloc */
    374 
    375 static int
    376 _bcm_pkt_data_alloc(int unit, int size, bcm_pkt_blk_t *pkt_data)
    377 {
    378     int	aunit;
    379     int rv = BCM_E_MEMORY;
    380 
    381     /* allocation unit, which may not be the same as unit */
    382     aunit = _bcm_pkt_allocator_unit(unit);
    383 
    384     BCM_UNIT_BUSY(aunit);
    385     /* If aunit == NO_ALLOCATOR_UNIT, use a heap allocator, because
    386        there are no DMAable devices available. */
    387     pkt_data->data = (aunit == NO_ALLOCATOR_UNIT) ?
    388         sal_alloc(size, "pkt alloc data") :
    389         soc_cm_salloc(aunit, size, "pkt alloc data");
    390 
    391     if (pkt_data->data) {
    392         pkt_data->len = size;
    393         rv = BCM_E_NONE;
    394     }
    395     BCM_UNIT_IDLE(aunit);
    396 
    397     return rv; 
    398 }
    399 
    400 static int
    401 _bcm_pkt_data_free(int unit, bcm_pkt_blk_t *pkt_data)
    402 {
    403     int	aunit;
    404 
    405     /* allocation unit, which may not be the same as unit */
    406     aunit = _bcm_pkt_allocator_unit(unit);
    407     BCM_UNIT_BUSY(aunit);
    408     if (pkt_data->data != NULL) {
    409         if (aunit == NO_ALLOCATOR_UNIT) {
    410             sal_free(pkt_data->data);
    411         } else {
    412             soc_cm_sfree(aunit, pkt_data->data);
    413         }
    414     }
    415     pkt_data->data = NULL;
    416     pkt_data->len = 0;
    417     BCM_UNIT_IDLE(aunit);
    418 
    419     return BCM_E_NONE; 
    420 }
    421 
    422 
    423 
    424 /*
    425  * Function:
    426  *      bcm_pkt_alloc
    427  * Purpose:
    428  *      Basic, single block packet allocation using sal and soc functions
    429  * Parameters:
    430  *      unit - Strata unit
    431  *      size - Bytes to allocate
    432  *      flags - See pkt.h for more about these flags
    433  * Returns:
    434  *      Pointer to packet if successful or NULL if not
    435  * Notes:
    436  *	Flags are copied into the packet, and so may indicate if CRC/VLAN
    437  *	should be stripped.
    438  *
    439  *      If the unit allocator returns NO_ALLOCATOR_UNIT, then assume
    440  *      that a DMA allocator is not required, and use a regular memory
    441  *      allocator.
    442  */
    443 
    444 int
    445 bcm_pkt_alloc(int unit, int size, uint32 flags, bcm_pkt_t **pkt_buf)
    446 {
    447     bcm_pkt_t *pkt;
    448     int rv = BCM_E_INTERNAL;
    449 
    450     UNIT_VALID(unit);
    451 
    452     pkt = sal_alloc(sizeof(bcm_pkt_t), "bcm_pkt_alloc");
    453     if (!pkt) {
    454         *pkt_buf = NULL;
    455         return BCM_E_MEMORY;
    456     }
    457     sal_memset(pkt, 0, sizeof(bcm_pkt_t));
    458     pkt->pkt_data = &pkt->_pkt_data;
    459     pkt->blk_count = 1;
    460 
    461     rv = _bcm_pkt_data_alloc(unit, size, pkt->pkt_data);
    462 
    463     if (BCM_FAILURE(rv)) {
    464         sal_free(pkt);
    465         *pkt_buf = NULL;
    466         return rv;
    467     }
    468     bcm_pkt_flags_init(unit, pkt, flags);
    469 
    470     *pkt_buf = pkt;
    471 
    472     return BCM_E_NONE;
    473 }
    474 
    475 
    476 /*
    477  * Function:
    478  *      bcm_pkt_free
    479  * Purpose:
    480  *      Basic, free routine using sal and soc functions
    481  * Parameters:
    482  *      unit - Strata unit
    483  *      size - Bytes to allocate
    484  *      flags - See pkt.h for more about these flags
    485  * Returns:
    486  * Notes:
    487  *      Works with bcm_pkt_alloc.  Checks for multiple blocks,
    488  *      so could be used with other routines that use sal_alloc
    489  *      and soc_cm_salloc.
    490  */
    491 
    492 int
    493 bcm_pkt_free(int unit, bcm_pkt_t *pkt)
    494 {
    495     int i;
    496     soc_stat_t    *stat = &SOC_CONTROL(unit)->stat;
    497 
    498     UNIT_VALID(unit);
    499 
    500     if (pkt) {
    501         for (i = 0; i < pkt->blk_count; i++) {
    502             if (pkt->pkt_data[i].data) {
    503                 _bcm_pkt_data_free(unit, &pkt->pkt_data[i]);
    504             }
    505         }
    506 
    507         if (soc_feature(unit, soc_feature_cmicx)) {
    508             if (pkt->tx_header) {
    509                 stat->dma_tbyt -= sizeof(pkt->_higig);
    510                 soc_cm_sfree(unit, pkt->tx_header);
    511                 pkt->tx_header = NULL;
    512             }
    513         }
    514 
    515         sal_free(pkt);
    516     }
    517 
    518     return BCM_E_NONE;
    519 }
    520 
    521 /*
    522  * Function:
    523  *      bcm_pkt_blk_alloc
    524  * Purpose:
    525  *      Allocate an array of packets
    526  * Parameters:
    527  *      unit - Strata device number
    528  *      count - How many packets to alloc
    529  *      size - Bytes in each packet
    530  *      flags - flags to use for packet alloc
    531  * Returns:
    532  *      Pointer to allocated structure or NULL if fails
    533  */
    534 
    535 int
    536 bcm_pkt_blk_alloc(int unit, int count, int size, uint32 flags, 
    537                   bcm_pkt_t ***packet_array)
    538 {
    539     bcm_pkt_t          **p_array;
    540     int i, j;
    541 
    542     UNIT_VALID(unit);
    543 
    544     if (!(p_array = sal_alloc(count * sizeof(bcm_pkt_t *), "pkt_blk"))) {
    545         *packet_array = NULL;
    546         return (BCM_E_MEMORY);
    547     }
    548 
    549     for (i = 0; i < count; i++) {
    550         if (BCM_FAILURE(bcm_pkt_alloc(unit, size, flags, p_array + i))) {
    551 
    552             for (j = 0; j < i; j++) {
    553                 bcm_pkt_free(unit, p_array[j]);
    554             }
    555             sal_free(p_array);
    556             *packet_array = NULL;
    557             return (BCM_E_MEMORY);
    558         }
    559     }
    560 
    561     *packet_array = p_array;
    562     return BCM_E_NONE;
    563 }
    564 
    565 
    566 /*
    567  * Function:
    568  *      bcm_pkt_blk_free
    569  * Purpose:
    570  *      Free an array of packets allocated with bcm_pkt_blk_alloc
    571  * Parameters:
    572  *      unit - Strata device number
    573  *      pkts - pointer to array of packets
    574  *      count - How many packets to alloc
    575  * Returns:
    576  */
    577 
    578 int 
    579 bcm_pkt_blk_free(int unit, bcm_pkt_t **pkts, int count)
    580 {
    581     int i;
    582 
    583     UNIT_VALID(unit);
    584 
    585     if (pkts) {
    586         for (i = 0; i < count; i++) {
    587             if (pkts[i]) {
    588                 bcm_pkt_free(unit, pkts[i]);
    589             }
    590         }
    591         sal_free(pkts);
    592     }
    593 
    594     return BCM_E_NONE;
    595 }
    596 
    597 
    598 /*
    599  * Function:
    600  *      bcm_pkt_rx_alloc
    601  * Purpose:
    602  *      Allocate a packet using RX alloc
    603  * Parameters:
    604  *      len    - length of data buffer
    605  * Returns:
    606  *      Pointer to packet or NULL if memory error
    607  * Notes:
    608  *      Sets up the packet to have a single buffer.
    609  */
    610 
    611 int
    612 bcm_pkt_rx_alloc(int unit, int len, bcm_pkt_t **pkt_buf)
    613 {
    614     bcm_pkt_t *pkt;
    615     uint8 *buf;
    616     int rv;
    617 
    618     UNIT_VALID(unit);
    619 
    620     buf = NULL;
    621     pkt = sal_alloc(sizeof(bcm_pkt_t), "pkt_rx_alloc");
    622     if (pkt == NULL) {
    623         *pkt_buf = NULL;
    624         return BCM_E_MEMORY;
    625     }
    626     sal_memset(pkt, 0, sizeof(bcm_pkt_t));
    627 
    628     if (len > 0) {
    629         rv = bcm_rx_alloc(unit, len, 0, (void*)&buf);
    630         if (rv != BCM_E_NONE) {
    631             sal_free(pkt);
    632             return rv;
    633         }
    634         pkt->_pkt_data.data = buf;
    635         pkt->_pkt_data.len = len;
    636         pkt->pkt_len = len;
    637         pkt->pkt_data = &pkt->_pkt_data;
    638         pkt->blk_count = 1;
    639     }
    640 
    641     /* Set up flags here if possible */
    642 
    643     *pkt_buf = pkt;
    644     return BCM_E_NONE;
    645 }
    646 
    647 /*
    648  * Function:
    649  *      bcm_pkt_rx_free
    650  * Purpose:
    651  *      Free a packet allocated using bcm_pkt_rx_alloc
    652  * Parameters:
    653  *      pkt    - packet to free
    654  * Returns:
    655  * Notes:
    656  *      Checks for null pkt and buffer
    657  */
    658 
    659 int
    660 bcm_pkt_rx_free(int unit, bcm_pkt_t *pkt)
    661 {
    662     UNIT_VALID(unit);
    663 
    664     if (pkt) {
    665         if (pkt->_pkt_data.data) {
    666             bcm_rx_free(unit, pkt->_pkt_data.data);
    667         }
    668         sal_free(pkt);
    669     }
    670 
    671     return BCM_E_NONE;
    672 }
    673 
    674 /*
    675  * Function:
    676  *      bcm_rx_reasons_t_init
    677  * Purpose:
    678  *      Initialize RX reasons structure.
    679  * Parameters:
    680  *      reasons - (INOUT) Pointer to the structure to be initialized.
    681  * Returns:
    682  *      NONE
    683  */
    684 void
    685 bcm_rx_reasons_t_init(bcm_rx_reasons_t *reasons)
    686 {
    687     if (reasons != NULL) {
    688         sal_memset(reasons, 0, sizeof (*reasons));
    689     }
    690     return;
    691 }
    692 
    693 
    694 
    695 int
    696 bcm_pkt_ecmp_grp_set(int unit, bcm_pkt_t *pkt, bcm_if_t ecmp_grp)
    697 {
    698 #if defined(INCLUDE_L3) && defined(BCM_FIREBOLT_SUPPORT)
    699     if (ecmp_grp < BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)) {
    700         return BCM_E_PARAM;
    701     }
    702 
    703     pkt->txprocmh_ecmp_group_index =
    704          ecmp_grp - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
    705 
    706     return BCM_E_NONE;
    707 #else
    708     return BCM_E_CONFIG;
    709 #endif
    710 }
    711 int
    712 bcm_pkt_ecmp_member_set(int unit, bcm_pkt_t *pkt, bcm_if_t ecmp_grp,
    713                         bcm_if_t ecmp_member)
    714 {
    715 #if defined(INCLUDE_L3) && defined(BCM_FIREBOLT_SUPPORT)
    716     int ecmp_group_idx = ecmp_grp - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
    717     int ecmp_count = 0;
    718     int *ecmp_mem, max_group_size, i;
    719     int rv;
    720 
    721     if (ecmp_grp < BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)) {
    722         return BCM_E_PARAM;
    723     }
    724 
    725     if (ecmp_member < BCM_XGS3_EGRESS_IDX_MIN(unit)) {
    726         return BCM_E_PARAM;
    727     }
    728 
    729     ecmp_mem = sal_alloc(4096 * sizeof(bcm_if_t), "intf array");
    730 
    731     if (ecmp_mem == NULL) {
    732         return BCM_E_MEMORY;
    733     }
    734 
    735     pkt->txprocmh_ecmp_group_index =
    736         ecmp_grp - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit);
    737 
    738     rv = _bcm_xgs3_ecmp_max_grp_size_get(unit, ecmp_group_idx, &max_group_size);
    739     if (BCM_FAILURE(rv)) {
    740         sal_free(ecmp_mem);
    741         return rv;
    742     }
    743 
    744     rv = bcm_xgs3_l3_egress_multipath_get(unit, ecmp_grp, 
    745                                         max_group_size, ecmp_mem, &ecmp_count);
    746 
    747     for( i = 0; i < ecmp_count; ++i) {
    748         if (ecmp_mem[i] == ecmp_member) {
    749             pkt->txprocmh_ecmp_member_index = i;
    750             sal_free(ecmp_mem);
    751             return BCM_E_NONE;
    752         }
    753     }
    754     sal_free(ecmp_mem);
    755     return BCM_E_PARAM;
    756 #else
    757     return BCM_E_CONFIG;
    758 #endif
    759 }
    760 
    761 int
    762 bcm_pkt_nexthop_set(int unit, bcm_pkt_t *pkt, bcm_if_t nexthop_id)
    763 {
    764 
    765 #if defined(INCLUDE_L3) && defined(BCM_FIREBOLT_SUPPORT)
    766     if (nexthop_id < BCM_XGS3_EGRESS_IDX_MIN(unit)) {
    767         return BCM_E_PARAM;
    768     }
    769 
    770     pkt->txprocmh_destination = nexthop_id - BCM_XGS3_EGRESS_IDX_MIN(unit);
    771     return BCM_E_NONE;
    772 #else
    773     return BCM_E_CONFIG;
    774 #endif
    775 }
    776