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

ft_export.c (133486B)


      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:        ft_export.c
      8  * Purpose:     Implementation of Flowtracker Export APIs.
      9  * Requires:
     10  */
     11 
     12 
     13 #include <bcm_int/esw/flowtracker/ft_group.h>
     14 #include <bcm_int/esw/flowtracker/ft_export.h>
     15 #include <bcm_int/esw/flowtracker/ft_field.h>
     16 
     17 #if defined(BCM_FLOWTRACKER_SUPPORT)
     18 
     19 #include <soc/cmicm.h>
     20 
     21 
     22 #ifdef BCM_WARM_BOOT_SUPPORT
     23 #include <bcm_int/esw/switch.h>
     24 
     25 #define BCM_WB_FT_EXPORT_VERSION_1_1                SOC_SCACHE_VERSION(1,1)
     26 
     27 /* Default warmboot version */
     28 #define BCM_WB_FT_EXPORT_DEFAULT_VERSION            BCM_WB_FT_EXPORT_VERSION_1_1
     29 
     30 #endif
     31 
     32 /* Export software state. */
     33 bcmi_ft_export_state_t *bcmi_ft_export_state[BCM_MAX_NUM_UNITS] = {0};
     34 
     35 
     36 
     37 #define BCMI_FT_XLATE_PARAM(_name, _size) \
     38         bcmFlowtrackerTrackingParamType##_name, \
     39         bcmFlowtrackerExportElementType##_name, \
     40         _size, \
     41         #_name
     42 
     43 typedef struct bcmi_fte_template_record_elem_info_s {
     44     int length;
     45     bcm_flowtracker_export_element_type_t info_elem;
     46     bcm_flowtracker_tracking_param_type_t tracking_param;
     47     bcm_flowtracker_check_t check_id;
     48 } bcmi_fte_template_record_elem_info_t;
     49 
     50 typedef struct bcmi_fte_template_record_info_s {
     51     int info_depth;
     52     int total_bits;
     53     int flow_key_offset;
     54     int flow_key_length;
     55     int flow_data_offset;
     56     int flow_data_length;
     57     bcmi_fte_template_record_elem_info_t *info;
     58 } bcmi_fte_template_record_info_t;
     59 
     60 #define BCMI_FTE_RECORD_ELEM_IDX_GET(_start_, _offset_, _len_, _idx_)       \
     61         _idx_ = ((_start_) - ((_offset_) + (_len_)))/ 8
     62 
     63 #define BCMI_FTE_RECORD_ELEM_SET(_record_, _idx_, _info_elem_)              \
     64         (_record_)->info[(_idx_)].info_elem = (_info_elem_)
     65 
     66 #define BCMI_FTE_RECORD_TRACKING_PARAM_SET(_record_, _idx_, _tracking_p_)   \
     67         (_record_)->info[(_idx_)].tracking_param = (_tracking_p_)
     68 
     69 #define BCMI_FTE_RECORD_LENGTH_SET(_record_, _idx_, _length_)               \
     70         do {                                                                \
     71             int reset_count = 0;                                            \
     72             (_record_)->info[(_idx_)].length = (_length_);                  \
     73             reset_count = (_length_ - 8) / 8;                               \
     74             while (reset_count > 0) {                                       \
     75                 (_record_)->info[(_idx_) + reset_count].length = 0;         \
     76                 reset_count--;                                              \
     77             }                                                               \
     78         } while(0)
     79 
     80 #define BCMI_FTE_RECORD_FLOW_CHECK_SET(_record_, _idx_, _check_id_)         \
     81         (_record_)->info[(_idx_)].check_id = (_check_id_)
     82 
     83 typedef struct bcmi_ft_export_elements_map_s {
     84     bcm_flowtracker_tracking_param_type_t tracking_param;
     85     bcm_flowtracker_export_element_type_t export_element;
     86     int default_data_size;
     87     char element_name[BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX];
     88 } bcmi_ft_export_elements_map_t;
     89 
     90 
     91 static bcmi_ft_export_elements_map_t bcmi_ft_export_elements_map[] = {
     92             {   BCMI_FT_XLATE_PARAM(SrcIPv4,               4  )   },
     93             {   BCMI_FT_XLATE_PARAM(DstIPv4,               4  )   },
     94             {   BCMI_FT_XLATE_PARAM(L4SrcPort,             2  )   },
     95             {   BCMI_FT_XLATE_PARAM(L4DstPort,             2  )   },
     96             {   BCMI_FT_XLATE_PARAM(SrcIPv6,               16 )   },
     97             {   BCMI_FT_XLATE_PARAM(DstIPv6,               16 )   },
     98             {   BCMI_FT_XLATE_PARAM(IPProtocol,            1  )   },
     99             {   BCMI_FT_XLATE_PARAM(PktCount,              4  )   },
    100             {   BCMI_FT_XLATE_PARAM(ByteCount,             4  )   },
    101             {   BCMI_FT_XLATE_PARAM(VRF,                   2  )   },
    102             {   BCMI_FT_XLATE_PARAM(TTL,                   1  )   },
    103             {   BCMI_FT_XLATE_PARAM(IPLength,              2  )   },
    104             {   BCMI_FT_XLATE_PARAM(IP6Length,             2  )   },
    105             {   BCMI_FT_XLATE_PARAM(TcpWindowSize,         2  )   },
    106             {   BCMI_FT_XLATE_PARAM(DosAttack,             4  )   },
    107             {   BCMI_FT_XLATE_PARAM(VxlanNetworkId,        3  )   },
    108             {   BCMI_FT_XLATE_PARAM(NextHeader,            1  )   },
    109             {   BCMI_FT_XLATE_PARAM(HopLimit,              1  )   },
    110             {   BCMI_FT_XLATE_PARAM(InnerSrcIPv4,          4  )   },
    111             {   BCMI_FT_XLATE_PARAM(InnerDstIPv4,          4  )   },
    112             {   BCMI_FT_XLATE_PARAM(InnerL4SrcPort,        2  )   },
    113             {   BCMI_FT_XLATE_PARAM(InnerL4DstPort,        2  )   },
    114             {   BCMI_FT_XLATE_PARAM(InnerSrcIPv6,          16 )   },
    115             {   BCMI_FT_XLATE_PARAM(InnerDstIPv6,          16 )   },
    116             {   BCMI_FT_XLATE_PARAM(InnerIPProtocol,       1  )   },
    117             {   BCMI_FT_XLATE_PARAM(InnerTTL,              1  )   },
    118             {   BCMI_FT_XLATE_PARAM(InnerIPLength,         2  )   },
    119             {   BCMI_FT_XLATE_PARAM(InnerNextHeader,       1  )   },
    120             {   BCMI_FT_XLATE_PARAM(InnerHopLimit,         1  )   },
    121             {   BCMI_FT_XLATE_PARAM(InnerIP6Length,        2  )   },
    122             {   BCMI_FT_XLATE_PARAM(TcpFlags,              1  )   },
    123             {   BCMI_FT_XLATE_PARAM(OuterVlanTag,          2  )   },
    124             {   BCMI_FT_XLATE_PARAM(TimestampNewLearn,     6  )   },
    125             {   BCMI_FT_XLATE_PARAM(TimestampFlowStart,    6  )   },
    126             {   BCMI_FT_XLATE_PARAM(TimestampFlowEnd,      6  )   },
    127             {   BCMI_FT_XLATE_PARAM(TimestampCheckEvent1, 6  )   },
    128             {   BCMI_FT_XLATE_PARAM(TimestampCheckEvent2, 6  )   },
    129             {   BCMI_FT_XLATE_PARAM(InnerDosAttack,        4  )   },
    130             {   BCMI_FT_XLATE_PARAM(TunnelClass,           3  )   },
    131             {   BCMI_FT_XLATE_PARAM(FlowtrackerCheck,      4  )   },
    132 
    133             { bcmFlowtrackerTrackingParamTypeNone, bcmFlowtrackerExportElementTypeExportReasons, 2, "ExportReasons"},
    134             { bcmFlowtrackerTrackingParamTypeNone, bcmFlowtrackerExportElementTypeExportFlags, 1, "ExportFlags"},
    135             { bcmFlowtrackerTrackingParamTypeNone, bcmFlowtrackerExportElementTypeFlowtrackerGroup, 1, "FlowtrackerGroup"},
    136             { bcmFlowtrackerTrackingParamTypeNone, bcmFlowtrackerExportElementTypeReserved, 1, "Reserved"}
    137 };
    138 
    139 /* FT Export internal routines. */
    140 
    141 STATIC int
    142 bcmi_ft_export_cb_init(int unit)
    143 {
    144     bcmi_ft_export_cb_ctrl_t *ft_export_cb_ctrl = BCMI_FT_CB_CTRL(unit);
    145 
    146     if (ft_export_cb_ctrl == NULL) {
    147         ft_export_cb_ctrl = sal_alloc(sizeof(bcmi_ft_export_cb_ctrl_t),
    148                                       "IPFIX Control Data");
    149         if (ft_export_cb_ctrl == NULL) {
    150             return BCM_E_MEMORY;
    151         }
    152         sal_memset(ft_export_cb_ctrl, 0, sizeof(bcmi_ft_export_cb_ctrl_t));
    153 
    154         BCMI_FT_EXPORT_INFO(unit)->export_cb_ctrl = ft_export_cb_ctrl;
    155 
    156         ft_export_cb_ctrl->pid = SAL_THREAD_ERROR;
    157         ft_export_cb_ctrl->dma_chan = SOC_MEM_FIFO_DMA_CHANNEL_2;
    158 
    159     }
    160 
    161     return BCM_E_NONE;
    162 }
    163 
    164 
    165 STATIC int
    166 bcmi_ft_export_cb_deinit(int unit)
    167 {
    168     soc_timeout_t timeout;
    169     bcmi_ft_export_cb_ctrl_t *ft_export_cb_ctrl = BCMI_FT_CB_CTRL(unit);
    170     int i;
    171 
    172     if (NULL == ft_export_cb_ctrl) {
    173         return (BCM_E_NONE);
    174     }
    175 
    176     bcma_ft_export_fifo_control(unit, 0);
    177 
    178     soc_timeout_init(&timeout, SAL_BOOT_BCMSIM ? 30000000 : 10000000, 0);
    179 
    180     while (ft_export_cb_ctrl->pid != SAL_THREAD_ERROR) {
    181         if (soc_timeout_check(&timeout) != 0) {
    182             LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
    183                       (BSL_META_U(unit,
    184                                   "IPFIX thread did not exit.\n")));
    185 
    186             return BCM_E_INTERNAL;
    187         }
    188     }
    189 
    190     for (i = 0; i < BCMI_FT_CB_MAX; i++) {
    191         ft_export_cb_ctrl->callback_entry[i].state =
    192             BCMI_FT_CALLBACK_STATE_INVALID;
    193     }
    194 
    195 
    196     sal_free(ft_export_cb_ctrl);
    197     ft_export_cb_ctrl = NULL;
    198 
    199     return BCM_E_NONE;
    200 }
    201 
    202 #define BCMI_FTE_IPFIX_HDR_VERSION      0xa
    203 #define BCMI_FTE_IPFIX_HDR_LENGTH       0x10
    204 #define BCMI_FTE_IPFIX_HDR_TIMESTAMP    0x0
    205 #define BCMI_FTE_IPFIX_HDR_SEQNUM       0x0
    206 #define BCMI_FTE_IPFIX_HDR_OBS_DOMAIN   0x1
    207 
    208 /* IpV4 based IPFIX encap header */
    209 #define BCMI_FTE_IPV4_HDR_CTRL_IP_CHKSUM    0
    210 #define BCMI_FTE_IPV4_HDR_CTRL_IP_LENGTH    1
    211 #define BCMI_FTE_UDP_HDR_CTRL_LENGTH        2
    212 #define BCMI_FTE_UDP_HDR_CTRL_CHKSUM        3
    213 #define BCMI_FTE_IPFIX_HDR_CTRL_LENGTH      4
    214 #define BCMI_FTE_IPFIX_HDR_CTRL_TIMESTAMP   5
    215 #define BCMI_FTE_IPFIX_HDR_CTRL_SEQ_NUM     6
    216 #define BCMI_FTE_IPV6_HDR_CTRL_IP_LENGTH    7
    217 
    218 typedef struct bcmi_fte_flex_hdr_upd_info_s {
    219     uint32 double_for_chksum;
    220     uint32 edit_type;
    221     uint32 num_bytes;
    222     uint32 offset_type;
    223     uint32 offset;
    224     uint32 payload_chksum;
    225     uint32 chksum_type;
    226 } bcmi_fte_flex_hdr_upd_info_t;
    227 
    228 /* HDR UPD CTRL EDIT TYPE hardware values. DO NOT MODIFY */
    229 #define BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_LENGTH      0
    230 #define BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_CHKSUM      1
    231 #define BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_TIMESTAMP   2
    232 #define BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_SEQ_NUM     3
    233 
    234 /* Offset Type */
    235 #define BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_IP        1
    236 #define BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_UDP       2
    237 #define BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_IPFIX     3
    238 
    239 /* CheckSum Type */
    240 #define BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_NONE      0
    241 #define BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_BIT_OR    1
    242 #define BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_SET       2
    243 
    244 static bcmi_fte_flex_hdr_upd_info_t flex_hdr_upd_info_array[] = {
    245     /* BCMI_FTE_IPV4_HDR_CTRL_IP_CHKSUM */
    246     {0, BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_CHKSUM, 0x2,
    247         BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_IP, 10,
    248         0, BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_SET},
    249 
    250     /* BCMI_FTE_IPV4_HDR_CTRL_IP_LENGTH */
    251     {0, BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_LENGTH, 0x2,
    252         BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_IP, 2,
    253         0, BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_BIT_OR},
    254 
    255     /* BCMI_FTE_UDP_HDR_CTRL_LENGTH */
    256     {1, BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_LENGTH, 0x2,
    257         BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_UDP, 4,
    258         0, BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_BIT_OR},
    259 
    260     /* BCMI_FTE_UDP_HDR_CTRL_CHKSUM */
    261     {0, BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_CHKSUM, 0x2,
    262         BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_UDP, 6,
    263         1, BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_SET},
    264 
    265     /* BCMI_FTE_IPFIX_HDR_CTRL_LENGTH */
    266     {0, BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_LENGTH, 0x2,
    267         BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_IPFIX, 2,
    268         0, BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_BIT_OR},
    269 
    270     /* BCMI_FTE_IPFIX_HDR_CTRL_TIMESTAMP */
    271     {0, BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_TIMESTAMP, 0x4,
    272         BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_IPFIX, 4,
    273         0, BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_BIT_OR},
    274 
    275     /* BCMI_FTE_IPFIX_HDR_CTRL_SEQ_NUM */
    276     {0, BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_SEQ_NUM, 0x4,
    277         BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_IPFIX, 8,
    278         0, BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_BIT_OR},
    279 
    280     /* BCMI_FTE_IPV6_HDR_CTRL_IP_LENGTH */
    281     {0, BCMI_FTE_HDR_UDP_CTRL_EDIT_TYPE_LENGTH, 0x2,
    282         BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_IP, 4,
    283         0, BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_NONE}
    284 };
    285 
    286 STATIC int
    287 bcmi_ft_ipfix_header_get(int unit,
    288                          bcmi_ft_collector_info_t *ft_coll_info,
    289                          shr_ipfix_header_t *ipfix)
    290 {
    291     /* Set IPFIX */
    292     sal_memset(ipfix, 0, sizeof(*ipfix));
    293 
    294     ipfix->version = ft_coll_info->ipfix_hdr.version;
    295     ipfix->length = BCMI_FTE_IPFIX_HDR_LENGTH;
    296     ipfix->export_time = BCMI_FTE_IPFIX_HDR_TIMESTAMP;
    297     ipfix->sequence_num = ft_coll_info->ipfix_hdr.initial_sequence_num;
    298     ipfix->observation_id = BCMI_FT_EXPORT_INFO(unit)->ipfix_observation_domain_id;
    299 
    300     return BCM_E_NONE;
    301 }
    302 
    303 STATIC int
    304 bcmi_ft_udp_header_get(int unit,
    305                        bcm_flowtracker_collector_info_t *collector_info,
    306                        shr_udp_header_t *udp)
    307 {
    308     /* Set UDP */
    309     sal_memset(udp, 0, sizeof(*udp));
    310     udp->src = collector_info->udp.src_port;
    311     udp->dst = collector_info->udp.dst_port;
    312 
    313     /* To be calculated later.  */
    314     udp->sum = 0;
    315     udp->length = 0;
    316 
    317     return BCM_E_NONE;
    318 }
    319 
    320 
    321 STATIC int
    322 bcmi_ft_ipv4_header_get(int unit,
    323                         bcm_flowtracker_collector_info_t *collector_info,
    324                         uint16 *etype,
    325                         shr_ipv4_header_t *ipv4)
    326 {
    327 
    328     *etype = SHR_L2_ETYPE_IPV4;
    329 
    330     sal_memset(ipv4, 0, sizeof(*ipv4));
    331 
    332     ipv4->version  = SHR_IPV4_VERSION;
    333     ipv4->h_length = SHR_IPV4_HEADER_LENGTH_WORDS;
    334     ipv4->dscp     = collector_info->ipv4.dscp;
    335     ipv4->ecn      = 0;
    336 
    337     /* Length populated by EDIT_CTRL function.
    338      */
    339     ipv4->length   = 0;
    340     ipv4->id       = 0;
    341     ipv4->flags    = 0;
    342     ipv4->f_offset = 0;
    343     ipv4->ttl      = collector_info->ipv4.ttl;
    344     ipv4->protocol = SHR_IP_PROTOCOL_UDP;
    345     ipv4->sum      = 0;
    346     ipv4->src      = collector_info->ipv4.src_ip;
    347     ipv4->dst      = collector_info->ipv4.dst_ip;
    348 
    349     /* Calculate IP header checksum. */
    350     ipv4->sum = 0;
    351 
    352     return BCM_E_NONE;
    353 }
    354 
    355 STATIC int
    356 bcmi_ft_ipv6_header_get(int unit,
    357                         bcm_flowtracker_collector_info_t *collector_info,
    358                         uint16 *etype,
    359                         shr_ipv6_header_t *ipv6)
    360 {
    361     *etype = SHR_L2_ETYPE_IPV6;
    362 
    363     sal_memset(ipv6, 0, sizeof(*ipv6));
    364 
    365     ipv6->version = SHR_IPV6_VERSION;
    366     ipv6->t_class = collector_info->ipv6.traffic_class;
    367     ipv6->f_label = collector_info->ipv6.flow_label;
    368     ipv6->next_header = SHR_IP_PROTOCOL_UDP;
    369     ipv6->hop_limit = collector_info->ipv6.hop_limit;
    370     sal_memcpy(ipv6->src, collector_info->ipv6.src_ip, sizeof(bcm_ip6_t));
    371     sal_memcpy(ipv6->dst, collector_info->ipv6.dst_ip, sizeof(bcm_ip6_t));
    372 
    373     /* To be calculated by EDIT_CTRL function */
    374     ipv6->p_length = 0;
    375 
    376     return BCM_E_NONE;
    377 }
    378 
    379 STATIC int
    380 bcmi_ft_l2_header_get(int unit,
    381                       bcm_flowtracker_collector_info_t *collector_info,
    382                       uint16 etype, shr_l2_header_t *l2)
    383 {
    384     sal_memset(l2, 0, sizeof(*l2));
    385 
    386     /* Destination and Source MAC */
    387     sal_memcpy(l2->dst_mac, collector_info->eth.dst_mac, SHR_MAC_ADDR_LENGTH);
    388     sal_memcpy(l2->src_mac, collector_info->eth.src_mac, SHR_MAC_ADDR_LENGTH);
    389 
    390     /*
    391      * VLAN Tag(s)
    392      */
    393     if (collector_info->eth.vlan_tag_structure ==
    394         BCM_FLOWTRACKER_COLLECTOR_ETH_HDR_UNTAGGED) {
    395 
    396         /* Set to 0 to indicate untagged */
    397         l2->outer_vlan_tag.tpid = 0;
    398         l2->inner_vlan_tag.tpid = 0;
    399     } else {
    400 
    401         /* Fill outer vlan */
    402         if ((collector_info->eth.vlan_tag_structure ==
    403              BCM_FLOWTRACKER_COLLECTOR_ETH_HDR_SINGLE_TAGGED) ||
    404             (collector_info->eth.vlan_tag_structure ==
    405              BCM_FLOWTRACKER_COLLECTOR_ETH_HDR_DOUBLE_TAGGED))
    406         {
    407             l2->outer_vlan_tag.tpid     =
    408                 collector_info->eth.outer_tpid;
    409             l2->outer_vlan_tag.tci.prio =
    410                 BCM_VLAN_CTRL_PRIO(collector_info->eth.outer_vlan_tag);
    411             l2->outer_vlan_tag.tci.cfi  =
    412                 BCM_VLAN_CTRL_CFI(collector_info->eth.outer_vlan_tag);
    413             l2->outer_vlan_tag.tci.vid  =
    414                 BCM_VLAN_CTRL_ID(collector_info->eth.outer_vlan_tag);
    415         } else {
    416             /* Set to 0 to indicate not inner tagged */
    417             l2->inner_vlan_tag.tpid = 0;
    418         }
    419     }
    420 
    421     /* Ether Type */
    422     l2->etype = etype;
    423 
    424     return BCM_E_NONE;
    425 }
    426 
    427 STATIC int
    428 bcmi_ft_collector_packet_build(int unit,
    429                                bcmi_ft_collector_info_t *ft_coll_info,
    430                                bcmi_ft_pkt_build_t *pkt_build)
    431 {
    432     int rv;
    433     uint8 *cur_ptr;
    434     uint8 *buffer;
    435 
    436     bcm_ethertype_t   etype;
    437     shr_ipfix_header_t ipfix;
    438     shr_udp_header_t  udp;
    439     shr_ipv4_header_t ipv4;
    440     shr_ipv6_header_t ipv6;
    441     shr_l2_header_t   l2;
    442     uint16            flex_offset;
    443 
    444     bcm_flowtracker_collector_info_t *collector_info;
    445 
    446     collector_info = &(ft_coll_info->collector_info);
    447 
    448     etype = 0;
    449     sal_memset(&ipfix, 0, sizeof(ipfix));
    450     sal_memset(&udp, 0, sizeof(udp));
    451     sal_memset(&ipv4, 0, sizeof(ipv4));
    452     sal_memset(&ipv6, 0, sizeof(ipv6));
    453     sal_memset(&l2, 0, sizeof(l2));
    454 
    455     switch(collector_info->transport_type) {
    456         case bcmFlowtrackerCollectorTransportTypeIpfixIpv4Udp:
    457 
    458             /* Get IPFIX Header fields */
    459             rv = bcmi_ft_ipfix_header_get(unit, ft_coll_info, &ipfix);
    460             BCM_IF_ERROR_RETURN(rv);
    461 
    462             /* Get UDP Header Fields */
    463             rv = bcmi_ft_udp_header_get(unit, collector_info, &udp);
    464             BCM_IF_ERROR_RETURN(rv);
    465 
    466             /* Get IPv4 Header Fields */
    467             rv = bcmi_ft_ipv4_header_get(unit, collector_info, &etype, &ipv4);
    468             BCM_IF_ERROR_RETURN(rv);
    469 
    470             /* Get L2 Header Fields */
    471             rv = bcmi_ft_l2_header_get(unit, collector_info, etype, &l2);
    472             break;
    473 
    474         case bcmFlowtrackerCollectorTransportTypeIpfixIpv6Udp:
    475 
    476             /* Get IPFIX Header fields */
    477             rv = bcmi_ft_ipfix_header_get(unit, ft_coll_info, &ipfix);
    478             BCM_IF_ERROR_RETURN(rv);
    479 
    480             /* Get UDP Header Fields */
    481             rv = bcmi_ft_udp_header_get(unit, collector_info, &udp);
    482             BCM_IF_ERROR_RETURN(rv);
    483 
    484             /* Get IPv6 Header Fields */
    485             rv = bcmi_ft_ipv6_header_get(unit, collector_info, &etype, &ipv6);
    486             BCM_IF_ERROR_RETURN(rv);
    487 
    488             /* Get L2 Header Fields */
    489             rv = bcmi_ft_l2_header_get(unit, collector_info, etype, &l2);
    490             break;
    491 
    492         default:
    493             return BCM_E_PARAM;
    494     }
    495 
    496     BCM_IF_ERROR_RETURN(rv);
    497 
    498     /*
    499      * Pack header/labels into given buffer (network packet format).
    500      *
    501      * Following packing order must be followed to correctly
    502      * build the packet encapsulation.
    503      */
    504     buffer = pkt_build->encap;
    505     cur_ptr = buffer;
    506 
    507     switch(collector_info->transport_type) {
    508         case bcmFlowtrackerCollectorTransportTypeIpfixIpv4Udp:
    509 
    510             cur_ptr = shr_l2_header_pack(cur_ptr, &l2);
    511 
    512             /* Set Flowtracker export pkt IP base offset */
    513             pkt_build->ip_offset = cur_ptr - buffer;
    514             cur_ptr = shr_ipv4_header_pack(cur_ptr, &ipv4);
    515 
    516             /* Set Flowtracker export pkt UDP base offset */
    517             pkt_build->udp_offset = cur_ptr - buffer;
    518             cur_ptr = shr_udp_header_pack(cur_ptr, &udp);
    519 
    520             /* Set Flowtracker export pkt IPFIX base offset */
    521             pkt_build->ipfix_offset = cur_ptr - buffer;
    522             cur_ptr = shr_ipfix_header_pack(cur_ptr, &ipfix);
    523 
    524             /* Set Flowtracker export pkt encapsulation length */
    525             pkt_build->encap_length = cur_ptr - buffer;
    526 
    527             /* Set Flowtracker Export pkt UDP Length */
    528             udp.length = pkt_build->encap_length - pkt_build->udp_offset;
    529 
    530             /* pack udp length */
    531             flex_offset = pkt_build->udp_offset +
    532                 flex_hdr_upd_info_array[BCMI_FTE_UDP_HDR_CTRL_LENGTH].offset;
    533             cur_ptr = buffer + flex_offset;
    534             SHR_PKT_PACK_U16(cur_ptr, udp.length);
    535 
    536             /* Set Flowtracker export pkt UDP Base checksum */
    537             cur_ptr = buffer + pkt_build->ipfix_offset;
    538             pkt_build->udp_base_checksum =
    539                 shr_udp_initial_checksum_get(0, &ipv4, NULL, cur_ptr, &udp);
    540 
    541             /* Initial Udp checksum calculation */
    542             udp.sum = (pkt_build->udp_base_checksum >> 16) & 0xffff;
    543             udp.sum += (pkt_build->udp_base_checksum & 0xffff);
    544             udp.sum = (~udp.sum);
    545 
    546             /* pack UDP checksum */
    547             flex_offset = pkt_build->udp_offset +
    548                 flex_hdr_upd_info_array[BCMI_FTE_UDP_HDR_CTRL_CHKSUM].offset;
    549             cur_ptr = buffer + flex_offset;
    550             SHR_PKT_PACK_U16(cur_ptr, udp.sum);
    551 
    552             /* Set Flowtracker export pkt IP Length */
    553             ipv4.length = pkt_build->encap_length - pkt_build->ip_offset;
    554 
    555             /* pack ip length */
    556             flex_offset = pkt_build->ip_offset +
    557                 flex_hdr_upd_info_array[BCMI_FTE_IPV4_HDR_CTRL_IP_LENGTH].offset;
    558             cur_ptr = buffer + flex_offset;
    559             SHR_PKT_PACK_U16(cur_ptr, ipv4.length);
    560 
    561             /* Set Flowtracker export pkt IP Base checksum */
    562             cur_ptr = buffer + pkt_build->ip_offset;
    563             pkt_build->ip_base_checksum =
    564                 shr_initial_chksum_get(SHR_IPV4_HEADER_LENGTH, cur_ptr);
    565 
    566             /* Initial Ip Header checksum calculation */
    567             ipv4.sum = (pkt_build->ip_base_checksum >> 16) & 0xffff;
    568             ipv4.sum += (pkt_build->ip_base_checksum & 0xffff);
    569             ipv4.sum = (~ipv4.sum);
    570 
    571             /* pack checksum */
    572             flex_offset = pkt_build->ip_offset +
    573                 flex_hdr_upd_info_array[BCMI_FTE_IPV4_HDR_CTRL_IP_CHKSUM].offset;
    574             cur_ptr = buffer + flex_offset;
    575             SHR_PKT_PACK_U16(cur_ptr, ipv4.sum);
    576             break;
    577 
    578         case bcmFlowtrackerCollectorTransportTypeIpfixIpv6Udp:
    579 
    580             cur_ptr = shr_l2_header_pack(cur_ptr, &l2);
    581 
    582             /* Set Flowtracker export pkt IP base offset */
    583             pkt_build->ip_offset = cur_ptr - buffer;
    584             cur_ptr = shr_ipv6_header_pack(cur_ptr, &ipv6);
    585 
    586             /* Set Flowtracker export pkt UDP base offset */
    587             pkt_build->udp_offset = cur_ptr - buffer;
    588             cur_ptr = shr_udp_header_pack(cur_ptr, &udp);
    589 
    590             /* Set Flowtracker export pkt IPFIX base offset */
    591             pkt_build->ipfix_offset = cur_ptr - buffer;
    592             cur_ptr = shr_ipfix_header_pack(cur_ptr, &ipfix);
    593 
    594             /* Set Flowtracker export pkt encapsulation length */
    595             pkt_build->encap_length = cur_ptr - buffer;
    596 
    597             /* Set Flowtracker Export pkt UDP Length */
    598             udp.length = pkt_build->encap_length - pkt_build->udp_offset;
    599 
    600             /* pack udp length */
    601             flex_offset = pkt_build->udp_offset +
    602                 flex_hdr_upd_info_array[BCMI_FTE_UDP_HDR_CTRL_LENGTH].offset;
    603             cur_ptr = buffer + flex_offset;
    604             SHR_PKT_PACK_U16(cur_ptr, udp.length);
    605 
    606             /* Set Flowtracker export pkt UDP Base checksum */
    607             cur_ptr = buffer + pkt_build->ipfix_offset;
    608             pkt_build->udp_base_checksum =
    609                 shr_udp_initial_checksum_get(1, NULL, &ipv6, cur_ptr, &udp);
    610 
    611             /* Initial UDP Checksum calculation */
    612             udp.sum = (pkt_build->udp_base_checksum >> 16) & 0xffff;
    613             udp.sum += (pkt_build->udp_base_checksum & 0xffff);
    614             udp.sum = (~udp.sum);
    615 
    616             /* pack UDP checksum */
    617             flex_offset = pkt_build->udp_offset +
    618                 flex_hdr_upd_info_array[BCMI_FTE_UDP_HDR_CTRL_CHKSUM].offset;
    619             cur_ptr = buffer + flex_offset;
    620             SHR_PKT_PACK_U16(cur_ptr, udp.sum);
    621 
    622             /* Set Flowtracker export pkt IP payload Length */
    623             ipv6.p_length = pkt_build->encap_length - pkt_build->udp_offset;
    624 
    625             /* pack ip length */
    626             flex_offset = pkt_build->ip_offset +
    627                 flex_hdr_upd_info_array[BCMI_FTE_IPV6_HDR_CTRL_IP_LENGTH].offset;
    628             cur_ptr = buffer + flex_offset;
    629             SHR_PKT_PACK_U16(cur_ptr, ipv6.p_length);
    630             break;
    631 
    632         default:
    633             return BCM_E_PARAM;
    634     }
    635 
    636     return BCM_E_NONE;
    637 }
    638 
    639 STATIC int
    640 bcmi_ft_collector_flex_hdr_upd_ctrl_set(int unit,
    641                                         soc_mem_t mem,
    642                                         uint32 ctrl,
    643                                         int ctrl_bin,
    644                                         bcmi_ft_pkt_build_t *pkt_build,
    645                                         bsc_ex_hdr_construct_cfg_entry_t *hdr,
    646                                         uint32 *chksum_bin_map)
    647 {
    648     int offset;
    649     uint32 hdr_upd_ctrl;
    650     soc_field_t hdr_upd_fld;
    651     soc_format_t collector_fmt;
    652     bcmi_fte_flex_hdr_upd_info_t *flex_hdr_upd_info = NULL;
    653 
    654     soc_field_t fte_flx_hdr_upd_flds[] = {
    655         HDR_UPDATE_CTRL_0f, HDR_UPDATE_CTRL_1f,
    656         HDR_UPDATE_CTRL_2f, HDR_UPDATE_CTRL_3f,
    657         HDR_UPDATE_CTRL_4f, HDR_UPDATE_CTRL_5f,
    658         HDR_UPDATE_CTRL_6f, HDR_UPDATE_CTRL_7f
    659     };
    660 
    661     collector_fmt = HDR_UPDATE_CTRLfmt;
    662 
    663     offset = 0;
    664     hdr_upd_ctrl = 0x0;
    665     hdr_upd_fld = fte_flx_hdr_upd_flds[ctrl_bin];
    666     flex_hdr_upd_info = &flex_hdr_upd_info_array[ctrl];
    667 
    668     if (flex_hdr_upd_info->offset_type ==
    669             BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_IP) {
    670         offset = pkt_build->ip_offset;
    671     } else if (flex_hdr_upd_info->offset_type ==
    672             BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_UDP) {
    673         offset = pkt_build->udp_offset;
    674     } else if (flex_hdr_upd_info->offset_type ==
    675             BCMI_FTE_HDR_UPD_CTRL_OFFSET_TYPE_IPFIX) {
    676         offset = pkt_build->ipfix_offset;
    677     }
    678     offset += flex_hdr_upd_info->offset;
    679 
    680     soc_format_field32_set(unit, collector_fmt, &hdr_upd_ctrl,
    681             FLEX_HDR_EDIT_TYPEf, flex_hdr_upd_info->edit_type);
    682     soc_format_field32_set(unit, collector_fmt, &hdr_upd_ctrl,
    683             FLEX_HDR_EDIT_OFFSETf, offset);
    684     soc_format_field32_set(unit, collector_fmt, &hdr_upd_ctrl,
    685             FLEX_HDR_EDIT_NUM_BYTESf, flex_hdr_upd_info->num_bytes);
    686     soc_format_field32_set(unit, collector_fmt, &hdr_upd_ctrl,
    687             FLEX_HDR_EDIT_VALIDf, 1);
    688 
    689     if (flex_hdr_upd_info->double_for_chksum == 1) {
    690         soc_format_field32_set(unit, collector_fmt, &hdr_upd_ctrl,
    691                 DOUBLE_FOR_CHKSUMf, 0x1);
    692     }
    693     if (flex_hdr_upd_info->payload_chksum == 1) {
    694         soc_format_field32_set(unit, collector_fmt, &hdr_upd_ctrl,
    695                 PAYLOAD_CHKSUM_ENf, 0x1);
    696     }
    697     if (flex_hdr_upd_info->chksum_type ==
    698             BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_BIT_OR) {
    699         (*chksum_bin_map) |= (1 << ctrl_bin);
    700     } else if (flex_hdr_upd_info->chksum_type ==
    701             BCMI_FTE_HDR_UPD_CTRL_CHKSUM_TYPE_SET) {
    702         soc_format_field32_set(unit, collector_fmt, &hdr_upd_ctrl,
    703                 CHKSUM_EN_BITMAPf, *chksum_bin_map);
    704         *chksum_bin_map = 0;
    705     }
    706 
    707     soc_mem_field32_set(unit, mem, hdr, hdr_upd_fld, hdr_upd_ctrl);
    708 
    709     return BCM_E_NONE;
    710 }
    711 
    712 STATIC int
    713 bcmi_ft_collector_hdr_construct(int unit,
    714                                 bcm_flowtracker_collector_t coll_hw_id,
    715                                 bcm_flowtracker_collector_info_t *collector_info,
    716                                 bcmi_ft_pkt_build_t *pkt_build)
    717 {
    718     int rv;
    719     int index = 0;
    720     int ctrl_count = 0;
    721     uint32 chksum_bin_map;
    722     uint32 ctrl_array[8];
    723     uint32 ctrl_bin_array[8];
    724     soc_mem_t mem;
    725     bsc_ex_hdr_construct_cfg_entry_t hdr;
    726 
    727     mem = BSC_EX_HDR_CONSTRUCT_CFGm;
    728     sal_memset(&hdr, 0, sizeof(bsc_ex_hdr_construct_cfg_entry_t));
    729     chksum_bin_map = 0;
    730 
    731     switch(collector_info->transport_type) {
    732         case bcmFlowtrackerCollectorTransportTypeIpfixIpv4Udp:
    733 
    734             /* Do Not Change Order */
    735             ctrl_array[0] = BCMI_FTE_IPFIX_HDR_CTRL_LENGTH;
    736             ctrl_bin_array[0] = 1;
    737             ctrl_array[1] = BCMI_FTE_IPFIX_HDR_CTRL_TIMESTAMP;
    738             ctrl_bin_array[1] = 2;
    739             ctrl_array[2] = BCMI_FTE_IPFIX_HDR_CTRL_SEQ_NUM;
    740             ctrl_bin_array[2] = 3;
    741             ctrl_array[3] = BCMI_FTE_UDP_HDR_CTRL_LENGTH;
    742             ctrl_bin_array[3] = 4;
    743             ctrl_array[4] = BCMI_FTE_UDP_HDR_CTRL_CHKSUM;
    744             ctrl_bin_array[4] = 5;
    745             ctrl_array[5] = BCMI_FTE_IPV4_HDR_CTRL_IP_LENGTH;
    746             ctrl_bin_array[5] = 6;
    747             ctrl_array[6] = BCMI_FTE_IPV4_HDR_CTRL_IP_CHKSUM;
    748             ctrl_bin_array[6] = 0;
    749             ctrl_count = 7;
    750 
    751             for (index = 0; index < ctrl_count; index++) {
    752                 rv = bcmi_ft_collector_flex_hdr_upd_ctrl_set(unit,
    753                         mem, ctrl_array[index], ctrl_bin_array[index],
    754                         pkt_build, &hdr, &chksum_bin_map);
    755                 BCM_IF_ERROR_RETURN(rv);
    756             }
    757             break;
    758 
    759         case bcmFlowtrackerCollectorTransportTypeIpfixIpv6Udp:
    760 
    761             /* Do Not Change Order */
    762             ctrl_array[0] = BCMI_FTE_IPFIX_HDR_CTRL_LENGTH;
    763             ctrl_bin_array[0] = 0;
    764             ctrl_array[1] = BCMI_FTE_IPFIX_HDR_CTRL_TIMESTAMP;
    765             ctrl_bin_array[1] = 1;
    766             ctrl_array[2] = BCMI_FTE_IPFIX_HDR_CTRL_SEQ_NUM;
    767             ctrl_bin_array[2] = 2;
    768             ctrl_array[3] = BCMI_FTE_UDP_HDR_CTRL_LENGTH;
    769             ctrl_bin_array[3] = 3;
    770             ctrl_array[4] = BCMI_FTE_UDP_HDR_CTRL_CHKSUM;
    771             ctrl_bin_array[4] = 4;
    772             ctrl_array[5] = BCMI_FTE_IPV6_HDR_CTRL_IP_LENGTH;
    773             ctrl_bin_array[5] = 5;
    774             ctrl_count = 6;
    775 
    776             for (index = 0; index < ctrl_count; index++) {
    777                 rv = bcmi_ft_collector_flex_hdr_upd_ctrl_set(unit,
    778                         mem, ctrl_array[index], ctrl_bin_array[index],
    779                         pkt_build, &hdr, &chksum_bin_map);
    780                 BCM_IF_ERROR_RETURN(rv);
    781             }
    782             break;
    783 
    784         default:
    785             return BCM_E_PARAM;
    786     }
    787 
    788     /* Encap length. */
    789     soc_mem_field32_set(unit, mem, &hdr, HDR_BYTE_LENGTHf,
    790             pkt_build->encap_length);
    791 
    792     soc_mem_write(unit, mem, COPYNO_ALL, coll_hw_id, &hdr);
    793 
    794     return BCM_E_NONE;
    795 }
    796 
    797 int
    798 bcmi_ft_num_records_enc_get(int unit, int val, uint32 *num_rec_enc)
    799 {
    800     int idx = 0;
    801 
    802     uint32 record_enc_array[] = { 0, 1, 4, 8, 12, 16, 20, 24,
    803                                  28, 32, 40, 48, 56, 64, 96, 128};
    804 
    805     if (num_rec_enc == NULL) {
    806         return BCM_E_PARAM;
    807     }
    808 
    809     /* Round off to lower nearest encoding */
    810     for (idx = 0; idx < (COUNTOF(record_enc_array) - 1); idx++) {
    811         if ((val >= record_enc_array[idx]) &&
    812             (val < record_enc_array[idx + 1])) {
    813             break;
    814         }
    815     }
    816     *num_rec_enc = idx;
    817 
    818     return BCM_E_NONE;
    819 }
    820 
    821 
    822 
    823 /* Routine to install FT collector hardware. */
    824 STATIC int
    825 bcmi_ft_collector_hw_install(int unit,
    826                              bcm_flowtracker_collector_t coll_hw_id,
    827                              int coll_enable)
    828 {
    829     int ix, rv;
    830     int m_idx, m_bytes, m_entries;
    831     int min_ptr;
    832     int fifo_depth;
    833     int coll_depth;
    834     int num_collectors;
    835     int init_seq;
    836     int num_records;
    837     uint32 num_records_enc;
    838 
    839     uint8 *buffer;
    840     uint32 rval = 0;
    841     uint32 dma_en, dma_coll_id;
    842     uint32 m_entry_val[2];
    843     bcmi_ft_pkt_build_t pkt_build;
    844 
    845     soc_mem_t collector_mem;
    846     soc_reg_t collector_reg;
    847 
    848     bsc_ex_collector_ipfix_packet_build_entry_t m_entry;
    849     bsc_ex_collector_config_entry_t config;
    850 
    851     bcmi_ft_collector_info_t *ft_coll_info;
    852     bcm_flowtracker_collector_info_t *collector_info;
    853 
    854 
    855     /* Init pkt_build. */
    856     sal_memset(&pkt_build, 0, sizeof(bcmi_ft_pkt_build_t));
    857 
    858     ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, coll_hw_id);
    859     collector_info = &(ft_coll_info->collector_info);
    860 
    861     num_records = 1;
    862     num_collectors = BCMI_FT_EXPORT_INFO(unit)->max_collectors;
    863     fifo_depth = (soc_mem_index_count(unit, BSC_EX_EXPORT_FIFOm) / 2);
    864     coll_depth = (fifo_depth / num_collectors);
    865     min_ptr = (coll_depth * coll_hw_id);
    866     m_entries = (soc_mem_index_count(unit, BSC_EX_COLLECTOR_IPFIX_PACKET_BUILDm) /
    867                  soc_mem_index_count(unit, BSC_EX_COLLECTOR_CONFIGm));
    868 
    869     init_seq = (ft_coll_info->ipfix_hdr).initial_sequence_num;
    870 
    871     /* Flush Collector before enabling. */
    872     collector_mem = BSC_EX_COLLECTOR_CONFIGm;
    873     sal_memset(&config, 0, sizeof(config));
    874     soc_mem_field32_set(unit, collector_mem,
    875                         &config, FLUSHf, 0x1);
    876     soc_mem_write(unit, collector_mem, COPYNO_ALL, coll_hw_id, &config);
    877 
    878 
    879 
    880     /* Disable DMA for Local collector */
    881     collector_reg = BSC_EX_EXPORT_CONTROLr;
    882     rv = soc_reg32_get(unit, collector_reg, REG_PORT_ANY, 0, &rval);
    883     BCM_IF_ERROR_RETURN(rv);
    884 
    885     dma_en = soc_reg_field_get(unit, collector_reg, rval, DMA_ENf);
    886     dma_coll_id = soc_reg_field_get(unit, collector_reg, rval, DMA_COLLECTOR_IDf);
    887 
    888     if ((dma_en == 1) && (coll_hw_id == dma_coll_id)) {
    889         soc_reg_field_set(unit, collector_reg, &rval, DMA_ENf, 0x0);
    890         soc_reg_field_set(unit, collector_reg, &rval, DMA_COLLECTOR_IDf, 0x0);
    891 
    892         rv = soc_reg32_set(unit, collector_reg, REG_PORT_ANY, 0, rval);
    893         BCM_IF_ERROR_RETURN(rv);
    894     }
    895 
    896 
    897     /* For uninstalling, flush collector, disable and return  */
    898     if (coll_enable == 0) {
    899         return BCM_E_NONE;
    900     }
    901 
    902     /* Populate PACKET_BUILD. */
    903     if (collector_info->collector_type == bcmFlowtrackerCollectorRemote) {
    904         collector_mem = BSC_EX_COLLECTOR_IPFIX_PACKET_BUILDm;
    905 
    906         sal_memset(&pkt_build, 0, sizeof(pkt_build));
    907 
    908         rv = bcmi_ft_collector_packet_build(unit, ft_coll_info, &pkt_build);
    909         BCM_IF_ERROR_RETURN(rv);
    910 
    911         num_records = ft_coll_info->num_records;
    912         if (num_records == -1) {
    913             num_records = ((collector_info->max_packet_length -
    914                             pkt_build.encap_length) /
    915                            (BCMI_FT_IPFIX_RECORD_SIZE));
    916         }
    917 
    918         /* Populate PACKET_BUILD */
    919         buffer = &(pkt_build.encap[0]);
    920         m_bytes = soc_mem_entry_bytes(unit, collector_mem);
    921         m_idx = (coll_hw_id * m_entries);
    922 
    923         for (ix = 0; ix < (m_entries * m_bytes); ix += m_bytes) {
    924             /* 64 bit FIELDS field is to be written in Network byte order */
    925             SHR_PKT_UNPACK_U32(buffer, m_entry_val[1]);
    926             SHR_PKT_UNPACK_U32(buffer, m_entry_val[0]);
    927 
    928             soc_mem_field_set(unit, collector_mem, (uint32 *)&m_entry,
    929                               FIELDSf, m_entry_val);
    930             soc_mem_write(unit, collector_mem,
    931                           COPYNO_ALL, (m_idx + (ix / m_bytes)), &m_entry);
    932         }
    933 
    934         /* Configure HDR_CONSTRUCT fields. */
    935         rv = bcmi_ft_collector_hdr_construct(unit,
    936                     coll_hw_id, collector_info, &pkt_build);
    937         BCM_IF_ERROR_RETURN(rv);
    938     }
    939 
    940     rv = bcmi_ft_num_records_enc_get(unit, num_records, &num_records_enc);
    941     BCM_IF_ERROR_RETURN(rv);
    942 
    943     /* Reset sequence number. */
    944     rval = 0;
    945     soc_reg_field_set(unit, BSC_EX_SEQ_NUMr, &rval, SEQ_NUMf, init_seq);
    946     rv = soc_reg32_set(unit, BSC_EX_SEQ_NUMr, REG_PORT_ANY, coll_hw_id, rval);
    947     BCM_IF_ERROR_RETURN(rv);
    948 
    949     /* Enable Collector. */
    950     collector_mem = BSC_EX_COLLECTOR_CONFIGm;
    951     soc_mem_field32_set(unit, collector_mem,
    952                         &config, FLUSHf, 0x0);
    953     soc_mem_field32_set(unit, collector_mem,
    954                         &config, ENABLEf, 0x1);
    955     soc_mem_field32_set(unit, collector_mem,
    956                         &config, MAX_POINTERf, (min_ptr + coll_depth - 1));
    957     soc_mem_field32_set(unit, collector_mem,
    958                         &config, MIN_POINTERf, min_ptr);
    959     soc_mem_field32_set(unit, collector_mem,
    960                         &config, MAX_RECORDS_PER_PACKETf, num_records_enc);
    961     soc_mem_field32_set(unit, collector_mem,
    962                         &config, TIME_INTERVAL_ENABLEf, 0x1);
    963     soc_mem_field32_set(unit, collector_mem,
    964                         &config, TIME_INTERVALf, 0x1);
    965 
    966 
    967     /* Enable threshold based drain. */
    968     if (SAL_BOOT_BCMSIM) {
    969         soc_mem_field32_set(unit, collector_mem,
    970                             &config, MAX_RECORDS_PER_PACKETf, 0x1);
    971         soc_mem_field32_set(unit, collector_mem,
    972                             &config, TIME_INTERVAL_ENABLEf, 0x0);
    973         soc_mem_field32_set(unit, collector_mem,
    974                             &config, TIME_INTERVALf, 0x0);
    975     }
    976 
    977     if (collector_info->collector_type == bcmFlowtrackerCollectorRemote) {
    978         soc_mem_field32_set(unit, collector_mem,
    979                             &config, PACKET_BUILD_ENABLEf, 0x1);
    980     } else {
    981         /* Local collector */
    982         rval = 0;
    983         collector_reg = BSC_EX_EXPORT_CONTROLr;
    984 
    985         soc_reg_field_set(unit, collector_reg, &rval, DMA_ENf, 0x1);
    986         soc_reg_field_set(unit, collector_reg, &rval, DMA_COLLECTOR_IDf, coll_hw_id);
    987 
    988         rv = soc_reg32_set(unit, collector_reg, REG_PORT_ANY, 0, rval);
    989         BCM_IF_ERROR_RETURN(rv);
    990     }
    991     soc_mem_write(unit, collector_mem, COPYNO_ALL, coll_hw_id, &config);
    992 
    993     return BCM_E_NONE;
    994 }
    995 
    996 /* Routine to validate collector params. */
    997 STATIC int
    998 bcmi_ft_collector_info_validate(int unit,
    999                                 bcm_flowtracker_collector_info_t *info)
   1000 {
   1001     int min_frame_size = 0, max_frame_size = 0;
   1002 
   1003     /* Check if the encap mode is supported. */
   1004     if (info->collector_type == bcmFlowtrackerCollectorRemote) {
   1005         switch (info->transport_type) {
   1006             case bcmFlowtrackerCollectorTransportTypeIpfixIpv4Udp:
   1007             case bcmFlowtrackerCollectorTransportTypeIpfixIpv6Udp:
   1008                 /* Currently supported encap types for remote collector. */
   1009                 break;
   1010             default:
   1011                 return BCM_E_PARAM;
   1012         }
   1013     } else if (info->collector_type == bcmFlowtrackerCollectorLocal) {
   1014         switch (info->transport_type) {
   1015             case bcmFlowtrackerCollectorTransportTypeRaw:
   1016                 /* Only rawmode transport is supported for local collector. */
   1017                 break;
   1018             default:
   1019                 return BCM_E_PARAM;
   1020         }
   1021     } else {
   1022         /* Unknown collector type  */
   1023         return BCM_E_PARAM;
   1024     }
   1025 
   1026     /* Calculate min_frame_size and max_frame_size - TBD */
   1027     if (info->collector_type == bcmFlowtrackerCollectorRemote) {
   1028         /*
   1029          * IpfixIpv4Udp: L2_HDR + IPV4_HDR + UDP_HDR
   1030          * IpfixIpv6Udp: L2_HDR + IPV6_HDR + UDP_HDR
   1031          *
   1032          * L2_HDR: MACDA (6) + MACSA (6) + TPID (2) = 14 Bytes.
   1033          * IPV4_HDR = 20 Bytes.
   1034          * IPV6_HDR = 40 Bytes.
   1035          * UDP_HDR = 8 Bytes.
   1036  */
   1037         if (info->transport_type ==
   1038             bcmFlowtrackerCollectorTransportTypeIpfixIpv4Udp) {
   1039             min_frame_size = 46;
   1040         } else if (info->transport_type ==
   1041                    bcmFlowtrackerCollectorTransportTypeIpfixIpv6Udp) {
   1042             min_frame_size = 66;
   1043         } else {
   1044             return BCM_E_PARAM;
   1045         }
   1046 
   1047         max_frame_size = (BCMI_FT_IPFIX_PACKET_BUILD_MAX_SIZE +
   1048                           (BCMI_FT_IPFIX_MAX_RECORDS_PER_PACKET *
   1049                            BCMI_FT_IPFIX_RECORD_SIZE)
   1050                          );
   1051 
   1052         if ((info->max_packet_length < min_frame_size) ||
   1053             (info->max_packet_length > max_frame_size)) {
   1054             return BCM_E_PARAM;
   1055         }
   1056     }
   1057 
   1058     return BCM_E_NONE;
   1059 }
   1060 
   1061 #if 0
   1062 int hx5_supported_elems[BCMI_FT_MAX_TEMPLATES] = {
   1063     bcmFlowtrackerExportElementTypeSrcIPv4,
   1064     bcmFlowtrackerExportElementTypeDstIPv4,
   1065     bcmFlowtrackerExportElementTypeSrcIPv6,
   1066     bcmFlowtrackerExportElementTypeDstIPv6,
   1067     bcmFlowtrackerExportElementTypeL4SrcPort,
   1068     bcmFlowtrackerExportElementTypeL4DstPort,
   1069     bcmFlowtrackerExportElementTypeIPProtocol,
   1070     bcmFlowtrackerExportElementTypePktCount,
   1071     bcmFlowtrackerExportElementTypeByteCount,
   1072     bcmFlowtrackerExportElementTypeFlowtrackerGroup,
   1073     bcmFlowtrackerExportElementTypeReserved
   1074 };
   1075 
   1076 struct hx5_support_elem_s {
   1077     bcm_flowtracker_export_element_type_t elem;
   1078     char elem_name[20];
   1079 } hx5_supported_elems[BCMI_FT_MAX_TEMPLATES] = {
   1080     {bcmFlowtrackerExportElementTypeSrcIPv4,
   1081      "SrcIpv4"},
   1082     {bcmFlowtrackerExportElementTypeDstIPv4,
   1083      "DstIpv4"},
   1084     {bcmFlowtrackerExportElementTypeSrcIPv6,
   1085      "SrcIpv6"},
   1086     {bcmFlowtrackerExportElementTypeDstIPv6,
   1087      "DstIpv6"},
   1088     {bcmFlowtrackerExportElementTypeL4SrcPort,
   1089      "SrcL4Port"},
   1090     {bcmFlowtrackerExportElementTypeL4DstPort,
   1091      "DstL4Port"},
   1092     {bcmFlowtrackerExportElementTypeIPProtocol,
   1093      "IpProto"},
   1094     {bcmFlowtrackerExportElementTypePktCount,
   1095      "PktCount"},
   1096     {bcmFlowtrackerExportElementTypeByteCount,
   1097      "ByteCount"},
   1098     {bcmFlowtrackerExportElementTypeFlowtrackerGroup,
   1099      "FlowGroup"},
   1100     {bcmFlowtrackerExportElementTypeReserved,
   1101      "Reserved"},
   1102 };
   1103 #endif
   1104 
   1105 
   1106 /* Routine to validate template params. */
   1107 STATIC int
   1108 bcmi_ft_template_validate(int unit,
   1109                           int num_elems,
   1110                           bcm_flowtracker_export_element_info_t *elem_list)
   1111 {
   1112     int ix, jx;
   1113     bcm_flowtracker_export_element_info_t *elem;
   1114 
   1115     if ((num_elems <= 0) ||
   1116         (num_elems >= BCMI_FT_EXPORT_INFO(unit)->max_elements)) {
   1117         return BCM_E_PARAM;
   1118     }
   1119 
   1120 
   1121     for (jx = 0; jx < num_elems; jx++) {
   1122         elem = elem_list +jx;
   1123 
   1124         for (ix = 0; ix < COUNTOF(bcmi_ft_export_elements_map); ix++) {
   1125             if (elem->element == bcmi_ft_export_elements_map[ix].export_element) {
   1126                 /* Break the loop when found. */
   1127                 break;
   1128             }
   1129         }
   1130 
   1131         /* Reached end of supported list. Not found.  */
   1132         if (ix >= COUNTOF(bcmi_ft_export_elements_map)) {
   1133             LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   1134                       (BSL_META_U(unit,
   1135                                   "Could not find name for element %d\n"), elem->element));
   1136             return BCM_E_PARAM;
   1137         }
   1138     }
   1139 
   1140     return BCM_E_NONE;
   1141 }
   1142 
   1143 /*
   1144  * Function:
   1145  *     bcmi_ft_template_id_alloc
   1146  * Purpose:
   1147  *     get free index for template id.
   1148  * Parameters:
   1149  *     unit - (IN) BCM device id
   1150  *     alloc - (IN) Allocate a fresh id.
   1151  *     template_id   - (OUT) FT export template id.
   1152  *
   1153  * Returns:
   1154  *     BCM_E_XXX.
   1155  */
   1156 STATIC int
   1157 bcmi_ft_template_id_alloc(int unit, int alloc, int *template_id)
   1158 {
   1159 
   1160     int idx, num_templates;
   1161 
   1162     num_templates = BCMI_FT_EXPORT_INFO(unit)->max_templates;
   1163 
   1164 
   1165     if (!alloc) {
   1166         idx = *template_id;
   1167         if ((idx >= num_templates) ||
   1168             (idx <= BCMI_FT_TEMPLATE_ID_INVALID)) {
   1169             return BCM_E_PARAM;
   1170         }
   1171 
   1172         if ((SHR_BITGET(BCMI_FT_TEMPLATE_BITMAP(unit), idx))) {
   1173             return BCM_E_EXISTS;
   1174         }
   1175 
   1176         /* Reserve new id. */
   1177         SHR_BITSET(BCMI_FT_TEMPLATE_BITMAP(unit), idx);
   1178 
   1179         return BCM_E_NONE;
   1180     }
   1181 
   1182     for (idx = 0; idx < num_templates; idx++) {
   1183 
   1184         if (!(SHR_BITGET(BCMI_FT_TEMPLATE_BITMAP(unit), idx))) {
   1185 
   1186             /* Found an unused template id. */
   1187             SHR_BITSET(BCMI_FT_TEMPLATE_BITMAP(unit), idx);
   1188 
   1189             *template_id = idx;
   1190             return BCM_E_NONE;
   1191         }
   1192     }
   1193 
   1194     return BCM_E_RESOURCE;
   1195 }
   1196 
   1197 
   1198 
   1199 
   1200 /*
   1201  * Function:
   1202  *     bcmi_ft_export_state_clear
   1203  * Purpose:
   1204  *     Clear Flowtracker export state.
   1205  * Parameters:
   1206  *     unit - (IN) BCM device id
   1207  *
   1208  * Returns:
   1209  *     None.
   1210  */
   1211 int
   1212 bcmi_ft_export_state_clear(int unit)
   1213 {
   1214     int ix;
   1215     bcmi_ft_template_info_t *template_info;
   1216 
   1217     if (NULL == BCMI_FT_EXPORT_INFO(unit)) {
   1218         return (BCM_E_NONE);
   1219     }
   1220 
   1221     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_templates; ix++) {
   1222         template_info = BCMI_FT_TEMPLATE_INFO(unit, ix);
   1223 
   1224         if (template_info != NULL) {
   1225             sal_free(template_info);
   1226             template_info = NULL;
   1227         }
   1228     }
   1229 
   1230 
   1231     if (bcmi_ft_export_state[unit] != NULL) {
   1232         sal_free(bcmi_ft_export_state[unit]);
   1233         bcmi_ft_export_state[unit] = NULL;
   1234     }
   1235 
   1236     return BCM_E_NONE;
   1237 }
   1238 
   1239 /*
   1240  * Function:
   1241  *     bcmi_ft_export_state_init
   1242  * Purpose:
   1243  *     Initialize Flowtracker export state.
   1244  * Parameters:
   1245  *     unit - (IN) BCM device id
   1246  *
   1247  * Returns:
   1248  *     None.
   1249  */
   1250 int
   1251 bcmi_ft_export_state_init(int unit)
   1252 {
   1253     int ix;
   1254     int num_collectors;
   1255     int record_length;
   1256     soc_mem_t collector_config_mem;
   1257     bcmi_ft_collector_info_t *collector_info;
   1258     bcmi_ft_template_info_t *template_info;
   1259 
   1260     collector_config_mem = BSC_EX_COLLECTOR_CONFIGm;
   1261 
   1262     /* Allocate export software state. */
   1263     bcmi_ft_export_state[unit] =
   1264         sal_alloc(sizeof(bcmi_ft_export_state_t),
   1265                   "flowtracker export sw state");
   1266 
   1267     if (bcmi_ft_export_state[unit] == NULL) {
   1268         return BCM_E_MEMORY;
   1269     }
   1270     sal_memset(bcmi_ft_export_state[unit], 0, sizeof(bcmi_ft_export_state_t));
   1271 
   1272     /* total number of collectors. */
   1273     num_collectors = soc_mem_index_count(unit, collector_config_mem);
   1274     BCMI_FT_EXPORT_INFO(unit)->max_collectors = num_collectors;
   1275 
   1276     /* Max number of templates cannot be greater than the max groups.
   1277      * Note: EXPORT_FIFO will have half of the record in each entry.
   1278      */
   1279     record_length = (soc_mem_entry_words(unit, BSC_EX_EXPORT_FIFOm) * 2) * 4;
   1280     BCMI_FT_EXPORT_INFO(unit)->record_length = record_length;
   1281 
   1282     BCMI_FT_EXPORT_INFO(unit)->max_templates =
   1283         soc_mem_index_count(unit, BSC_KG_GROUP_TABLEm);
   1284 
   1285     /* Max number of elements in a template cannot be more than the
   1286      * number of octets in a record. */
   1287     BCMI_FT_EXPORT_INFO(unit)->max_elements =
   1288         BCMI_FT_EXPORT_INFO(unit)->record_length;
   1289 
   1290     /* Initialize independent collector_info structures. */
   1291     for (ix = 0; ix < num_collectors; ix++) {
   1292         collector_info = BCMI_FT_COLLECTOR_INFO(unit, ix);
   1293         collector_info->coll_hw_id = BCMI_FT_COLLECTOR_ID_INVALID;
   1294         collector_info->cmn_coll_id = BCMI_FT_COLLECTOR_ID_INVALID;
   1295         collector_info->num_records = -1;
   1296     }
   1297 
   1298     /* Allocate memory for each template_info struct. */
   1299     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_templates; ix++) {
   1300 
   1301         template_info = sal_alloc(sizeof(*template_info), "template info");
   1302         if (template_info == NULL) {
   1303             return BCM_E_MEMORY;
   1304         }
   1305 
   1306         sal_memset(template_info, 0, sizeof(*template_info));
   1307         template_info->template_id = BCMI_FT_TEMPLATE_ID_INVALID;
   1308 
   1309         BCMI_FT_TEMPLATE_INFO(unit, ix) = template_info;
   1310     }
   1311 
   1312     return BCM_E_NONE;
   1313 }
   1314 
   1315 
   1316 int
   1317 bcmi_ft_export_init(int unit)
   1318 {
   1319     int rv;
   1320     int ipfix_obs_domain_id;
   1321     uint32 fld_len, interval, high_val;
   1322     uint32 interval_usecs, interval_secs;
   1323     uint64 val64;
   1324 
   1325     rv = bcmi_ft_export_cleanup(unit);
   1326     BCM_IF_ERROR_RETURN(rv);
   1327 
   1328     rv = bcmi_ft_export_state_init(unit);
   1329     BCM_IF_ERROR_RETURN(rv);
   1330 
   1331     if (soc_feature(unit, soc_feature_bscan_ft_fifodma_support)) {
   1332         rv = bcmi_ft_export_cb_init(unit);
   1333         BCM_IF_ERROR_RETURN(rv);
   1334     }
   1335 
   1336     ipfix_obs_domain_id = soc_property_get(unit,
   1337                               spn_FLOWTRACKER_IPFIX_OBSERVATION_DOMAIN_ID,
   1338                               BCMI_FTE_IPFIX_HDR_OBS_DOMAIN);
   1339     BCMI_FT_EXPORT_INFO(unit)->ipfix_observation_domain_id =
   1340                                   ipfix_obs_domain_id;
   1341 
   1342     interval_secs = soc_property_get(unit,
   1343                         spn_FLOWTRACKER_EXPORT_INTERVAL_SECS, 0);
   1344     interval_usecs = soc_property_get(unit,
   1345                           spn_FLOWTRACKER_EXPORT_INTERVAL_USECS, 0);
   1346 
   1347     /* Export Interval in seconds */
   1348     COMPILER_64_SET(val64, 0, interval_secs);
   1349 
   1350     /* Export Interval in 100 msecs */
   1351     COMPILER_64_UMUL_32(val64, 10);
   1352 
   1353     /* Converting usecs to 100 msecs */
   1354     interval = interval_usecs / 1000;
   1355     interval = interval / 100;
   1356 
   1357     /* Add to get export interval in 100 msecs */
   1358     COMPILER_64_ADD_32(val64, interval);
   1359 
   1360     COMPILER_64_TO_32_HI(high_val, val64);
   1361     if (high_val != 0) {
   1362         interval = 0xFFFFFFFF;
   1363     } else {
   1364         COMPILER_64_TO_32_LO(interval, val64);
   1365     }
   1366     /* In case user have configured export interval value less than 100 ms,
   1367      * but not zero. here user intention is to set least value of export
   1368      * interval, so set interval=1 (100 ms) */
   1369     if ((interval == 0) && (interval_usecs != 0)) {
   1370         interval = 1;
   1371     }
   1372 
   1373     fld_len = soc_reg_field_length(unit, BSC_AG_PERIODIC_EXPORTr, EXPORT_PERIODf);
   1374 
   1375     /* Do not exceed field length */
   1376     interval = MIN(interval, ((1 << fld_len) - 1));
   1377 
   1378     rv = soc_reg_field32_modify(unit, BSC_AG_PERIODIC_EXPORTr,
   1379                                 REG_PORT_ANY, EXPORT_PERIODf, interval);
   1380 
   1381     return rv;
   1382 }
   1383 
   1384 int
   1385 bcmi_ft_export_cleanup(int unit)
   1386 {
   1387     int rv;
   1388 
   1389     if (soc_feature(unit, soc_feature_bscan_ft_fifodma_support)) {
   1390         rv = bcmi_ft_export_cb_deinit(unit);
   1391         BCM_IF_ERROR_RETURN(rv);
   1392     }
   1393 
   1394     rv = bcmi_ft_export_state_clear(unit);
   1395     BCM_IF_ERROR_RETURN(rv);
   1396 
   1397     return rv;
   1398 }
   1399 
   1400 
   1401 
   1402 /*
   1403  * Function:
   1404  *     bcmi_ft_collector_create
   1405  * Purpose:
   1406  *     Create flowtracker collector id.
   1407  * Description :
   1408  *     Routine to create a flowtracker collector
   1409  * Parameters:
   1410  *     unit - (IN) BCM device id
   1411  *     options - (IN) options for group creation
   1412  *     coll_hw_id   - (OUT) FT collector id.
   1413  *     collector_info - (IN) Collector info.
   1414  *
   1415  * Returns:
   1416  *     BCM_E_XXX
   1417  */
   1418 int
   1419 bcmi_ft_collector_create(
   1420     int unit,
   1421     uint32 options,
   1422     bcm_flowtracker_collector_t *coll_hw_id,
   1423     bcm_flowtracker_collector_info_t *collector_info)
   1424 {
   1425     int rv;
   1426     int idx;
   1427     bcm_flowtracker_collector_info_t old_collector_info;
   1428     bcmi_ft_collector_info_t *ft_coll_info;
   1429     bcm_collector_ipfix_header_t *ipfix_hdr;
   1430 
   1431     /* Check if remote collector is supported. */
   1432     if (collector_info->collector_type ==
   1433         bcmFlowtrackerCollectorRemote) {
   1434 
   1435         if (!(soc_feature(unit,
   1436             soc_feature_flowtracker_ver_1_ipfix_remote_collector))) {
   1437             return BCM_E_UNAVAIL;
   1438         }
   1439     }
   1440 
   1441     /*
   1442      * Validate collector_info for any unsupported encap or
   1443      * export length etc.
   1444      */
   1445     rv = bcmi_ft_collector_info_validate(unit, collector_info);
   1446     BCM_IF_ERROR_RETURN(rv);
   1447 
   1448 
   1449     /* REPLACE should be set along with WITH_ID. */
   1450     if ((options & BCM_FLOWTRACKER_COLLECTOR_REPLACE) &&
   1451        !(options & BCM_FLOWTRACKER_COLLECTOR_WITH_ID)) {
   1452         return BCM_E_PARAM;
   1453     }
   1454 
   1455     /* While replacing, original entry should be already created. */
   1456     if (options & BCM_FLOWTRACKER_COLLECTOR_REPLACE) {
   1457         sal_memset(&old_collector_info, 0, sizeof(old_collector_info));
   1458 
   1459         rv = bcmi_ft_collector_get(unit, *coll_hw_id, &old_collector_info);
   1460         BCM_IF_ERROR_RETURN(rv);
   1461     }
   1462 
   1463     /* WITH_ID and not replacing. */
   1464     if (options & BCM_FLOWTRACKER_COLLECTOR_WITH_ID) {
   1465 
   1466         if (options & BCM_FLOWTRACKER_COLLECTOR_REPLACE) {
   1467             /* Reserve Id. */
   1468             ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, *coll_hw_id);
   1469             ft_coll_info->coll_hw_id = *coll_hw_id;
   1470         }
   1471 
   1472     } else {
   1473         for (idx = 0; idx < BCMI_FT_MAX_COLLECTORS; idx++) {
   1474             ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, idx);
   1475             if (ft_coll_info->coll_hw_id ==
   1476                     BCMI_FT_COLLECTOR_ID_INVALID) {
   1477                 break;
   1478             }
   1479         }
   1480         if (idx < BCMI_FT_MAX_COLLECTORS) {
   1481             *coll_hw_id = idx;
   1482             ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, *coll_hw_id);
   1483             ft_coll_info->coll_hw_id = *coll_hw_id;
   1484         } else {
   1485             return BCM_E_PARAM;
   1486         }
   1487     }
   1488 
   1489     /* Copy the collector info to system cache. */
   1490     ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, *coll_hw_id);
   1491     sal_memcpy(&(ft_coll_info->collector_info),
   1492                collector_info, sizeof(*collector_info));
   1493 
   1494     if (!(ft_coll_info->ipfix_hdr_use_custom)) {
   1495 
   1496         ipfix_hdr = &(ft_coll_info->ipfix_hdr);
   1497         ipfix_hdr->version = BCMI_FTE_IPFIX_HDR_VERSION;
   1498         ipfix_hdr->initial_sequence_num = 0;
   1499     }
   1500 
   1501     /* Install in hardware. */
   1502     rv = bcmi_ft_collector_hw_install(unit, *coll_hw_id, TRUE);
   1503 
   1504     if (BCM_SUCCESS(rv)) {
   1505         ft_coll_info->coll_hw_id = *coll_hw_id;
   1506     }
   1507 
   1508     return rv;
   1509 }
   1510 
   1511 
   1512 /*
   1513  * Function:
   1514  *     bcmi_ft_collector_get
   1515  * Purpose:
   1516  *     Fetch flowtracker collector info.
   1517  * Description :
   1518  *     Routine to create a flowtracker collector
   1519  * Parameters:
   1520  *     unit - (IN) BCM device id
   1521  *     coll_hw_id   - (OUT) FT collector id.
   1522  *     collector_info - (IN) Collector info.
   1523  *
   1524  * Returns:
   1525  *     BCM_E_XXX
   1526  */
   1527 int
   1528 bcmi_ft_collector_get(
   1529     int unit,
   1530     bcm_flowtracker_collector_t coll_hw_id,
   1531     bcm_flowtracker_collector_info_t *collector_info)
   1532 {
   1533     bcmi_ft_collector_info_t *ft_coll_info;
   1534 
   1535     if (collector_info == NULL) {
   1536         return BCM_E_PARAM;
   1537     }
   1538     if ((coll_hw_id <= BCMI_FT_COLLECTOR_ID_INVALID) ||
   1539         (coll_hw_id >= BCMI_FT_MAX_COLLECTORS)) {
   1540         return BCM_E_PARAM;
   1541     }
   1542 
   1543     ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, coll_hw_id);
   1544 
   1545     if (ft_coll_info->coll_hw_id == BCMI_FT_COLLECTOR_ID_INVALID) {
   1546         return BCM_E_PARAM;
   1547     }
   1548 
   1549     sal_memcpy(collector_info,
   1550                &(ft_coll_info->collector_info),
   1551                sizeof(*collector_info));
   1552 
   1553     return BCM_E_NONE;
   1554 }
   1555 
   1556 
   1557 /*
   1558  * Function:
   1559  *     bcmi_ft_collector_get_all
   1560  * Purpose:
   1561  *     Fetch all flowtracker collectors info.
   1562  * Description :
   1563  *     Routine to create a flowtracker collector
   1564  * Parameters:
   1565  *     unit - (IN) BCM device id
   1566  *     max_size   - (OUT) Max collectors to read.
   1567  *     collector_list - (OUT) Collector id list.
   1568  *     list_size (OUT) - Num of collectors read.
   1569  *
   1570  * Returns:
   1571  *     BCM_E_XXX
   1572  */
   1573 int
   1574 bcmi_ft_collector_get_all(
   1575     int unit,
   1576     int max_size,
   1577     bcm_flowtracker_collector_t *collector_list,
   1578     int *list_size)
   1579 {
   1580     int idx, cnt;
   1581     bcm_flowtracker_collector_t *coll_hw_id;
   1582     bcmi_ft_collector_info_t *ft_coll_info;
   1583 
   1584     if ((max_size != 0) && (collector_list == NULL)) {
   1585         return BCM_E_PARAM;
   1586     }
   1587     if (list_size == NULL) {
   1588         return BCM_E_PARAM;
   1589     }
   1590 
   1591     if ((max_size <= BCMI_FT_COLLECTOR_ID_INVALID) ||
   1592         (max_size >= BCMI_FT_MAX_COLLECTORS)) {
   1593         return BCM_E_PARAM;
   1594     }
   1595 
   1596     *list_size = cnt = 0;
   1597 
   1598     for (idx = 0; idx < BCMI_FT_MAX_COLLECTORS; idx++) {
   1599         ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, idx);
   1600         coll_hw_id = &(collector_list[(*list_size)]);
   1601 
   1602         if (ft_coll_info->coll_hw_id == BCMI_FT_COLLECTOR_ID_INVALID) {
   1603             continue;
   1604         }
   1605 
   1606         if (cnt < max_size) {
   1607             *coll_hw_id = ft_coll_info->coll_hw_id;
   1608             cnt++;
   1609         }
   1610 
   1611         (*list_size) += 1;
   1612     }
   1613 
   1614     if (max_size == 0) {
   1615         *list_size = cnt;
   1616     }
   1617 
   1618     return BCM_E_NONE;
   1619 }
   1620 
   1621 /*
   1622  * Function:
   1623  *     bcmi_ft_collector_destroy
   1624  * Purpose:
   1625  *     Destroy flowtracker collector.
   1626  * Description :
   1627  *     Routine to destroy a flowtracker collector
   1628  * Parameters:
   1629  *     unit - (IN) BCM device id
   1630  *     coll_hw_id   - (OUT) FT collector id.
   1631  *
   1632  * Returns:
   1633  *     BCM_E_XXX
   1634  */
   1635 int
   1636 bcmi_ft_collector_destroy(
   1637     int unit,
   1638     bcm_flowtracker_collector_t coll_hw_id)
   1639 {
   1640     bcmi_ft_collector_info_t *ft_coll_info;
   1641 
   1642     if ((coll_hw_id <= BCMI_FT_COLLECTOR_ID_INVALID) ||
   1643         (coll_hw_id >= BCMI_FT_MAX_COLLECTORS)) {
   1644         return BCM_E_PARAM;
   1645     }
   1646 
   1647     ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, coll_hw_id);
   1648     if (ft_coll_info->coll_hw_id == BCMI_FT_COLLECTOR_ID_INVALID) {
   1649         return BCM_E_NOT_FOUND;
   1650     }
   1651 
   1652     /* Allow destroying collector only if it is detached from all groups. */
   1653     if (ft_coll_info->in_use != 0) {
   1654         return BCM_E_BUSY;
   1655     }
   1656 
   1657     sal_memset(&(ft_coll_info->collector_info), 0,
   1658                sizeof(ft_coll_info->collector_info));
   1659     ft_coll_info->coll_hw_id = BCMI_FT_COLLECTOR_ID_INVALID;
   1660     ft_coll_info->cmn_coll_id = BCMI_FT_COLLECTOR_ID_INVALID;
   1661     ft_coll_info->num_records = -1;
   1662 
   1663     BCM_IF_ERROR_RETURN(bcmi_ft_collector_hw_install(unit, coll_hw_id, FALSE));
   1664 
   1665     return BCM_E_NONE;
   1666 }
   1667 
   1668 
   1669 #if 0
   1670 STATIC int
   1671 bcmi_ft_templ_fill_elem(int unit, int num_bits, int elem_size,
   1672                         bcm_flowtracker_export_element_type_t elem_type,
   1673                         bcm_flowtracker_export_element_info_t *out_elems,
   1674                         int *num_elems)
   1675 {
   1676     bcm_flowtracker_export_element_info_t *l_elem_list;
   1677 
   1678     *num_elems = 0;
   1679     while (num_bits) {
   1680         l_elem_list = out_elems;
   1681 
   1682         l_elem_list->element = elem_type;
   1683         l_elem_list->data_size = 1;
   1684 
   1685         num_bits -= elem_size;
   1686         out_elems++;
   1687         (*num_elems)++;
   1688     }
   1689 
   1690     return BCM_E_NONE;
   1691 }
   1692 #endif
   1693 
   1694 STATIC int
   1695 bcmi_ft_tracking_param_xlate(int unit,
   1696                              bcm_flowtracker_tracking_param_type_t elem,
   1697                              int *size,
   1698                              bcm_flowtracker_export_element_type_t *info_elem)
   1699 {
   1700     int ix;
   1701 
   1702     for (ix = 0; ix < COUNTOF(bcmi_ft_export_elements_map); ix++) {
   1703         if (bcmi_ft_export_elements_map[ix].tracking_param == elem) {
   1704             if (size) {
   1705                 *size = bcmi_ft_export_elements_map[ix].default_data_size;
   1706             }
   1707             if (info_elem) {
   1708                 *info_elem = bcmi_ft_export_elements_map[ix].export_element;
   1709             }
   1710 
   1711             break;
   1712         }
   1713     }
   1714 
   1715 
   1716     return BCM_E_NONE;
   1717 }
   1718 
   1719 
   1720 
   1721 #if 0
   1722 typedef enum pdd_field_type_e {
   1723     bcmiFtePddFldTypeAlu32,
   1724     bcmiFtePddFldTypeLoad16,
   1725     bcmiFtePddFldTypeAlu16,
   1726     bcmiFtePddFldTypeLoad8,
   1727     bcmiFtePddFldTypeReserved,
   1728 } pdd_field_type_t;
   1729 
   1730 struct bcmi_fte_pdd_fields_s {
   1731     int length;
   1732     pdd_field_type_t field_type;
   1733     soc_field_t pdd_field;
   1734 } bcmi_fte_flex_pdd_action_list[] = {
   1735         {4, bcmiFtePddFldTypeReserved, BSD_FLEX_TIMESTAMP_0f,              },
   1736         {4, bcmiFtePddFldTypeReserved, BSD_FLEX_TIMESTAMP_1f,              },
   1737         {4, bcmiFtePddFldTypeReserved, BSD_FLEX_TIMESTAMP_2f,              },
   1738         {4, bcmiFtePddFldTypeReserved, BSD_FLEX_TIMESTAMP_3f,              },
   1739         {4, bcmiFtePddFldTypeReserved, BSD_FLEX_FLOW_METERf,               },
   1740         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_0f,   },
   1741         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_1f,   },
   1742         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_2f,   },
   1743         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_3f,   },
   1744         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_4f,   },
   1745         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_5f,   },
   1746         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_6f,   },
   1747         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_7f,   },
   1748         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_8f,   },
   1749         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_9f,   },
   1750         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_10f,  },
   1751         {4, bcmiFtePddFldTypeAlu32,    BSD_FLEX_ALU32_TRACKING_PARAM_11f,  },
   1752         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_0f,  },
   1753         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_1f,  },
   1754         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_2f,  },
   1755         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_3f,  },
   1756         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_4f,  },
   1757         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_5f,  },
   1758         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_6f,  },
   1759         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_7f,  },
   1760         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_8f,  },
   1761         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_9f,  },
   1762         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_10f, },
   1763         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_11f, },
   1764         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_12f, },
   1765         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_13f, },
   1766         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_14f, },
   1767         {2, bcmiFtePddFldTypeLoad16,   BSD_FLEX_LOAD16_TRACKING_PARAM_15f, },
   1768         {2, bcmiFtePddFldTypeAlu16,    BSD_FLEX_ALU16_TRACKING_PARAM_0f,   },
   1769         {2, bcmiFtePddFldTypeAlu16,    BSD_FLEX_ALU16_TRACKING_PARAM_1f,   },
   1770         {2, bcmiFtePddFldTypeAlu16,    BSD_FLEX_ALU16_TRACKING_PARAM_2f,   },
   1771         {2, bcmiFtePddFldTypeAlu16,    BSD_FLEX_ALU16_TRACKING_PARAM_3f,   },
   1772         {2, bcmiFtePddFldTypeAlu16,    BSD_FLEX_ALU16_TRACKING_PARAM_4f,   },
   1773         {2, bcmiFtePddFldTypeAlu16,    BSD_FLEX_ALU16_TRACKING_PARAM_5f,   },
   1774         {2, bcmiFtePddFldTypeAlu16,    BSD_FLEX_ALU16_TRACKING_PARAM_6f,   },
   1775         {2, bcmiFtePddFldTypeAlu16,    BSD_FLEX_ALU16_TRACKING_PARAM_7f,   },
   1776         {2, bcmiFtePddFldTypeReserved, BSD_FLEX_FLOW_COUNT_TO_CPUf,        },
   1777         {1, bcmiFtePddFldTypeLoad8,    BSD_FLEX_LOAD8_TRACKING_PARAM_0f,   },
   1778         {1, bcmiFtePddFldTypeLoad8,    BSD_FLEX_LOAD8_TRACKING_PARAM_1f,   },
   1779         {1, bcmiFtePddFldTypeLoad8,    BSD_FLEX_LOAD8_TRACKING_PARAM_2f,   },
   1780         {1, bcmiFtePddFldTypeLoad8,    BSD_FLEX_LOAD8_TRACKING_PARAM_3f,   },
   1781         {1, bcmiFtePddFldTypeLoad8,    BSD_FLEX_LOAD8_TRACKING_PARAM_4f,   },
   1782         {1, bcmiFtePddFldTypeLoad8,    BSD_FLEX_LOAD8_TRACKING_PARAM_5f,   },
   1783         {1, bcmiFtePddFldTypeLoad8,    BSD_FLEX_LOAD8_TRACKING_PARAM_6f,   },
   1784         {1, bcmiFtePddFldTypeLoad8,    BSD_FLEX_LOAD8_TRACKING_PARAM_7f,   },
   1785         {1, bcmiFtePddFldTypeReserved, BSD_FLEX_FLOW_STATEf,               },
   1786         {0, bcmiFtePddFldTypeReserved, INVALIDf,                            },
   1787 };
   1788 #endif
   1789 
   1790 STATIC int
   1791 bcmi_ft_export_elem_name_get(int unit,
   1792                              bcm_flowtracker_export_element_type_t info_elem,
   1793                              int *data_size,
   1794                              char *elem_name)
   1795 {
   1796     int ix;
   1797 
   1798     for (ix = 0; ix < COUNTOF(bcmi_ft_export_elements_map); ix++) {
   1799         if (bcmi_ft_export_elements_map[ix].export_element == info_elem) {
   1800             if (elem_name) {
   1801                 sal_strncpy(elem_name, bcmi_ft_export_elements_map[ix].element_name,
   1802                     BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX);
   1803             }
   1804             if (data_size) {
   1805                 *data_size = bcmi_ft_export_elements_map[ix].default_data_size;
   1806             }
   1807             break;
   1808         }
   1809     }
   1810 
   1811     if (ix == COUNTOF(bcmi_ft_export_elements_map)) {
   1812         return BCM_E_PARAM;
   1813     }
   1814 
   1815     return BCM_E_NONE;
   1816 }
   1817 
   1818 STATIC int
   1819 bcmi_fte_template_record_flow_key_populate(int unit,
   1820         bcm_flowtracker_group_t flow_group,
   1821         bcmi_fte_template_record_info_t *record)
   1822 {
   1823     int rv = BCM_E_NONE;
   1824     int idx = 0;
   1825     int key_idx = 0;
   1826     int offset = 0;
   1827     int num_key_info = 0;
   1828     int rec_total_bits = 0;
   1829     int flow_key_offset = 0;
   1830     bcmi_ft_alu_key_t *key_alu = NULL;
   1831     bcmi_ft_group_alu_info_t *key_ext_info = NULL;
   1832     bcm_flowtracker_export_element_type_t info_elem;
   1833     char info_name[BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX];
   1834 
   1835     /* Get Session Key info from FT Group */
   1836     key_ext_info = BCMI_FT_GROUP_EXT_KEY_INFO(unit, flow_group);
   1837     num_key_info = BCMI_FT_GROUP_EXT_INFO(unit, flow_group).num_key_info;
   1838 
   1839     rec_total_bits = record->total_bits;
   1840     flow_key_offset = record->flow_key_offset;
   1841 
   1842     /* 1st Byte at Flow_key_offset is skipped as it represent KeyType + Mode */
   1843     flow_key_offset += 8;
   1844 
   1845     for (key_idx = 0; key_idx < num_key_info; key_idx++) {
   1846         key_alu = &(key_ext_info->key1);
   1847         offset = flow_key_offset + key_alu->location;
   1848 
   1849         info_elem = bcmFlowtrackerExportElementTypeReserved;
   1850         rv = bcmi_ft_tracking_param_xlate(unit,
   1851                 key_ext_info->element_type1, NULL, &info_elem);
   1852         BCM_IF_ERROR_RETURN(rv);
   1853 
   1854         BCMI_FTE_RECORD_ELEM_IDX_GET(rec_total_bits, offset, key_alu->length, idx);
   1855         BCMI_FTE_RECORD_ELEM_SET(record, idx, info_elem);
   1856         BCMI_FTE_RECORD_LENGTH_SET(record, idx, key_alu->length);
   1857         BCMI_FTE_RECORD_TRACKING_PARAM_SET(record, idx, key_ext_info->element_type1);
   1858 
   1859         sal_memset(info_name, 0, sizeof(char) * BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX);
   1860         (void) bcmi_ft_export_elem_name_get(unit, info_elem, NULL, info_name);
   1861         LOG_DEBUG(BSL_LS_BCM_FLOWTRACKER, (BSL_META_U(unit,
   1862                         "[TemplateValidate]Element Record_Idx: %2d | Id: %2d (%20s) |"
   1863                         " Size: %02d\n\r"), idx, info_elem, info_name, key_alu->length));
   1864         key_ext_info++;
   1865     }
   1866 
   1867     return BCM_E_NONE;
   1868 }
   1869 
   1870 STATIC int
   1871 bcmi_fte_template_record_flow_data_polpulate(int unit,
   1872         bcm_flowtracker_group_t flow_group,
   1873         bcmi_fte_template_record_info_t *record)
   1874 {
   1875     int rv = BCM_E_NONE;
   1876     int idx = 0;
   1877     int offset = 0;
   1878     int length = 0;
   1879     int rec_total_bits = 0;
   1880     int flow_data_offset = 0;
   1881     bcm_flowtracker_check_t check_id;
   1882     bcm_flowtracker_export_element_type_t info_elem;
   1883     bcm_flowtracker_tracking_param_type_t tracking_param;
   1884     bcmi_ft_group_template_list_t *ftg_template = NULL;
   1885     char info_name[BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX];
   1886 
   1887     /* Flow Data is populated from higher bits to lower bits */
   1888     rec_total_bits = record->total_bits;
   1889     flow_data_offset = record->flow_data_offset + record->flow_data_length;
   1890 
   1891     ftg_template = ((BCMI_FT_GROUP(unit, flow_group))->template_head);
   1892     while(ftg_template) {
   1893         switch(ftg_template->info.param_type) {
   1894             case bcmiFtGroupParamTypeTracking:
   1895                 tracking_param =
   1896                     ftg_template->info.param;
   1897                 break;
   1898 
   1899             case bcmiFtGroupParamTypeTsNewLearn:
   1900                 tracking_param =
   1901                     bcmFlowtrackerTrackingParamTypeTimestampNewLearn;
   1902                 break;
   1903             case bcmiFtGroupParamTypeTsFlowStart:
   1904                 tracking_param =
   1905                     bcmFlowtrackerTrackingParamTypeTimestampFlowStart;
   1906                 break;
   1907             case bcmiFtGroupParamTypeTsFlowEnd:
   1908                 tracking_param =
   1909                     bcmFlowtrackerTrackingParamTypeTimestampFlowEnd;
   1910                 break;
   1911             case bcmiFtGroupParamTypeTsCheckEvent1:
   1912                 tracking_param =
   1913                     bcmFlowtrackerTrackingParamTypeTimestampCheckEvent1;
   1914                 break;
   1915             case bcmiFtGroupParamTypeTsCheckEvent2:
   1916                 tracking_param =
   1917                     bcmFlowtrackerTrackingParamTypeTimestampCheckEvent2;
   1918                 break;
   1919             case bcmiFtGroupParamTypeFlowchecker:
   1920                 tracking_param =
   1921                     bcmFlowtrackerTrackingParamTypeFlowtrackerCheck;
   1922                 break;
   1923 
   1924             default:
   1925                 tracking_param =
   1926                     bcmFlowtrackerTrackingParamTypeCount;
   1927                 break;
   1928         }
   1929         check_id = ftg_template->info.check_id;
   1930         info_elem = bcmFlowtrackerExportElementTypeReserved;
   1931         rv = bcmi_ft_tracking_param_xlate(unit,
   1932                    tracking_param, NULL, &info_elem);
   1933         BCM_IF_ERROR_RETURN(rv);
   1934 
   1935         length = ftg_template->info.cont_width;
   1936 
   1937         if (ftg_template->info.flags & BCMI_FT_ALU_LOAD_NEXT_ATTACH) {
   1938             /* Special case for dos attack. */
   1939             length += ftg_template->next->info.cont_width;
   1940         }
   1941 
   1942         if (ftg_template->info.data_shift != 0) {
   1943             length -= ftg_template->info.data_shift;
   1944         }
   1945         offset = ftg_template->info.cont_offset;
   1946         offset = flow_data_offset - (offset + length);
   1947 
   1948         BCMI_FTE_RECORD_ELEM_IDX_GET(rec_total_bits, offset, length, idx);
   1949         BCMI_FTE_RECORD_ELEM_SET(record, idx, info_elem);
   1950         BCMI_FTE_RECORD_LENGTH_SET(record, idx, length);
   1951         BCMI_FTE_RECORD_TRACKING_PARAM_SET(record, idx, tracking_param);
   1952         BCMI_FTE_RECORD_FLOW_CHECK_SET(record, idx, check_id);
   1953 
   1954         sal_memset(info_name, 0, sizeof(char) * BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX);
   1955         (void) bcmi_ft_export_elem_name_get(unit, info_elem, NULL, info_name);
   1956         LOG_DEBUG(BSL_LS_BCM_FLOWTRACKER, (BSL_META_U(unit,
   1957                         "[TemplateValidate]Element Record_Idx: %2d | Id: %2d (%20s) |"
   1958                         " Size: %02d (0x%x)\n\r"), idx, info_elem, info_name, length,
   1959                         check_id));
   1960 
   1961         if (ftg_template->info.flags & BCMI_FT_ALU_LOAD_NEXT_ATTACH) {
   1962             /* This is surely at least second last. so we can blindly go next.*/
   1963             ftg_template = ftg_template->next;
   1964         }
   1965 
   1966         ftg_template = ftg_template->next;
   1967     }
   1968 
   1969     return BCM_E_NONE;
   1970 }
   1971 
   1972 STATIC int
   1973 bcmi_fte_template_record_info_populate(int unit,
   1974         bcm_flowtracker_group_t flow_group,
   1975         bcmi_fte_template_record_info_t *record)
   1976 {
   1977     int rv = BCM_E_NONE;
   1978     int idx = 0;
   1979     int offset = 0;
   1980     int length = 0;
   1981     int rec_total_bits = 0;
   1982     soc_field_info_t *field_info = NULL;
   1983     soc_format_t format;
   1984     bcm_flowtracker_export_element_type_t info_elem;
   1985     char info_name[BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX];
   1986 
   1987     format = BSC_EX_EXPORT_RECORDfmt;
   1988 
   1989     /* Get record total bits, base offset of SET HEADER */
   1990     field_info = NULL;
   1991     field_info = soc_format_fieldinfo_get(unit, format, SET_HEADERf);
   1992     if (field_info != NULL) {
   1993         rec_total_bits = field_info->bp;
   1994     }
   1995     record->total_bits = rec_total_bits;
   1996     record->info_depth = (record->total_bits / 8);
   1997 
   1998     /* Allocate memory for record */
   1999     record->info = sal_alloc(record->info_depth *
   2000                 sizeof(bcmi_fte_template_record_elem_info_t),
   2001                 "Export Record element info");
   2002     if (record->info == NULL) {
   2003         return BCM_E_MEMORY;
   2004     }
   2005 
   2006     /* Initialize with 'Reserved' element */
   2007     for (idx = 0; idx < record->info_depth; idx++) {
   2008         record->info[idx].info_elem = bcmFlowtrackerExportElementTypeReserved;
   2009         record->info[idx].length = 8;
   2010         record->info[idx].check_id = 0;
   2011     }
   2012 
   2013     /* Insert hardware extracted default elements */
   2014     /* FT_INDEX */
   2015     field_info = NULL;
   2016     field_info = soc_format_fieldinfo_get(unit, format, FLOW_INDEXf);
   2017     if (field_info != NULL) {
   2018         offset = field_info->bp;
   2019         length = field_info->len;
   2020         info_elem = bcmFlowtrackerExportElementTypeReserved;
   2021         BCMI_FTE_RECORD_ELEM_IDX_GET(rec_total_bits, offset, length, idx);
   2022         BCMI_FTE_RECORD_ELEM_SET(record, idx, info_elem);
   2023         BCMI_FTE_RECORD_LENGTH_SET(record, idx, length);
   2024 
   2025         sal_memset(info_name, 0, sizeof(char) * BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX);
   2026         (void) bcmi_ft_export_elem_name_get(unit, info_elem, NULL, info_name);
   2027         LOG_DEBUG(BSL_LS_BCM_FLOWTRACKER, (BSL_META_U(unit,
   2028                         "[TemplateValidate]Element Record_Idx: %2d | Id: %2d (%20s) |"
   2029                         " Size: %02d\n\r"), idx, info_elem, info_name, length));
   2030     }
   2031 
   2032     /* FT_Group */
   2033     field_info = NULL;
   2034     field_info = soc_format_fieldinfo_get(unit, format, GROUP_IDf);
   2035     if (field_info != NULL) {
   2036         offset = field_info->bp;
   2037         length = field_info->len;
   2038         info_elem = bcmFlowtrackerExportElementTypeFlowtrackerGroup;
   2039         BCMI_FTE_RECORD_ELEM_IDX_GET(rec_total_bits, offset, length, idx);
   2040         BCMI_FTE_RECORD_ELEM_SET(record, idx, info_elem);
   2041         BCMI_FTE_RECORD_LENGTH_SET(record, idx, length);
   2042 
   2043         sal_memset(info_name, 0, sizeof(char) * BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX);
   2044         (void) bcmi_ft_export_elem_name_get(unit, info_elem, NULL, info_name);
   2045         LOG_DEBUG(BSL_LS_BCM_FLOWTRACKER, (BSL_META_U(unit,
   2046                         "[TemplateValidate]Element Record_Idx: %2d | Id: %2d (%20s) |"
   2047                         " Size: %02d\n\r"), idx, info_elem, info_name, length));
   2048     }
   2049 
   2050     /* FT_EXPORT_REASON */
   2051     field_info = NULL;
   2052     field_info = soc_format_fieldinfo_get(unit, format, EXPORT_REASONf);
   2053     if (field_info != NULL) {
   2054         offset = field_info->bp;
   2055         length = field_info->len;
   2056         info_elem = bcmFlowtrackerExportElementTypeExportReasons;
   2057         BCMI_FTE_RECORD_ELEM_IDX_GET(rec_total_bits, offset, length, idx);
   2058         BCMI_FTE_RECORD_ELEM_SET(record, idx, info_elem);
   2059         BCMI_FTE_RECORD_LENGTH_SET(record, idx, length);
   2060 
   2061         sal_memset(info_name, 0, sizeof(char) * BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX);
   2062         (void) bcmi_ft_export_elem_name_get(unit, info_elem, NULL, info_name);
   2063         LOG_DEBUG(BSL_LS_BCM_FLOWTRACKER, (BSL_META_U(unit,
   2064                         "[TemplateValidate]Element Record_Idx: %2d | Id: %2d (%20s) |"
   2065                         " Size: %02d\n\r"), idx, info_elem, info_name, length));
   2066     }
   2067 
   2068     /* EXPORT_FLAGS */
   2069     field_info = NULL;
   2070     field_info = soc_format_fieldinfo_get(unit, format, EXPORT_FLAGSf);
   2071     if (field_info != NULL) {
   2072         offset = field_info->bp;
   2073         length = field_info->len;
   2074         info_elem = bcmFlowtrackerExportElementTypeExportFlags;
   2075         BCMI_FTE_RECORD_ELEM_IDX_GET(rec_total_bits, offset, length, idx);
   2076         BCMI_FTE_RECORD_ELEM_SET(record, idx, info_elem);
   2077         BCMI_FTE_RECORD_LENGTH_SET(record, idx, length);
   2078 
   2079         sal_memset(info_name, 0, sizeof(char) * BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX);
   2080         (void) bcmi_ft_export_elem_name_get(unit, info_elem, NULL, info_name);
   2081         LOG_DEBUG(BSL_LS_BCM_FLOWTRACKER, (BSL_META_U(unit,
   2082                         "[TemplateValidate]Element Record_Idx: %2d | Id: %2d (%20s) |"
   2083                         " Size: %02d\n\r"), idx, info_elem, info_name, length));
   2084     }
   2085 
   2086     /* TIMESTAMP */
   2087     field_info = NULL;
   2088     field_info = soc_format_fieldinfo_get(unit, format, TIMESTAMPf);
   2089     if (field_info != NULL) {
   2090         offset = field_info->bp;
   2091         length = field_info->len;
   2092         info_elem = bcmFlowtrackerExportElementTypeReserved;
   2093         BCMI_FTE_RECORD_ELEM_IDX_GET(rec_total_bits, offset, length, idx);
   2094         BCMI_FTE_RECORD_ELEM_SET(record, idx, info_elem);
   2095         BCMI_FTE_RECORD_LENGTH_SET(record, idx, length);
   2096 
   2097         sal_memset(info_name, 0, sizeof(char) * BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX);
   2098         (void) bcmi_ft_export_elem_name_get(unit, info_elem, NULL, info_name);
   2099         LOG_DEBUG(BSL_LS_BCM_FLOWTRACKER, (BSL_META_U(unit,
   2100                         "[TemplateValidate]Element Record_Idx: %2d | Id: %2d (%20s) |"
   2101                         " Size: %02d\n\r"), idx, info_elem, info_name, length));
   2102     }
   2103 
   2104     /* FLOW_KEY */
   2105     field_info = NULL;
   2106     field_info = soc_format_fieldinfo_get(unit, format, FLOW_KEYf);
   2107     if (field_info != NULL) {
   2108         record->flow_key_offset = field_info->bp;
   2109         record->flow_key_length = field_info->len;
   2110     }
   2111     rv = bcmi_fte_template_record_flow_key_populate(unit, flow_group, record);
   2112     if(BCM_FAILURE(rv)) {
   2113         goto cleanup;
   2114     }
   2115 
   2116     /* FLOW_DATA */
   2117     field_info = NULL;
   2118     field_info = soc_format_fieldinfo_get(unit, format, FLOW_DATAf);
   2119     if (field_info != NULL) {
   2120         record->flow_data_offset = field_info->bp;
   2121         record->flow_data_length = field_info->len;
   2122     }
   2123     rv = bcmi_fte_template_record_flow_data_polpulate(unit, flow_group, record);
   2124 
   2125 cleanup:
   2126 
   2127     if (BCM_FAILURE(rv)) {
   2128         if (record->info != NULL) {
   2129             sal_free(record->info);
   2130             record->info = NULL;
   2131         }
   2132     }
   2133 
   2134     return rv;
   2135 }
   2136 
   2137 /*
   2138  * Function:
   2139  *     bcmi_ft_export_elements_check_search
   2140  * Purpose:
   2141  *     Search flowcheck in export elements list.
   2142  * Parameters:
   2143  *     unit - (IN) BCM device id
   2144  *     check_id - (IN) Flowtracker Check
   2145  *     list - (IN) list of export elements.
   2146  *     count - (IN) number of export elements.
   2147  *
   2148  * Returns:
   2149  *     TRUE if found FALSE otherwise
   2150  */
   2151 int
   2152 bcmi_ft_export_elements_check_search(
   2153     int unit,
   2154     bcm_flowtracker_check_t check_id,
   2155     void *list,
   2156     int count)
   2157 {
   2158     int idx = 0;
   2159     bcm_flowtracker_export_element_info_t *export_elements = NULL;
   2160 
   2161     if ((list == NULL) || (count == 0)) {
   2162         return FALSE;
   2163     }
   2164     export_elements = (bcm_flowtracker_export_element_info_t *) list;
   2165 
   2166     for (idx = 0; idx < count; idx++) {
   2167         if ((export_elements[idx].element ==
   2168                 bcmFlowtrackerExportElementTypeFlowtrackerCheck) &&
   2169             (export_elements[idx].check_id == check_id)) {
   2170             return TRUE;
   2171         }
   2172     }
   2173     return FALSE;
   2174 }
   2175 
   2176 /*
   2177  * Function:
   2178  *      bcmi_fte_template_create_validate
   2179  * Purpose:
   2180  *      Validate the template and return the list supported by the
   2181  *      device.
   2182  * Parameters:
   2183  *      unit - (IN) Unit number.
   2184  *      flow_group_id - (IN) Flowtracker flow group software ID.
   2185  *      num_in_export_elements - (IN) Number of export elements intended in the tempate.
   2186  *      in_export_elements - (IN) List of export elements intended to be in the template.
   2187  *      num_out_export_elements - (IN/OUT) Number of export elements in the supportable tempate.
   2188  *      out_export_elements - (OUT) List of export elements in the template supportable by hardware.
   2189  * Returns:
   2190  *      BCM_E_xxx
   2191  * Notes:
   2192  */
   2193 STATIC int
   2194 bcmi_fte_template_create_validate(
   2195     int unit,
   2196     bcm_flowtracker_group_t flow_group_id,
   2197     int num_in_export_elements,
   2198     bcm_flowtracker_export_element_info_t *in_export_elements,
   2199     int num_out_export_elements,
   2200     bcm_flowtracker_export_element_info_t *out_export_elements,
   2201     int *actual_out_export_elements)
   2202 {
   2203     int rv = BCM_E_NONE;
   2204     int ix_in = 0, ix_out = 0, in_c = 0;
   2205     int idx = 0;
   2206     int info_size = 0;
   2207     char info_name[BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX];
   2208     bcm_flowtracker_check_t check_id;
   2209     bcmi_fte_template_record_info_t record;
   2210     bcm_flowtracker_export_element_type_t info_elem;
   2211     bcm_flowtracker_export_element_info_t *info_elem_in = NULL;
   2212     bcm_flowtracker_export_element_info_t *info_elem_out = NULL;
   2213 
   2214     if ((num_in_export_elements <= 0) || (in_export_elements == NULL)) {
   2215         return BCM_E_PARAM;
   2216     }
   2217     if ((num_out_export_elements > 0) && (out_export_elements == NULL)) {
   2218         return BCM_E_PARAM;
   2219     }
   2220 
   2221     /* Validate export element list of the group */
   2222     rv = bcmi_ft_group_export_checks_validate(unit,
   2223             flow_group_id, num_in_export_elements, in_export_elements);
   2224     BCM_IF_ERROR_RETURN(rv);
   2225 
   2226     sal_memset(&record, 0, sizeof(bcmi_fte_template_record_info_t));
   2227     rv = bcmi_fte_template_record_info_populate(unit, flow_group_id, &record);
   2228     BCM_IF_ERROR_RETURN(rv);
   2229 
   2230     if (record.info_depth == 0) {
   2231         /* Faied to populate template info */
   2232         return BCM_E_INTERNAL;
   2233     }
   2234 
   2235     /* Mark info elements not requested by user as 'Reserved' */
   2236     for (idx = 0; idx < record.info_depth; idx++) {
   2237 
   2238         if (record.info[idx].info_elem !=
   2239                 bcmFlowtrackerExportElementTypeReserved) {
   2240             for (ix_in = 0; ix_in < num_in_export_elements; ix_in++) {
   2241                 info_elem_in = &(in_export_elements[ix_in]);
   2242 
   2243                 /* If non-primary check, skip */
   2244                 if (info_elem_in->element ==
   2245                         bcmFlowtrackerExportElementTypeFlowtrackerCheck) {
   2246                     check_id = info_elem_in->check_id;
   2247 
   2248                     if (!BCMI_FT_IDX_IS_PRIMARY_CHECK(check_id)) {
   2249                         in_c++;
   2250                         break;
   2251                     }
   2252                 }
   2253 
   2254                 if ((record.info[idx].info_elem == info_elem_in->element) &&
   2255                         (record.info[idx].check_id == info_elem_in->check_id)) {
   2256                     in_c++;
   2257                     break;
   2258                 }
   2259             }
   2260             if (ix_in == num_in_export_elements) {
   2261                 record.info[idx].info_elem =
   2262                     bcmFlowtrackerExportElementTypeReserved;
   2263                 record.info[idx].check_id = 0;
   2264             }
   2265         }
   2266     }
   2267 
   2268     idx = 0;
   2269     ix_out = 0;
   2270     info_elem = bcmFlowtrackerExportElementTypeReserved;
   2271 
   2272     /* Form out export elements list */
   2273     while(idx < record.info_depth) {
   2274 
   2275         check_id = 0;
   2276         info_size = 0;
   2277         info_elem = record.info[idx].info_elem;
   2278 
   2279         if (info_elem == bcmFlowtrackerExportElementTypeReserved) {
   2280             info_size = record.info[idx].length;
   2281 
   2282             /* Add up all adjacent 'Reserved' element */
   2283             while(((idx + 1) < record.info_depth) &&
   2284                     (record.info[idx + 1].info_elem ==
   2285                      bcmFlowtrackerExportElementTypeReserved)) {
   2286                 info_size += record.info[idx + 1].length;
   2287                 idx++;
   2288             }
   2289         } else {
   2290             info_size = record.info[idx].length;
   2291             check_id = record.info[idx].check_id;
   2292 
   2293             /* Skip next $info_size 'Reserved' elements */
   2294             idx += ((info_size / 8) - 1);
   2295         }
   2296         info_size = info_size / 8;
   2297 
   2298         /* Dump FT export element list */
   2299         (void) bcmi_ft_export_elem_name_get(unit, info_elem, NULL, info_name);
   2300         LOG_INFO(BSL_LS_BCM_FLOWTRACKER, (BSL_META_U(unit,
   2301                         "[TemplateValidate]Element Id: %2d (%20s)"
   2302                         " | Size: %02d (0x%x)\n\r"), info_elem, info_name,
   2303                     info_size, check_id));
   2304 
   2305         info_elem_out = NULL;
   2306         if (ix_out < num_out_export_elements) {
   2307             info_elem_out = &(out_export_elements[ix_out]);
   2308 
   2309             info_elem_out->element = info_elem;
   2310             info_elem_out->data_size = info_size;
   2311             info_elem_out->check_id = check_id;
   2312         }
   2313         idx++;
   2314         ix_out++;
   2315      }
   2316 
   2317      *actual_out_export_elements = ix_out;
   2318 
   2319      if (in_c < num_in_export_elements) {
   2320          /* Export element list contains extra elements */
   2321          LOG_ERROR(BSL_LS_BCM_FLOWTRACKER, (BSL_META_U(unit,
   2322                          "In-Export Elements array contain"
   2323                          " additional elements which are not present"
   2324                          " in FT Group tracking list.\n\r")));
   2325          rv = BCM_E_CONFIG;
   2326      } else if ((num_out_export_elements != 0) &&
   2327             (num_out_export_elements < ix_out)) {
   2328 
   2329          LOG_ERROR(BSL_LS_BCM_FLOWTRACKER, (BSL_META_U(unit,
   2330                          "Size of Out-Export Elements array is insufficient."
   2331                          " Required=(%d) but given Size=(%d)\n\r"),
   2332                      ix_out, num_out_export_elements));
   2333          rv = BCM_E_PARAM;
   2334      }
   2335 
   2336     /* Cleanup table */
   2337     if (record.info != NULL) {
   2338         sal_free(record.info);
   2339     }
   2340 
   2341     return rv;
   2342 }
   2343 
   2344 /*
   2345  * Function:
   2346  *      bcmi_ft_export_template_validate
   2347  * Purpose:
   2348  *      Validate the template and return the list supported by the
   2349  *      device.
   2350  * Parameters:
   2351  *      unit - (IN) Unit number.
   2352  *      flow_group_id - (IN) Flowtracker flow group software ID.
   2353  *      num_in_export_elements - (IN) Number of export elements intended in the tempate.
   2354  *      in_export_elements - (IN) List of export elements intended to be in the template.
   2355  *      num_out_export_elements - (IN/OUT) Number of export elements in the supportable tempate.
   2356  *      out_export_elements - (OUT) List of export elements in the template supportable by hardware.
   2357  * Returns:
   2358  *      BCM_E_xxx
   2359  * Notes:
   2360  */
   2361 int
   2362 bcmi_ft_export_template_validate(
   2363     int unit,
   2364     bcm_flowtracker_group_t flow_group_id,
   2365     int num_in_export_elements,
   2366     bcm_flowtracker_export_element_info_t *in_export_elements,
   2367     int num_out_export_elements,
   2368     bcm_flowtracker_export_element_info_t *out_export_elements,
   2369     int *actual_out_export_elements)
   2370 {
   2371     int rv = BCM_E_NONE;
   2372     int ft_group_installed = FALSE;
   2373 
   2374     if ((num_in_export_elements <= 0) || (in_export_elements == NULL)) {
   2375         return BCM_E_PARAM;
   2376     }
   2377     if ((num_out_export_elements > 0) && (out_export_elements == NULL)) {
   2378         return BCM_E_PARAM;
   2379     }
   2380 
   2381     /* If FT Group is not created, fail */
   2382     rv = bcmi_ft_group_is_invalid(unit, flow_group_id);
   2383     BCM_IF_ERROR_RETURN(rv);
   2384 
   2385     /* If FT Group is installed, fail */
   2386     if (BCMI_FT_GROUP_IS_BUSY(unit, flow_group_id)) {
   2387         return BCM_E_BUSY;
   2388     }
   2389 
   2390     /* If FT Group is validated, uninstall */
   2391     if (BCMI_FT_GROUP_IS_VALIDATED(unit, flow_group_id)) {
   2392         rv = bcmi_esw_ft_group_hw_uninstall(unit, flow_group_id);
   2393         BCM_IF_ERROR_RETURN(rv);
   2394     }
   2395 
   2396     /* Extract FT Group tracking params and flow checks */
   2397     rv = _bcm_field_ft_group_tracking_info_process(unit, flow_group_id, 1);
   2398 
   2399     /* Validate and Install FT Group to Hw */
   2400     if (BCM_SUCCESS(rv)) {
   2401         rv = bcmi_esw_ft_group_hw_install(unit, flow_group_id);
   2402     }
   2403 
   2404     /* Validate and Create Export template */
   2405     if (BCM_SUCCESS(rv)) {
   2406         ft_group_installed = TRUE;
   2407         rv = bcmi_fte_template_create_validate(unit,
   2408                 flow_group_id, num_in_export_elements, in_export_elements,
   2409                 num_out_export_elements, out_export_elements,
   2410                 actual_out_export_elements);
   2411     }
   2412 
   2413     /* Cleanup in case of failure */
   2414     if (BCM_FAILURE(rv)) {
   2415         /* Uninstalled FT Group */
   2416         if (ft_group_installed == TRUE) {
   2417             (void) bcmi_esw_ft_group_hw_uninstall(unit, flow_group_id);
   2418         }
   2419 
   2420         /* Cleanup FT Group Extraction information */
   2421         (void) _bcm_field_ft_group_extraction_clear(unit, flow_group_id);
   2422     }
   2423 
   2424     return rv;
   2425 }
   2426 
   2427 /*
   2428  * Function:
   2429  *     bcmi_ft_template_create
   2430  * Purpose:
   2431  *     Create flowtracker export template.
   2432  * Description :
   2433  *     Routine to create a flowtracker template
   2434  * Parameters:
   2435  *     unit - (IN) BCM device id
   2436  *     options - (IN) options for template creation
   2437  *     template_id   - (OUT) FT template id.
   2438  *     set_id - (IN) IPFIX template set id
   2439  *     num_elements - (IN) Number of information elements.
   2440  *     list_of_export_elements - (IN) List of IPFIX information elems.
   2441  *
   2442  * Returns:
   2443  *     BCM_E_XXX
   2444  */
   2445 int
   2446 bcmi_ft_template_create(
   2447     int unit,
   2448     uint32 options,
   2449     bcm_flowtracker_export_template_t *template_id,
   2450     uint16 set_id,
   2451     int num_elements,
   2452     bcm_flowtracker_export_element_info_t *list_of_export_elements)
   2453 {
   2454     int rv;
   2455     bcm_flowtracker_export_template_t index = 0;
   2456     bcmi_ft_template_info_t template_info;
   2457 
   2458     /*
   2459      * Validate info elems
   2460      */
   2461     rv = bcmi_ft_template_validate(unit,
   2462                                    num_elements,
   2463                                    list_of_export_elements);
   2464     BCM_IF_ERROR_RETURN(rv);
   2465 
   2466 
   2467     /* If WITH_ID, reserve the ID */
   2468     if (options & BCM_FLOWTRACKER_EXPORT_TEMPLATE_WITH_ID) {
   2469         index = *template_id;
   2470 
   2471         rv = bcmi_ft_template_id_alloc(unit, FALSE, &index);
   2472         BCM_IF_ERROR_RETURN(rv);
   2473 
   2474     } else {
   2475 
   2476         rv = bcmi_ft_template_id_alloc(unit, TRUE, &index);
   2477         BCM_IF_ERROR_RETURN(rv);
   2478     }
   2479 
   2480     /* Init template_info. */
   2481     sal_memset(&template_info, 0, sizeof(bcmi_ft_template_info_t));
   2482 
   2483     template_info.template_id = index;
   2484     template_info.set_id = set_id;
   2485     template_info.num_elements = num_elements;
   2486 
   2487     sal_memcpy(template_info.export_elements,
   2488                list_of_export_elements,
   2489                (num_elements * sizeof(bcm_flowtracker_export_element_info_t)));
   2490 
   2491     sal_memcpy(BCMI_FT_TEMPLATE_INFO(unit, index),
   2492                &template_info, sizeof(template_info));
   2493 
   2494     *template_id = index;
   2495 
   2496     return rv;
   2497 }
   2498 
   2499 /*
   2500  * Function:
   2501  *     bcmi_ft_template_get
   2502  * Purpose:
   2503  *     Ftech flowtracker export template.
   2504  * Description :
   2505  *     Routine to get flowtracker template info.
   2506  * Parameters:
   2507  *     unit - (IN) BCM device id
   2508  *     template_id   - (IN) FT template id.
   2509  *     *set_id - (OUT) IPFIX template set id
   2510  *     max_size - (IN) Max num of elements
   2511  *     list_of_export_elements - (OUT) List of IPFIX information elems.
   2512  *     num_elements - (OUT) Actual Number of information elements.
   2513  *
   2514  * Returns:
   2515  *     BCM_E_XXX
   2516  */
   2517 int
   2518 bcmi_ft_template_get(
   2519     int unit,
   2520     bcm_flowtracker_export_template_t template_id,
   2521     uint16 *set_id,
   2522     int max_elems,
   2523     bcm_flowtracker_export_element_info_t *list_of_elems,
   2524     int *num_elems)
   2525 {
   2526     int idx;
   2527     bcm_flowtracker_export_element_info_t *elem;
   2528     bcmi_ft_template_info_t *template_info;
   2529 
   2530     if (max_elems != 0 && list_of_elems == NULL) {
   2531         return BCM_E_PARAM;
   2532     }
   2533     if (num_elems == NULL) {
   2534         return BCM_E_PARAM;
   2535     }
   2536 
   2537     if ((template_id > BCMI_FT_EXPORT_INFO(unit)->max_templates) ||
   2538         (template_id <= BCMI_FT_TEMPLATE_ID_INVALID)) {
   2539         return BCM_E_PARAM;
   2540     }
   2541 
   2542     if (!SHR_BITGET(BCMI_FT_TEMPLATE_BITMAP(unit), template_id)) {
   2543         return BCM_E_NOT_FOUND;
   2544     }
   2545 
   2546     template_info = BCMI_FT_TEMPLATE_INFO(unit, template_id);
   2547     *set_id = template_info->set_id;
   2548     *num_elems = template_info->num_elements;
   2549 
   2550     for (idx = 0; idx < max_elems; idx++) {
   2551         elem = &(list_of_elems[idx]);
   2552         sal_memcpy(elem,
   2553                    &(template_info->export_elements[idx]),
   2554                    sizeof(*elem));
   2555     }
   2556 
   2557     if ((max_elems != 0) && (max_elems <= *num_elems)) {
   2558         *num_elems = max_elems;
   2559     }
   2560 
   2561     return BCM_E_NONE;
   2562 }
   2563 
   2564 /*
   2565  * Function:
   2566  *     bcmi_ft_template_destroy
   2567  * Purpose:
   2568  *     Destroy flowtracker export template.
   2569  * Description :
   2570  *     Routine to destroy a flowtracker template
   2571  * Parameters:
   2572  *     unit - (IN) BCM device id
   2573  *     id   - (OUT) FT template id.
   2574  *
   2575  * Returns:
   2576  *     BCM_E_XXX
   2577  */
   2578 int
   2579 bcmi_ft_template_destroy(
   2580     int unit,
   2581     bcm_flowtracker_export_template_t template_id)
   2582 {
   2583     bcmi_ft_template_info_t *template_info;
   2584 
   2585     if ((template_id > BCMI_FT_EXPORT_INFO(unit)->max_templates) ||
   2586         (template_id <= BCMI_FT_TEMPLATE_ID_INVALID)) {
   2587         return BCM_E_PARAM;
   2588     }
   2589 
   2590     if (!SHR_BITGET(BCMI_FT_TEMPLATE_BITMAP(unit), template_id)) {
   2591         return BCM_E_NOT_FOUND;
   2592     }
   2593 
   2594     template_info = BCMI_FT_TEMPLATE_INFO(unit, template_id);
   2595 
   2596     /* Allow destroying template only if it is detached from all groups. */
   2597     if (template_info->in_use != 0) {
   2598         return BCM_E_BUSY;
   2599     }
   2600 
   2601     sal_memset(template_info->export_elements, 0,
   2602                (template_info->num_elements *
   2603                 sizeof(bcm_flowtracker_export_element_info_t)));
   2604 
   2605     template_info->template_id = template_id;
   2606     template_info->set_id = 0;
   2607     template_info->num_elements = 0;
   2608 
   2609     /* Reset bit in template bitmap */
   2610     SHR_BITCLR(BCMI_FT_TEMPLATE_BITMAP(unit), template_id);
   2611 
   2612     return BCM_E_NONE;
   2613 }
   2614 
   2615 /*
   2616  * Function:
   2617  *     bcmi_ft_flow_group_collector_add
   2618  * Purpose:
   2619  *     Attach a collector a flow group.
   2620  * Description :
   2621  *     Routine to associate a collector to an flowtracker group.
   2622  * Parameters:
   2623  *     unit - (IN) BCM device id
   2624  *     group_id- (IN) FT group Id.
   2625  *     coll_hw_id   - (OUT) FT Collector Id.
   2626  *     template_id - (IN) IPFIX template Id.
   2627  *
   2628  * Returns:
   2629  *     BCM_E_XXX
   2630  */
   2631 int
   2632 bcmi_ft_flow_group_collector_add(
   2633     int unit,
   2634     bcm_flowtracker_group_t flow_group_id,
   2635     bcm_flowtracker_collector_t coll_hw_id,
   2636     bcm_flowtracker_export_template_t template_id)
   2637 {
   2638     uint16 set_id;
   2639     bcmi_ft_collector_info_t *ft_coll_info;
   2640 
   2641     /*
   2642      * Validate group id
   2643      */
   2644     if (bcmi_ft_group_is_invalid(unit, flow_group_id)) {
   2645         return BCM_E_NOT_FOUND;
   2646     }
   2647 
   2648     /* Validate Template Id. */
   2649     if ((template_id > BCMI_FT_EXPORT_INFO(unit)->max_templates) ||
   2650         (template_id <= BCMI_FT_TEMPLATE_ID_INVALID)) {
   2651         return BCM_E_PARAM;
   2652     }
   2653 
   2654     if (!SHR_BITGET(BCMI_FT_TEMPLATE_BITMAP(unit), template_id)) {
   2655         return BCM_E_NOT_FOUND;
   2656     }
   2657 
   2658     if ((coll_hw_id <= BCMI_FT_COLLECTOR_ID_INVALID) ||
   2659         (coll_hw_id >= BCMI_FT_MAX_COLLECTORS)) {
   2660         return BCM_E_PARAM;
   2661     }
   2662 
   2663     ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, coll_hw_id);
   2664 
   2665     if (ft_coll_info->coll_hw_id == BCMI_FT_COLLECTOR_ID_INVALID) {
   2666         return BCM_E_NOT_FOUND;
   2667     }
   2668 
   2669     if (BCMI_FT_TEMPLATE_ID_INVALID !=
   2670         BCMI_FT_GROUP(unit, flow_group_id)->template_id) {
   2671         return BCM_E_BUSY;
   2672     }
   2673 
   2674     if (BCMI_FT_COLLECTOR_ID_INVALID !=
   2675         BCMI_FT_GROUP(unit, flow_group_id)->collector_id) {
   2676         return BCM_E_BUSY;
   2677     }
   2678 
   2679     /* Update Group table with collector Id. */
   2680     soc_mem_field32_modify(unit, BSC_KG_GROUP_TABLEm, flow_group_id,
   2681                            COLLECTOR_IDf, coll_hw_id);
   2682     ft_coll_info->in_use += 1;
   2683     BCMI_FT_GROUP(unit, flow_group_id)->collector_id = coll_hw_id;
   2684 
   2685     /* Update Group table with template SET Id. */
   2686     set_id = BCMI_FT_TEMPLATE_INFO(unit, template_id)->set_id;
   2687     soc_mem_field32_modify(unit, BSC_KG_GROUP_TABLEm, flow_group_id,
   2688                            SET_IDf, set_id);
   2689     BCMI_FT_TEMPLATE_INFO(unit, template_id)->in_use += 1;
   2690     BCMI_FT_GROUP(unit, flow_group_id)->template_id = template_id;
   2691 
   2692 
   2693     return BCM_E_NONE;
   2694 }
   2695 
   2696 /*
   2697  * Function:
   2698  *     bcmi_ft_flow_group_collector_delete_check
   2699  * Purpose:
   2700  *     Check the conditions that needs to be satisfied
   2701  *     before a collector is removed from Flowtracker_group.
   2702  * Parameters:
   2703  *     unit         - (IN) BCM device id
   2704  *     id           - (IN) FT group Id.
   2705  *     coll_hw_id   - (IN) FT Collector Id.
   2706  *
   2707  * Returns:
   2708  *     BCM_E_XXX
   2709  */
   2710 int
   2711 bcmi_ft_flow_group_collector_delete_check(
   2712     int unit,
   2713     bcm_flowtracker_group_t id,
   2714     bcm_flowtracker_collector_t coll_hw_id)
   2715 {
   2716     int rv;
   2717     int ft_enable;
   2718     int is_busy;
   2719     int user_entry;
   2720     uint32 flow_limit;
   2721     uint64 age_out_count;
   2722     uint64 flow_learnt_count;
   2723 
   2724     user_entry = (BCMI_FT_GROUP(unit, id)->flags
   2725                      & BCM_FLOWTRACKER_GROUP_USER_ENTRIES_ONLY);
   2726     is_busy = BCMI_FT_GROUP_IS_BUSY(unit, id);
   2727     ft_enable = BCMI_FT_GROUP_FTFP_DATA(unit, id).flowtrack;
   2728     rv = bcmi_ft_group_flow_limit_get(unit, id, &flow_limit);
   2729     if (rv != BCM_E_NONE) {
   2730         flow_limit = 0;
   2731     }
   2732 
   2733     /*
   2734      * For sw managed groups, is_busy and ft_enable are valid, flow_limit is
   2735      * not significant. Where as for hw managed groups, is_busy,ft_enable and
   2736      * flow_limit are verified.
   2737      */
   2738     if (((user_entry == TRUE) && (is_busy == TRUE) && (ft_enable == TRUE)) ||
   2739         ((is_busy == TRUE) && (ft_enable == TRUE) && (flow_limit != 0))) {
   2740         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   2741                 (BSL_META_U(unit,
   2742                       "FLOWTRACKER(unit %d) Error: FT Group is installed in"
   2743                       " Field Entry or Flowtracking is enabled\r\n"), unit));
   2744         return BCM_E_BUSY;
   2745     }
   2746 
   2747     if (SAL_BOOT_BCMSIM) {
   2748         return BCM_E_NONE;
   2749     }
   2750 
   2751     COMPILER_64_SET(age_out_count, 0, 0);
   2752     COMPILER_64_SET(flow_learnt_count, 0, 0);
   2753     BCM_IF_ERROR_RETURN(soc_counter_sync_get(unit, REG_PORT_ANY,
   2754         SOC_COUNTER_NON_DMA_FT_GROUP_FLOW_AGE_OUT_CNT, id, &age_out_count));
   2755 
   2756     BCM_IF_ERROR_RETURN(soc_counter_sync_get(unit, REG_PORT_ANY,
   2757         SOC_COUNTER_NON_DMA_FT_GROUP_FLOW_LEARNT_CNT, id, &flow_learnt_count));
   2758 
   2759     if (COMPILER_64_LT(age_out_count, flow_learnt_count)) {
   2760         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   2761                 (BSL_META_U(unit,
   2762                       "FLOWTRACKER(unit %d) Error: FT Group"
   2763                       " has active flows\r\n"), unit));
   2764         return BCM_E_BUSY;
   2765     }
   2766 
   2767     return BCM_E_NONE;
   2768 }
   2769 
   2770 /*
   2771  * Function:
   2772  *     bcmi_ft_flow_group_collector_delete
   2773  * Purpose:
   2774  *     Detach a collector a flow group.
   2775  * Description :
   2776  *     Routine to dissociate a collector to an flowtracker group.
   2777  * Parameters:
   2778  *     unit - (IN) BCM device id
   2779  *     group_id- (IN) FT group Id.
   2780  *     coll_hw_id   - (OUT) FT Collector Id.
   2781  *     template_id - (IN) IPFIX template Id.
   2782  *
   2783  * Returns:
   2784  *     BCM_E_XXX
   2785  */
   2786 int
   2787 bcmi_ft_flow_group_collector_delete(
   2788     int unit,
   2789     bcm_flowtracker_group_t flow_group_id,
   2790     bcm_flowtracker_collector_t coll_hw_id,
   2791     bcm_flowtracker_export_template_t template_id)
   2792 {
   2793     bcmi_ft_collector_info_t *ft_coll_info;
   2794 
   2795     /*
   2796      * Validate group id
   2797      */
   2798     if (bcmi_ft_group_is_invalid(unit, flow_group_id)) {
   2799         return BCM_E_NOT_FOUND;
   2800     }
   2801 
   2802     /* Validate Template Id. */
   2803     if ((template_id > BCMI_FT_EXPORT_INFO(unit)->max_templates) ||
   2804         (template_id <= BCMI_FT_TEMPLATE_ID_INVALID)) {
   2805         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   2806                 (BSL_META_U(unit,
   2807                       "FLOWTRACKER(unit %d) Error: Incorrect"
   2808                       " template Id\r\n"), unit));
   2809         return BCM_E_PARAM;
   2810     }
   2811 
   2812     if (!SHR_BITGET(BCMI_FT_TEMPLATE_BITMAP(unit), template_id)) {
   2813         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   2814                 (BSL_META_U(unit,
   2815                       "FLOWTRACKER(unit %d) Error: template Id"
   2816                       " not found\r\n"), unit));
   2817         return BCM_E_NOT_FOUND;
   2818     }
   2819 
   2820     if ((coll_hw_id <= BCMI_FT_COLLECTOR_ID_INVALID) ||
   2821         (coll_hw_id >= BCMI_FT_MAX_COLLECTORS)) {
   2822         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   2823                 (BSL_META_U(unit,
   2824                       "FLOWTRACKER(unit %d) Error: Incorrect"
   2825                       " collector\r\n"), unit));
   2826         return BCM_E_PARAM;
   2827     }
   2828 
   2829     ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, coll_hw_id);
   2830 
   2831     if (ft_coll_info->coll_hw_id == BCMI_FT_COLLECTOR_ID_INVALID) {
   2832         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   2833                 (BSL_META_U(unit,
   2834                       "FLOWTRACKER(unit %d) Error: Collector"
   2835                       " is not associated with Flowtracker Group \r\n"), unit));
   2836         return BCM_E_NOT_FOUND;
   2837     }
   2838 
   2839     if (template_id !=
   2840         BCMI_FT_GROUP(unit, flow_group_id)->template_id) {
   2841         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   2842                 (BSL_META_U(unit,
   2843                       "FLOWTRACKER(unit %d) Error: Template"
   2844                       " is not associated with Flowtracker Group\r\n"), unit));
   2845         return BCM_E_NOT_FOUND;
   2846     }
   2847 
   2848     if (coll_hw_id !=
   2849         BCMI_FT_GROUP(unit, flow_group_id)->collector_id) {
   2850         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   2851                 (BSL_META_U(unit,
   2852                       "FLOWTRACKER(unit %d) Error: Collector"
   2853                       " is not associated with Flowtracker Group \r\n"), unit));
   2854         return BCM_E_NOT_FOUND;
   2855     }
   2856 
   2857     /* Update Group table with collector Id. */
   2858     BCM_IF_ERROR_RETURN(bcmi_ft_flow_group_collector_delete_check(unit,
   2859                 flow_group_id, coll_hw_id));
   2860 
   2861     soc_mem_field32_modify(unit, BSC_KG_GROUP_TABLEm, flow_group_id,
   2862                            COLLECTOR_IDf, 0);
   2863     ft_coll_info->in_use -= 1;
   2864     BCMI_FT_GROUP(unit, flow_group_id)->collector_id = BCMI_FT_COLLECTOR_ID_INVALID;
   2865 
   2866     /* Update Group table with template SET Id. */
   2867     soc_mem_field32_modify(unit, BSC_KG_GROUP_TABLEm, flow_group_id,
   2868                            SET_IDf, 0);
   2869     BCMI_FT_TEMPLATE_INFO(unit, template_id)->in_use -= 1;
   2870     BCMI_FT_GROUP(unit, flow_group_id)->template_id = BCMI_FT_TEMPLATE_ID_INVALID;
   2871 
   2872     return BCM_E_NONE;
   2873 }
   2874 
   2875 
   2876 /*
   2877  * Function:
   2878  *     bcmi_ft_flow_group_collector_get_all
   2879  * Purpose:
   2880  *     Get collector attached to a flow group.
   2881  * Description :
   2882  *     Routine to fetch collector and template id
   2883  *     associated a flowtracker group.
   2884  * Parameters:
   2885  *     unit                 - (IN)  BCM device id
   2886  *     group_id             - (IN)  FT group Id.
   2887  *     max_list_size        - (IN)  max list of collectors
   2888  *     list_of_collectors   - (OUT) FT Collector Id list.
   2889  *     list_of_templates    - (OUT) FT Template Id list.
   2890  *     list_size            - (IN)  Actual list size.
   2891  *
   2892  * Returns:
   2893  *     BCM_E_XXX
   2894  */
   2895 int
   2896 bcmi_ft_flow_group_collector_get_all(
   2897     int unit,
   2898     bcm_flowtracker_group_t flow_group_id,
   2899     int max_list_size,
   2900     bcm_flowtracker_collector_t *list_of_collectors,
   2901     bcm_flowtracker_export_template_t *list_of_templates,
   2902     int *list_size)
   2903 {
   2904 
   2905     if (list_size == NULL) {
   2906         return BCM_E_PARAM;
   2907     }
   2908 
   2909     /*
   2910      * Validate group id
   2911      */
   2912     if (bcmi_ft_group_is_invalid(unit, flow_group_id)) {
   2913         return BCM_E_NOT_FOUND;
   2914     }
   2915 
   2916     /* HX5 Hardware supports only one collector id and templat per group */
   2917     if (max_list_size > 0) {
   2918         if (list_of_collectors != NULL) {
   2919             list_of_collectors[0] = BCMI_FT_GROUP(unit, flow_group_id)->collector_id;
   2920         }
   2921 
   2922         if (list_of_templates != NULL) {
   2923             list_of_templates[0] = BCMI_FT_GROUP(unit, flow_group_id)->template_id;
   2924         }
   2925     }
   2926 
   2927     *list_size = 1;
   2928 
   2929     return BCM_E_NONE;
   2930 }
   2931 
   2932 /*
   2933  * Function:
   2934  *      bcmi_ft_group_collector_attach
   2935  * Purpose:
   2936  *      Associate flow group to a collector with an export template.
   2937  * Parameters:
   2938  *      unit            - (IN)  BCM device number
   2939  *      flow_group_id   - (IN)  Flow group Id
   2940  *      collector_id    - (IN)  Collector Id
   2941  *      template_id     - (IN)  Template Id
   2942  * Returns:
   2943  *      BCM_E_XXX   - BCM error code.
   2944  */
   2945 int bcmi_ft_group_collector_attach(
   2946         int unit,
   2947         bcm_flowtracker_group_t flow_group_id,
   2948         bcm_collector_t collector_id,
   2949         int export_profile_id,
   2950         bcm_flowtracker_export_template_t template_id)
   2951 {
   2952     int rv;
   2953     bcmi_ft_collector_info_t *ft_coll_info;
   2954     bcm_flowtracker_collector_t ix, first_free;
   2955 
   2956     bcm_flowtracker_collector_info_t collector_info;
   2957     bcm_collector_export_profile_t export_profile_info;
   2958     bcm_collector_info_t cmn_collector_info;
   2959 
   2960     first_free = BCMI_FT_COLLECTOR_ID_INVALID;
   2961 
   2962     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_collectors; ix++) {
   2963         ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, ix);
   2964         if ((first_free == BCMI_FT_COLLECTOR_ID_INVALID) &&
   2965             (ft_coll_info->coll_hw_id == BCMI_FT_COLLECTOR_ID_INVALID)) {
   2966             first_free = ix;
   2967         }
   2968 
   2969         if (ft_coll_info->cmn_coll_id == collector_id) {
   2970             if (ft_coll_info->cmn_export_prof_id != export_profile_id) {
   2971                 /* Export profile associated earlier is not same */
   2972                 return BCM_E_PARAM;
   2973             }
   2974             break;
   2975         }
   2976     }
   2977 
   2978     if (ix == BCMI_FT_EXPORT_INFO(unit)->max_collectors) {
   2979         if (first_free == BCMI_FT_COLLECTOR_ID_INVALID) {
   2980             /* Free hw collector not available. */
   2981             return BCM_E_RESOURCE;
   2982         }
   2983 
   2984         /* Collector not installed yet */
   2985         bcm_collector_info_t_init(&cmn_collector_info);
   2986         bcm_collector_export_profile_t_init(&export_profile_info);
   2987         bcm_flowtracker_collector_info_t_init(&collector_info);
   2988 
   2989         rv = _bcm_xgs5_collector_export_profile_get(unit,
   2990                                                     export_profile_id,
   2991                                                     &export_profile_info);
   2992         BCM_IF_ERROR_RETURN(rv);
   2993 
   2994         if (export_profile_info.wire_format != bcmCollectorWireFormatIpfix) {
   2995             return BCM_E_CONFIG;
   2996         }
   2997 
   2998         if (_bcm_esw_collector_check_user_is_other(unit, collector_id, 
   2999                     _BCM_COLLECTOR_EXPORT_APP_FT_IPFIX)) {
   3000             return BCM_E_CONFIG;
   3001         } 
   3002 
   3003         rv = _bcm_xgs5_collector_get(unit, collector_id, &cmn_collector_info);
   3004         BCM_IF_ERROR_RETURN(rv);
   3005 
   3006         switch (cmn_collector_info.collector_type) {
   3007             case bcmCollectorLocal:
   3008                 collector_info.collector_type = bcmFlowtrackerCollectorLocal;
   3009                 break;
   3010             case bcmCollectorRemote:
   3011                 collector_info.collector_type = bcmFlowtrackerCollectorRemote;
   3012                 break;
   3013             default:
   3014                 return (BCM_E_PARAM);
   3015         }
   3016 
   3017         switch (cmn_collector_info.transport_type) {
   3018             case bcmCollectorTransportTypeIpv4Udp:
   3019                 collector_info.transport_type = bcmFlowtrackerCollectorTransportTypeIpfixIpv4Udp;
   3020                 break;
   3021             case bcmCollectorTransportTypeIpv6Udp:
   3022                 collector_info.transport_type = bcmFlowtrackerCollectorTransportTypeIpfixIpv6Udp;
   3023                 break;
   3024             case bcmCollectorTransportTypeRaw:
   3025                 collector_info.transport_type = bcmFlowtrackerCollectorTransportTypeRaw;
   3026                 break;
   3027             default:
   3028                 return (BCM_E_PARAM);
   3029         }
   3030 
   3031 
   3032 
   3033         sal_memcpy(&(collector_info.eth.src_mac),
   3034                    &(cmn_collector_info.eth.src_mac), sizeof(bcm_mac_t));
   3035         sal_memcpy(&(collector_info.eth.dst_mac),
   3036                    &(cmn_collector_info.eth.dst_mac), sizeof(bcm_mac_t));
   3037         collector_info.eth.vlan_tag_structure = cmn_collector_info.eth.vlan_tag_structure;
   3038         collector_info.eth.outer_tpid = cmn_collector_info.eth.outer_tpid;
   3039         collector_info.eth.inner_tpid = cmn_collector_info.eth.inner_tpid;
   3040         collector_info.eth.outer_vlan_tag = cmn_collector_info.eth.outer_vlan_tag;
   3041         collector_info.eth.inner_vlan_tag = cmn_collector_info.eth.inner_vlan_tag;
   3042 
   3043         collector_info.ipv4.src_ip = cmn_collector_info.ipv4.src_ip;
   3044         collector_info.ipv4.dst_ip = cmn_collector_info.ipv4.dst_ip;
   3045         collector_info.ipv4.dscp = cmn_collector_info.ipv4.dscp;
   3046         collector_info.ipv4.ttl = cmn_collector_info.ipv4.ttl;
   3047 
   3048         sal_memcpy(&(collector_info.ipv6.src_ip),
   3049                    &(cmn_collector_info.ipv6.src_ip), sizeof(bcm_ip6_t));
   3050         sal_memcpy(&(collector_info.ipv6.dst_ip),
   3051                    &(cmn_collector_info.ipv6.dst_ip), sizeof(bcm_ip6_t));
   3052         collector_info.ipv6.traffic_class = cmn_collector_info.ipv6.traffic_class;
   3053         collector_info.ipv6.flow_label = cmn_collector_info.ipv6.flow_label;
   3054         collector_info.ipv6.hop_limit = cmn_collector_info.ipv6.hop_limit;
   3055 
   3056         collector_info.udp.dst_port = cmn_collector_info.udp.dst_port;
   3057         collector_info.udp.src_port = cmn_collector_info.udp.src_port;
   3058 
   3059         collector_info.max_packet_length = export_profile_info.max_packet_length;
   3060 
   3061         ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, first_free);
   3062         ft_coll_info->ipfix_hdr_use_custom = 1;
   3063         ft_coll_info->ipfix_hdr = cmn_collector_info.ipfix;
   3064 
   3065         if (export_profile_info.flags &
   3066             BCM_COLLECTOR_EXPORT_PROFILE_FLAGS_USE_NUM_RECORDS) {
   3067             ft_coll_info->num_records = export_profile_info.num_records;
   3068         }
   3069 
   3070         rv = bcmi_ft_collector_create(unit,
   3071                                       BCM_FLOWTRACKER_COLLECTOR_WITH_ID,
   3072                                       &first_free,
   3073                                       &collector_info);
   3074         BCM_IF_ERROR_RETURN(rv);
   3075 
   3076         ft_coll_info->cmn_coll_id = collector_id;
   3077 
   3078         if (collector_info.collector_type == bcmFlowtrackerCollectorLocal) {
   3079             BCMI_FT_EXPORT_INFO(unit)->dma_collector_id = ft_coll_info->cmn_coll_id;
   3080         }
   3081 
   3082         ft_coll_info->cmn_export_prof_id = export_profile_id;
   3083         ix = first_free;
   3084     }
   3085 
   3086     rv = bcmi_ft_flow_group_collector_add(unit,
   3087                                           flow_group_id,
   3088                                           ix,
   3089                                           template_id);
   3090     BCM_IF_ERROR_RETURN(rv);
   3091 
   3092     rv = _bcm_esw_collector_ref_count_update(unit, collector_id, 1);
   3093     if (BCM_FAILURE(rv)) {
   3094         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   3095                 (BSL_META_U(unit,
   3096                       "FLOWTRACKER(unit %d) Error: collector "
   3097                       " ref_count update failed  %s\n"), unit, bcm_errmsg(rv)));
   3098         return rv;
   3099     }
   3100     rv = _bcm_esw_collector_user_update(unit, collector_id, _BCM_COLLECTOR_EXPORT_APP_FT_IPFIX);
   3101     if (BCM_FAILURE(rv)) {
   3102         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   3103                 (BSL_META_U(unit,
   3104                       "FLOWTRACKER(unit %d) Error: collector "
   3105                       " user update failed  %s\n"), unit, bcm_errmsg(rv)));
   3106         return rv;
   3107     }
   3108     rv = _bcm_esw_collector_export_profile_ref_count_update(unit,
   3109                                                             export_profile_id,
   3110                                                             1);
   3111     if (BCM_FAILURE(rv)) {
   3112         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   3113                 (BSL_META_U(unit,
   3114                       "FLOWTRACKER(unit %d) Error: export profile "
   3115                       " ref_count update failed  %s\n"), unit, bcm_errmsg(rv)));
   3116         return rv;
   3117     }
   3118 
   3119     return BCM_E_NONE;
   3120 }
   3121 
   3122 /*
   3123  * Function:
   3124  *      bcmi_ft_group_collector_detach
   3125  * Purpose:
   3126  *      Dis-associate flow group from a collector with an export template.
   3127  * Parameters:
   3128  *      unit            - (IN)  BCM device number
   3129  *      flow_group_id   - (IN)  Flow group Id
   3130  *      collector_id    - (IN)  Collector Id
   3131  *      template_id     - (IN)  Template Id
   3132  * Returns:
   3133  *      BCM_E_XXX   - BCM error code.
   3134  */
   3135 int bcmi_ft_group_collector_detach(
   3136         int unit,
   3137         bcm_flowtracker_group_t flow_group_id,
   3138         bcm_flowtracker_collector_t collector_id,
   3139         int export_profile_id,
   3140         bcm_flowtracker_export_template_t template_id)
   3141 {
   3142     int rv;
   3143     bcmi_ft_collector_info_t *ft_coll_info = NULL;
   3144     bcm_flowtracker_collector_t ix;
   3145 
   3146     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_collectors; ix++) {
   3147         ft_coll_info = BCMI_FT_COLLECTOR_INFO(unit, ix);
   3148 
   3149         if (ft_coll_info->cmn_coll_id == collector_id) {
   3150             if (ft_coll_info->cmn_export_prof_id != export_profile_id) {
   3151                 /* Export profile associated earlier is not same */
   3152                 return BCM_E_PARAM;
   3153             }
   3154             break;
   3155         }
   3156     }
   3157 
   3158     if (ix == BCMI_FT_EXPORT_INFO(unit)->max_collectors) {
   3159         return BCM_E_NOT_FOUND;
   3160     }
   3161 
   3162     rv = bcmi_ft_flow_group_collector_delete(unit,
   3163                                              flow_group_id,
   3164                                              ix,
   3165                                              template_id);
   3166     BCM_IF_ERROR_RETURN(rv);
   3167 
   3168     if (ft_coll_info->in_use == 0) {
   3169         /* Destroy collector if not attached to any group. */
   3170         rv = bcmi_ft_collector_destroy(unit, ix);
   3171         BCM_IF_ERROR_RETURN(rv);
   3172 
   3173     }
   3174 
   3175     rv = _bcm_esw_collector_ref_count_update(unit, collector_id, -1);
   3176     if (BCM_FAILURE(rv)) {
   3177         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   3178                 (BSL_META_U(unit,
   3179                       "FLOWTRACKER(unit %d) Error: collector "
   3180                       " ref_count update failed  %s\n"), unit, bcm_errmsg(rv)));
   3181         return rv;
   3182     }
   3183     rv = _bcm_esw_collector_export_profile_ref_count_update(unit,
   3184                                                             export_profile_id,
   3185                                                             -1);
   3186     if (BCM_FAILURE(rv)) {
   3187         LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   3188                 (BSL_META_U(unit,
   3189                       "FLOWTRACKER(unit %d) Error: export profile "
   3190                       " ref_count update failed  %s\n"), unit, bcm_errmsg(rv)));
   3191         return rv;
   3192     }
   3193 
   3194 
   3195     return BCM_E_NONE;
   3196 }
   3197 
   3198 /*
   3199  * Function:
   3200  *      bcmi_ft_group_collector_attach_get_all
   3201  * Purpose:
   3202  *      Get list of all collectors, templates  attached to a flow group
   3203  * Parameters:
   3204  *      unit                - (IN)  BCM device number
   3205  *      flow_group_id       - (IN)  Flow group Id
   3206  *      max_list_size       - (IN)  Size of the list arrays
   3207  *      list_of_collectors  - (OUT) Collector list
   3208  *      list_of_templates   - (OUT) Template list
   3209  *      list_size           - (OUT) Number of elements in the lists
   3210  * Returns:
   3211  *      BCM_E_XXX   - BCM error code.
   3212  */
   3213 int bcmi_ft_group_collector_attach_get_all(
   3214     int unit, 
   3215     bcm_flowtracker_group_t flow_group_id, 
   3216     int max_list_size, 
   3217     bcm_flowtracker_collector_t *list_of_collectors, 
   3218     int *list_of_export_profile_ids,
   3219     bcm_flowtracker_export_template_t *list_of_templates, 
   3220     int *list_size)
   3221 {
   3222     int result = BCM_E_UNAVAIL;
   3223 
   3224     return result;
   3225 }
   3226 
   3227 
   3228 
   3229 
   3230 
   3231 /*
   3232  * Function:
   3233  *     bcmi_ft_export_record_register
   3234  * Description:
   3235  *     To register the callback function for flow info export
   3236  * Parameters:
   3237  *     unit          device number
   3238  *     callback      user callback function
   3239  *     userdata      user data used as argument during callback
   3240  * Return:
   3241  *     BCM_E_NONE
   3242  *     BCM_E_PARAM
   3243  *     BCM_E_RESOURCE
   3244  *     BCM_E_UNAVAIL
   3245  */
   3246 int
   3247 bcmi_ft_export_record_register(
   3248     int unit,
   3249     bcm_flowtracker_collector_t collector_id,
   3250     bcm_flowtracker_collector_callback_options_t callback_options,
   3251     bcm_flowtracker_export_record_cb_f callback_fn,
   3252     void *userdata)
   3253 {
   3254     int free_index, i;
   3255     bcmi_ft_export_cb_ctrl_t *ft_export_cb_ctrl;
   3256     bcmi_ft_cb_entry_t *entry;
   3257 
   3258 
   3259     if (!soc_feature(unit, soc_feature_bscan_ft_fifodma_support)) {
   3260         return BCM_E_UNAVAIL;
   3261     }
   3262 
   3263     if (callback_fn == NULL) {
   3264         return BCM_E_PARAM;
   3265     }
   3266 
   3267     if (BCMI_FT_CB_CTRL(unit) == NULL) {
   3268         BCM_IF_ERROR_RETURN(bcmi_ft_export_cb_init(unit));
   3269     }
   3270     ft_export_cb_ctrl = BCMI_FT_CB_CTRL(unit);
   3271 
   3272     if (BCMI_FT_EXPORT_INFO(unit)->dma_collector_id != collector_id) {
   3273         return BCM_E_PARAM;
   3274     }
   3275 
   3276     free_index = -1;
   3277     for (i = 0; i < BCMI_FT_CB_MAX; i++) {
   3278         entry = &ft_export_cb_ctrl->callback_entry[i];
   3279         if (entry->state == BCMI_FT_CALLBACK_STATE_INVALID ||
   3280             (ft_export_cb_ctrl->pid == SAL_THREAD_ERROR &&
   3281              entry->state == BCMI_FT_CALLBACK_STATE_UNREGISTERED)) {
   3282             if (free_index < 0) {
   3283                 free_index = i;
   3284             }
   3285         } else if ((entry->state == BCMI_FT_CALLBACK_STATE_ACTIVE) ||
   3286                    (entry->state == BCMI_FT_CALLBACK_STATE_REGISTERED)) {
   3287             if (entry->callback == callback_fn && entry->userdata == userdata) {
   3288                 return BCM_E_NONE;
   3289             }
   3290         }
   3291     }
   3292 
   3293     if (free_index < 0) {
   3294         return BCM_E_RESOURCE;
   3295     }
   3296 
   3297     entry = &ft_export_cb_ctrl->callback_entry[free_index];
   3298     entry->callback = callback_fn;
   3299     entry->callback_options = callback_options;
   3300     entry->userdata = userdata;
   3301     entry->state = BCMI_FT_CALLBACK_STATE_REGISTERED;
   3302 
   3303     (void)bcma_ft_export_fifo_control(unit, ft_export_cb_ctrl->interval);
   3304 
   3305     return BCM_E_NONE;
   3306 }
   3307 
   3308 
   3309 /*
   3310  * Function:
   3311  *     bcmi_ft_export_record_unregister
   3312  * Description:
   3313  *     To unregister the callback function for flow info export
   3314  * Parameters:
   3315  *     unit          device number
   3316  *     callback      user callback function
   3317  *     userdata      user data used as argument during callback
   3318  * Return:
   3319  *     BCM_E_NONE
   3320  *     BCM_E_NOT_FOUND
   3321  *     BCM_E_UNAVAIL
   3322  *     BCM_E_INIT
   3323  */
   3324 int
   3325 bcmi_ft_export_record_unregister(
   3326     int unit,
   3327     bcm_flowtracker_collector_t collector_id,
   3328     bcm_flowtracker_collector_callback_options_t callback_options,
   3329     bcm_flowtracker_export_record_cb_f callback_fn)
   3330 {
   3331     int i;
   3332     bcmi_ft_export_cb_ctrl_t *ft_export_cb_ctrl;
   3333     bcmi_ft_cb_entry_t *entry;
   3334 
   3335     if (!soc_feature(unit, soc_feature_bscan_ft_fifodma_support)) {
   3336         return BCM_E_UNAVAIL;
   3337     }
   3338 
   3339     if (BCMI_FT_CB_CTRL(unit) == NULL) {
   3340         return BCM_E_INIT;
   3341     }
   3342     ft_export_cb_ctrl = BCMI_FT_CB_CTRL(unit);
   3343 
   3344     for (i = 0; i < BCMI_FT_CB_MAX; i++) {
   3345         entry = &ft_export_cb_ctrl->callback_entry[i];
   3346 
   3347         if (entry->callback == callback_fn) {
   3348             entry->state = BCMI_FT_CALLBACK_STATE_UNREGISTERED;
   3349 
   3350             (void)bcma_ft_export_fifo_control(unit, ft_export_cb_ctrl->interval);
   3351             return BCM_E_NONE;
   3352         }
   3353     }
   3354 
   3355     return BCM_E_NOT_FOUND;
   3356 }
   3357 
   3358 
   3359 STATIC int
   3360 _bcm_ft_process_export_entry(int unit,
   3361                              void *entry,
   3362                              bcm_flowtracker_export_record_t *data)
   3363 {
   3364     int ix, count, num_words;
   3365     static int first_half = 1;
   3366     static uint8 data_rec[BCM_FLOWTRACKER_EXPORT_RECORD_LENGTH] = {0};
   3367     uint32 *entry_p, *data_p;
   3368 
   3369     count = (BCM_FLOWTRACKER_EXPORT_RECORD_LENGTH / 2);
   3370     num_words = count / 4;
   3371 
   3372     entry_p = entry;
   3373 
   3374     if (first_half) {
   3375         data_p = (uint32 *) &(data_rec[0]);
   3376         for (ix = 0; ix < num_words; ix++) {
   3377             data_p[num_words - ix - 1] = soc_htonl(entry_p[ix]);
   3378         }
   3379         first_half = 0;
   3380 
   3381         return SOC_E_BUSY;
   3382     } else {
   3383 
   3384         data_p = (uint32 *) &(data_rec[count]);
   3385         for (ix = 0; ix < num_words; ix++) {
   3386             data_p[num_words - ix - 1] = soc_htonl(*entry_p);
   3387             entry_p++;
   3388         }
   3389 
   3390         sal_memset(data, 0, sizeof(*data));
   3391         data->size = BCM_FLOWTRACKER_EXPORT_RECORD_LENGTH;
   3392         sal_memcpy(data->data_record, data_rec,
   3393                    data->size);
   3394 
   3395         first_half = 1;
   3396         sal_memset(&data_rec[0], 0, (BCM_FLOWTRACKER_EXPORT_RECORD_LENGTH));
   3397 
   3398         return SOC_E_NONE;
   3399     }
   3400 
   3401     return SOC_E_NONE;
   3402 }
   3403 
   3404 
   3405 
   3406 /*
   3407  * Function:
   3408  *     bcmi_ft_export_dma
   3409  * Description:
   3410  *     A task thread to process IPFIX export FIFOs via FIFO DMA
   3411  * Parameters:
   3412  *     unit_vp          Device number
   3413  * Return:
   3414  *     None
   3415  */
   3416 STATIC void
   3417 bcmi_ft_export_dma(void *unit_vp)
   3418 {
   3419     soc_mem_t export_fifo;
   3420     bcmi_ft_cb_entry_t *cb_entry;
   3421     bcmi_ft_export_cb_ctrl_t *ft_export_cb_ctrl;
   3422     bcm_flowtracker_export_record_t export_record;
   3423 
   3424     int unit;
   3425     int handled;
   3426     int rv, cb_rv;
   3427     int entries_per_buf, adv_threshold;
   3428     int interval, count, i, j, non_empty;
   3429     int chan, entry_words;
   3430     uint32 *buff_max;
   3431     void *host_buf, *export_entry;
   3432     uint32 rval, hostmem_timeout, overflow_ch, done, error, fail;
   3433 
   3434     unit = PTR_TO_INT(unit_vp);
   3435     ft_export_cb_ctrl = BCMI_FT_CB_CTRL(unit);
   3436     export_fifo = BSC_EX_EXPORT_FIFOm;
   3437 
   3438     entries_per_buf = soc_property_get(unit,
   3439                           spn_FLOWTRACKER_EXPORT_FIFO_HOSTBUF_SIZE, 1024);
   3440     adv_threshold = entries_per_buf / 2;
   3441 
   3442     chan = ft_export_cb_ctrl->dma_chan;
   3443 
   3444     entry_words = soc_mem_entry_words(unit, export_fifo);
   3445     host_buf = soc_cm_salloc(unit, entries_per_buf * entry_words * sizeof(uint32),
   3446                       "FT EXPORT DMA Buffer");
   3447 
   3448     if (host_buf == NULL) {
   3449         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR,
   3450                            SOC_SWITCH_EVENT_THREAD_IPFIX, __LINE__,
   3451                            BCM_E_MEMORY);
   3452         goto cleanup_exit;
   3453     }
   3454 
   3455     soc_fifodma_stop(unit, chan);
   3456 
   3457     rv = soc_fifodma_masks_get(unit, &hostmem_timeout, &overflow_ch, &error, &done);
   3458     if (SOC_FAILURE(rv)) {
   3459         goto cleanup_exit;
   3460     }
   3461 
   3462     rv = soc_fifodma_start(unit, chan, TRUE, export_fifo, 0,
   3463                                MEM_BLOCK_ANY, 0, entries_per_buf,
   3464                                host_buf);
   3465     if (BCM_FAILURE(rv)) {
   3466         soc_event_generate(unit, SOC_SWITCH_EVENT_THREAD_ERROR,
   3467                            SOC_SWITCH_EVENT_THREAD_IPFIX, __LINE__, rv);
   3468         goto cleanup_exit;
   3469     }
   3470 
   3471     export_entry = host_buf;
   3472     buff_max = (uint32 *)export_entry + (entries_per_buf * entry_words);
   3473 
   3474 
   3475     while ((interval = ft_export_cb_ctrl->interval)) {
   3476         fail = FALSE;
   3477         if (SOC_CONTROL(unit)->ftExportIntrEnb) {
   3478 
   3479             soc_fifodma_intr_enable(unit, chan);
   3480 
   3481 
   3482             if (sal_sem_take(SOC_CONTROL(unit)->ftExportIntr, interval) < 0) {
   3483                 LOG_VERBOSE(BSL_LS_SOC_INTR,
   3484                             (BSL_META_U(unit,
   3485                                         "FT Export DMA polling timeout\n")));
   3486             } else {
   3487                 LOG_VERBOSE(BSL_LS_SOC_INTR,
   3488                             (BSL_META_U(unit,
   3489                                         "FT Export DMA woken up\n")));
   3490 
   3491                 soc_fifodma_status_get(unit, chan, &rval);
   3492                 fail = ((rval & hostmem_timeout) | (rval & overflow_ch));
   3493             }
   3494         } else {
   3495             /* Polling mode: Sleep for thread interval */
   3496             sal_usleep(interval);
   3497         }
   3498 
   3499         /* Update current Callback Function Status */
   3500         for (i = 0; i < BCMI_FT_CB_MAX; i++) {
   3501             cb_entry = &ft_export_cb_ctrl->callback_entry[i];
   3502             switch (cb_entry->state) {
   3503             case BCMI_FT_CALLBACK_STATE_REGISTERED:
   3504                 cb_entry->state = BCMI_FT_CALLBACK_STATE_ACTIVE;
   3505                 break;
   3506             case BCMI_FT_CALLBACK_STATE_UNREGISTERED:
   3507                 cb_entry->state = BCMI_FT_CALLBACK_STATE_INVALID;
   3508                 break;
   3509             default:
   3510                 break;
   3511             }
   3512         }
   3513 
   3514 
   3515         do {
   3516             non_empty = FALSE;
   3517 
   3518             rv = soc_fifodma_num_entries_get(unit, chan, &count);
   3519             if (SOC_SUCCESS(rv)) {
   3520                 non_empty = TRUE;
   3521                 if (count > adv_threshold) {
   3522                     count = adv_threshold;
   3523                 }
   3524 
   3525                 /* Invalidate DMA memory to read */
   3526                 if (((uint32 *)export_entry + count * entry_words) > buff_max) {
   3527                     /* roll-over cases */
   3528                     soc_cm_sinval(unit, export_entry,
   3529                         (buff_max - (uint32 *)export_entry) * sizeof(uint32));
   3530                     soc_cm_sinval(unit, host_buf,
   3531                         ((count * entry_words) - (buff_max - (uint32 *)export_entry)) * sizeof(uint32));
   3532                 }
   3533                 else {
   3534                     soc_cm_sinval(unit, export_entry, (count * entry_words) * sizeof(uint32));
   3535                 }
   3536 
   3537 
   3538                 for (i = 0; i < count; i++) {
   3539 
   3540                     rv = _bcm_ft_process_export_entry(unit, export_entry, &export_record);
   3541 
   3542                     export_entry = (uint32 *)export_entry + entry_words;
   3543 
   3544                     /* From the begining of host buffer */
   3545                     if ((((uint32 *)export_entry - (uint32 *)host_buf) /
   3546                          entry_words) == entries_per_buf) {
   3547                         export_entry = host_buf;
   3548                     }
   3549 
   3550                     if (rv < 0) {
   3551                         /* Skip calling CB functions for
   3552                          *  first half records - i.e, when rv != SOC_E_NONE.
   3553                          */
   3554                         continue;
   3555                     }
   3556 
   3557 
   3558                     handled = FALSE;
   3559 
   3560                     for (j = 0; j < BCMI_FT_CB_MAX; j++) {
   3561                         cb_entry = &ft_export_cb_ctrl->callback_entry[j];
   3562                         if (cb_entry->state == BCMI_FT_CALLBACK_STATE_ACTIVE) {
   3563                             cb_rv = cb_entry->callback(unit,
   3564                                 BCMI_FT_EXPORT_INFO(unit)->dma_collector_id,
   3565                                 &export_record, cb_entry->userdata);
   3566 
   3567                             switch (cb_rv) {
   3568                             case BCM_FLOWTRACKER_EXPORT_RECORD_NOT_HANDLED:
   3569                                 break;
   3570                             case BCM_FLOWTRACKER_EXPORT_RECORD_HANDLED:
   3571                                 handled = TRUE;
   3572                                 break;
   3573                             case BCM_FLOWTRACKER_EXPORT_RECORD_HANDLED_OWNED:
   3574                                 handled = TRUE;
   3575                                 BCMI_FT_CB_CTRL(unit)->owned++;
   3576                                 break;
   3577                             default:
   3578                                 BCMI_FT_CB_CTRL(unit)->bad_handled++;
   3579                                 break;
   3580                             }
   3581 
   3582                             if (handled) {
   3583                                 break;
   3584                             }
   3585                         }
   3586                     }
   3587                 }
   3588 
   3589                 /* Mark entries read in fifo dma channel */
   3590                 soc_fifodma_set_entries_read(unit, chan, count);
   3591             }
   3592 
   3593             /* check and clear error */
   3594             soc_fifodma_status_get(unit, chan, &rval);
   3595             if (rval & done) {
   3596                 LOG_ERROR(BSL_LS_SOC_COMMON,
   3597                           (BSL_META_U(unit,
   3598                                       "FIFO DMA engine terminated for chan[%d]\n"),
   3599                            chan));
   3600                 if (rval & error) {
   3601                     LOG_ERROR(BSL_LS_SOC_COMMON,
   3602                               (BSL_META_U(unit,
   3603                                           "FIFO DMA engine encountered error: [0x%x]\n"),
   3604                                rval));
   3605                 }
   3606                 goto cleanup_exit;
   3607             }
   3608 
   3609         } while (non_empty);
   3610 
   3611         if (fail) {
   3612             /* Clearing of the FIFO_CH_DMA_INT interrupt by resetting
   3613              * overflow & timeout status in FIFO_CHx_RD_DMA_STAT_CLR reg
   3614              */
   3615             soc_fifodma_status_clear(unit, chan);
   3616         }
   3617     }
   3618 
   3619 cleanup_exit:
   3620     (void)soc_mem_fifo_dma_stop(unit, chan);
   3621 
   3622     if (host_buf != NULL) {
   3623         soc_cm_sfree(unit, host_buf);
   3624     }
   3625     ft_export_cb_ctrl->pid = SAL_THREAD_ERROR;
   3626     sal_thread_exit(0);
   3627 }
   3628 
   3629 
   3630 /* Functions called from diag shell */
   3631 
   3632 /*
   3633  * Function:
   3634  *     bcma_ft_export_fifo_control
   3635  * Description:
   3636  *     To start/stop ipfix export fifo processing thread
   3637  * Parameters:
   3638  *     unit            device number
   3639  *     sal_usecs_t     polling interval, set to 0 to stop the thread
   3640  * Return:
   3641  *     BCM_E_NONE
   3642  *     BCM_E_MEMORY
   3643  *     BCM_E_UNAVAIL
   3644  */
   3645 int
   3646 bcma_ft_export_fifo_control(int unit, sal_usecs_t interval)
   3647 {
   3648     bcmi_ft_export_cb_ctrl_t *ft_export_cb_ctrl = BCMI_FT_CB_CTRL(unit);
   3649     int pri;
   3650     char name[16];
   3651 
   3652     if (!soc_feature(unit, soc_feature_bscan_ft_fifodma_support)) {
   3653         return BCM_E_UNAVAIL;
   3654     }
   3655 
   3656 
   3657     if (ft_export_cb_ctrl == NULL) {
   3658         BCM_IF_ERROR_RETURN(bcmi_ft_export_cb_init(unit));
   3659         ft_export_cb_ctrl = BCMI_FT_CB_CTRL(unit);
   3660         if (ft_export_cb_ctrl == NULL) {
   3661             return BCM_E_INTERNAL;
   3662         }
   3663     }
   3664 
   3665     sal_snprintf(name, sizeof(name), "bcmFtExportDma.%d", unit);
   3666 
   3667     ft_export_cb_ctrl->interval = interval;
   3668 
   3669     if (interval) {
   3670         if (ft_export_cb_ctrl->pid == SAL_THREAD_ERROR) {
   3671             pri = soc_property_get(unit,
   3672                       spn_FLOWTRACKER_EXPORT_FIFO_THREAD_PRI, 100);
   3673             ft_export_cb_ctrl->pid = sal_thread_create(name,
   3674                                                        SAL_THREAD_STKSZ,
   3675                                                        pri,
   3676                                                        bcmi_ft_export_dma,
   3677                                                        INT_TO_PTR(unit));
   3678             if (ft_export_cb_ctrl->pid == SAL_THREAD_ERROR) {
   3679                 LOG_ERROR(BSL_LS_BCM_FLOWTRACKER,
   3680                           (BSL_META_U(unit,
   3681                                       "Could not start thread\n")));
   3682                 return BCM_E_MEMORY;
   3683             }
   3684         }
   3685     } else {
   3686         /* Wake up thread so it will check the changed interval value */
   3687         sal_sem_give(SOC_CONTROL(unit)->ftExportIntr);
   3688     }
   3689 
   3690     return BCM_E_NONE;
   3691 }
   3692 
   3693 
   3694 int
   3695 bcma_ft_export_dma_collector_get(int unit,
   3696                                  bcm_collector_t *id)
   3697 {
   3698     bcm_collector_t collector_id;
   3699 
   3700     collector_id = BCMI_FT_EXPORT_INFO(unit)->dma_collector_id;
   3701 
   3702     if (collector_id == BCMI_FT_COLLECTOR_ID_INVALID) {
   3703         return BCM_E_PARAM;
   3704     }
   3705 
   3706     *id = collector_id;
   3707 
   3708     return BCM_E_NONE;
   3709 }
   3710 
   3711 int
   3712 bcma_ft_setid_template_id_get(int unit, uint16 setid,
   3713                               bcm_flowtracker_export_template_t *template_id)
   3714 {
   3715     int ix;
   3716     bcmi_ft_template_info_t *template_info;
   3717 
   3718     for (ix = 0; ix < BCMI_FT_MAX_TEMPLATES; ix++) {
   3719         template_info = BCMI_FT_TEMPLATE_INFO(unit, ix);
   3720 
   3721         if (setid == template_info->set_id) {
   3722             break;
   3723         }
   3724 
   3725     }
   3726 
   3727     if (ix < BCMI_FT_MAX_TEMPLATES) {
   3728         *template_id = ix;
   3729         return BCM_E_NONE;
   3730     }
   3731 
   3732     return BCM_E_NOT_FOUND;
   3733 }
   3734 
   3735 
   3736 
   3737 #ifdef BCM_WARM_BOOT_SUPPORT
   3738 
   3739 #define BCMI_FT_WB_SCACHE_SIZE(_data_)  sizeof(*(_data_))
   3740 
   3741 
   3742 #define BCMI_FT_WB_SCACHE_SYNC(_scache_, _data_)            \
   3743     do {                                                    \
   3744         sal_memcpy((_scache_), (_data_), sizeof(*(_data_)));\
   3745         (_scache_) +=  sizeof(*(_data_));                   \
   3746     } while (0)
   3747 
   3748 #define BCMI_FT_WB_SCACHE_RECOVER(_scache_, _data_)         \
   3749     do {                                                    \
   3750         sal_memcpy((_data_), (_scache_), sizeof(*(_data_)));\
   3751         (_scache_) +=  sizeof(*(_data_));                   \
   3752     } while (0)
   3753 
   3754 
   3755 /*
   3756  * Function:
   3757  *      bcmi_ft_export_wb_alloc_size
   3758  * Purpose:
   3759  *      Allocate persistent info memory for flowtracker module
   3760  * Parameters:
   3761  *      unit - StrataSwitch unit number.
   3762  * Returns:
   3763  *      BCM_E_XXX
   3764  */
   3765 STATIC void
   3766 bcmi_ft_export_wb_alloc_size(int unit, int *size)
   3767 {
   3768     int ix, jx;
   3769     int alloc_size;
   3770     bcmi_ft_collector_info_t *coll_info;
   3771     bcmi_ft_template_info_t *template_info;
   3772 
   3773     alloc_size = 0;
   3774 
   3775     /* DMA collector Id */
   3776     alloc_size += BCMI_FT_WB_SCACHE_SIZE(&(BCMI_FT_EXPORT_INFO(unit)->dma_collector_id));
   3777 
   3778     /* Sync collector_info structs. */
   3779     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_collectors; ix++) {
   3780         coll_info = BCMI_FT_COLLECTOR_INFO(unit, ix);
   3781 
   3782         alloc_size += BCMI_FT_WB_SCACHE_SIZE(&(coll_info->cmn_coll_id));
   3783         alloc_size += BCMI_FT_WB_SCACHE_SIZE(&(coll_info->cmn_export_prof_id));
   3784         alloc_size += BCMI_FT_WB_SCACHE_SIZE(&(coll_info->coll_hw_id));
   3785         alloc_size += BCMI_FT_WB_SCACHE_SIZE(&(coll_info->in_use));
   3786         alloc_size += BCMI_FT_WB_SCACHE_SIZE(&(coll_info->collector_info));
   3787     }
   3788 
   3789     /* Sync template_info structs. */
   3790     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_templates; ix++) {
   3791         template_info = BCMI_FT_TEMPLATE_INFO(unit, ix);
   3792 
   3793         alloc_size += BCMI_FT_WB_SCACHE_SIZE(&(template_info->template_id));
   3794         alloc_size += BCMI_FT_WB_SCACHE_SIZE(&(template_info->in_use));
   3795         alloc_size += BCMI_FT_WB_SCACHE_SIZE(&(template_info->set_id));
   3796         alloc_size += BCMI_FT_WB_SCACHE_SIZE(&(template_info->num_elements));
   3797 
   3798 
   3799         for (jx = 0; jx < BCMI_FT_TEMPLATE_MAX_ELEMS; jx++) {
   3800             alloc_size += BCMI_FT_WB_SCACHE_SIZE(&(template_info->export_elements[jx]));
   3801         }
   3802     }
   3803 
   3804     /* Return the calculated size. */
   3805     *size = alloc_size;
   3806 
   3807     return;
   3808 }
   3809 
   3810 int
   3811 bcmi_ft_export_warmboot_alloc(int unit, soc_scache_handle_t scache_handle)
   3812 {
   3813 
   3814     uint8 *ft_scache_ptr;
   3815     int size = 0;
   3816     int rv = BCM_E_NONE;
   3817 
   3818     bcmi_ft_export_wb_alloc_size(unit, &size);
   3819 
   3820     rv = _bcm_esw_scache_ptr_get(unit, scache_handle, TRUE,
   3821                                  size, &ft_scache_ptr,
   3822                                  BCM_WB_FT_EXPORT_DEFAULT_VERSION, NULL);
   3823 
   3824     if (BCM_E_NOT_FOUND == rv) {
   3825         /* Proceed with Level 1 Warm Boot */
   3826         rv = BCM_E_NONE;
   3827     }
   3828 
   3829     return rv;
   3830 }
   3831 
   3832 
   3833 
   3834 /*
   3835  * Function:
   3836  *     bcmi_ft_export_warmboot_sync
   3837  * Purpose:
   3838  *     Sync flowtracker export state.
   3839  * Parameters:
   3840  *     unit - (IN) BCM device id
   3841  *
   3842  * Returns:
   3843  *     BCM_E_XXX
   3844  */
   3845 int
   3846 bcmi_ft_export_warmboot_sync(int unit, soc_scache_handle_t scache_handle)
   3847 {
   3848     int ix, jx;
   3849     int size;
   3850     bcmi_ft_collector_info_t *coll_info;
   3851     bcmi_ft_template_info_t *template_info;
   3852     uint8 *ft_scache_ptr;
   3853 
   3854     /* Get the size to save ft export module warmboot state. */
   3855     bcmi_ft_export_wb_alloc_size(unit, &size);
   3856 
   3857     BCM_IF_ERROR_RETURN
   3858         (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
   3859                                  size, &ft_scache_ptr,
   3860                                  BCM_WB_FT_EXPORT_DEFAULT_VERSION, NULL));
   3861 
   3862     /* DMA collector Id */
   3863     BCMI_FT_WB_SCACHE_SYNC(ft_scache_ptr, &(BCMI_FT_EXPORT_INFO(unit)->dma_collector_id));
   3864 
   3865     /* Sync collector_info structs. */
   3866     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_collectors; ix++) {
   3867         coll_info = BCMI_FT_COLLECTOR_INFO(unit, ix);
   3868 
   3869         BCMI_FT_WB_SCACHE_SYNC(ft_scache_ptr, &(coll_info->cmn_coll_id));
   3870         BCMI_FT_WB_SCACHE_SYNC(ft_scache_ptr, &(coll_info->cmn_export_prof_id));
   3871         BCMI_FT_WB_SCACHE_SYNC(ft_scache_ptr, &(coll_info->coll_hw_id));
   3872         BCMI_FT_WB_SCACHE_SYNC(ft_scache_ptr, &(coll_info->in_use));
   3873         BCMI_FT_WB_SCACHE_SYNC(ft_scache_ptr, &(coll_info->collector_info));
   3874     }
   3875 
   3876     /* Sync template_info structs. */
   3877     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_templates; ix++) {
   3878         template_info = BCMI_FT_TEMPLATE_INFO(unit, ix);
   3879 
   3880         BCMI_FT_WB_SCACHE_SYNC(ft_scache_ptr, &(template_info->template_id));
   3881         BCMI_FT_WB_SCACHE_SYNC(ft_scache_ptr, &(template_info->in_use));
   3882         BCMI_FT_WB_SCACHE_SYNC(ft_scache_ptr, &(template_info->set_id));
   3883         BCMI_FT_WB_SCACHE_SYNC(ft_scache_ptr, &(template_info->num_elements));
   3884 
   3885 
   3886         for (jx = 0; jx < BCMI_FT_TEMPLATE_MAX_ELEMS; jx++) {
   3887             BCMI_FT_WB_SCACHE_SYNC(ft_scache_ptr, &(template_info->export_elements[jx]));
   3888         }
   3889     }
   3890 
   3891     return BCM_E_NONE;
   3892 }
   3893 
   3894 STATIC int
   3895 bcmi_ft_export_reinit(int unit)
   3896 {
   3897 
   3898     int ix, rv;
   3899     bcmi_ft_template_info_t *template_info;
   3900     bcmi_ft_collector_info_t *coll_info;
   3901 
   3902     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_collectors; ix++) {
   3903         coll_info = BCMI_FT_COLLECTOR_INFO(unit, ix);
   3904 
   3905         if (coll_info->in_use) {
   3906             rv = _bcm_esw_collector_ref_count_update(unit,
   3907                             coll_info->cmn_coll_id,
   3908                             coll_info->in_use);
   3909             BCM_IF_ERROR_RETURN(rv);
   3910             rv = _bcm_esw_collector_user_update(unit,
   3911                             coll_info->cmn_coll_id,
   3912                             _BCM_COLLECTOR_EXPORT_APP_FT_IPFIX);
   3913             BCM_IF_ERROR_RETURN(rv);
   3914 
   3915             rv = _bcm_esw_collector_export_profile_ref_count_update(unit,
   3916                             coll_info->cmn_export_prof_id, coll_info->in_use);
   3917             BCM_IF_ERROR_RETURN(rv);
   3918 
   3919         }
   3920     }
   3921 
   3922     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_templates; ix++) {
   3923         template_info = BCMI_FT_TEMPLATE_INFO(unit, ix);
   3924         if (template_info->template_id != BCMI_FT_TEMPLATE_ID_INVALID) {
   3925             SHR_BITSET(BCMI_FT_TEMPLATE_BITMAP(unit), ix);
   3926         }
   3927     }
   3928 
   3929     return BCM_E_NONE;
   3930 }
   3931 
   3932 
   3933 /*
   3934  * Function:
   3935  *     bcmi_ft_export_warmboot_recover
   3936  * Purpose:
   3937  *     Recover flowtracker export state.
   3938  * Parameters:
   3939  *     unit - (IN) BCM device id
   3940  *
   3941  * Returns:
   3942  *     BCM_E_XXX
   3943  */
   3944 
   3945 int
   3946 bcmi_ft_export_warmboot_recover(int unit, soc_scache_handle_t scache_handle)
   3947 {
   3948     int ix, jx;
   3949     int size;
   3950     bcmi_ft_collector_info_t *coll_info;
   3951     bcmi_ft_template_info_t *template_info;
   3952     uint8 *ft_scache_ptr;
   3953 
   3954     /* Get the size to save ft export module warmboot state. */
   3955     bcmi_ft_export_wb_alloc_size(unit, &size);
   3956 
   3957 
   3958     BCM_IF_ERROR_RETURN
   3959         (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
   3960                                  size, &ft_scache_ptr,
   3961                                  BCM_WB_FT_EXPORT_DEFAULT_VERSION, NULL));
   3962 
   3963     /* DMA collector Id */
   3964     BCMI_FT_WB_SCACHE_RECOVER(ft_scache_ptr, &(BCMI_FT_EXPORT_INFO(unit)->dma_collector_id));
   3965 
   3966     /* Sync collector_info structs. */
   3967     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_collectors; ix++) {
   3968         coll_info = BCMI_FT_COLLECTOR_INFO(unit, ix);
   3969 
   3970         BCMI_FT_WB_SCACHE_RECOVER(ft_scache_ptr, &(coll_info->cmn_coll_id));
   3971         BCMI_FT_WB_SCACHE_RECOVER(ft_scache_ptr, &(coll_info->cmn_export_prof_id));
   3972         BCMI_FT_WB_SCACHE_RECOVER(ft_scache_ptr, &(coll_info->coll_hw_id));
   3973         BCMI_FT_WB_SCACHE_RECOVER(ft_scache_ptr, &(coll_info->in_use));
   3974         BCMI_FT_WB_SCACHE_RECOVER(ft_scache_ptr, &(coll_info->collector_info));
   3975     }
   3976 
   3977     /* Sync template_info structs. */
   3978     for (ix = 0; ix < BCMI_FT_EXPORT_INFO(unit)->max_templates; ix++) {
   3979         template_info = BCMI_FT_TEMPLATE_INFO(unit, ix);
   3980 
   3981         BCMI_FT_WB_SCACHE_RECOVER(ft_scache_ptr, &(template_info->template_id));
   3982         BCMI_FT_WB_SCACHE_RECOVER(ft_scache_ptr, &(template_info->in_use));
   3983         BCMI_FT_WB_SCACHE_RECOVER(ft_scache_ptr, &(template_info->set_id));
   3984         BCMI_FT_WB_SCACHE_RECOVER(ft_scache_ptr, &(template_info->num_elements));
   3985 
   3986 
   3987         for (jx = 0; jx < BCMI_FT_TEMPLATE_MAX_ELEMS; jx++) {
   3988             BCMI_FT_WB_SCACHE_RECOVER(ft_scache_ptr, &(template_info->export_elements[jx]));
   3989         }
   3990     }
   3991 
   3992 
   3993     /* Export reinit */
   3994     BCM_IF_ERROR_RETURN(bcmi_ft_export_reinit(unit));
   3995 
   3996     return BCM_E_NONE;
   3997 }
   3998 
   3999 #endif /* BCM_WARM_BOOT_SUPPORT */
   4000 
   4001 #else /* BCM_FLOWTRCAKER_SUPPORT*/
   4002 int bcmi_ft_export_not_empty;
   4003 #endif /* BCM_FLOWTRCAKER_SUPPORT */
   4004