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

ftrmon.c (59212B)


      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  * FlowTracker Remote record monitor
      8  */
      9 
     10 #include <sal/types.h>
     11 #include <shared/bsl.h>
     12 #ifndef __KERNEL__
     13 #include <sys/types.h>
     14 #include <netinet/in.h>
     15 #endif
     16 
     17 #include <soc/debug.h>
     18 #include <soc/cm.h>
     19 
     20 #include <sal/appl/io.h>
     21 #include <sal/appl/sal.h>
     22 #include <sal/core/thread.h>
     23 #include <sal/core/sync.h>
     24 #include <sal/core/spl.h>
     25 #include <sal/core/libc.h>
     26 
     27 #include <appl/diag/shell.h>
     28 #include <appl/diag/parse.h>
     29 #include <appl/diag/system.h>
     30 #include <appl/diag/decode.h>
     31 
     32 #include <bcm/rx.h>
     33 #include <bcm/error.h>
     34 #include <bcm/flowtracker.h>
     35 
     36 #include <soc/shared/shr_pkt.h>
     37 
     38 #if defined(BCM_FLOWTRACKER_SUPPORT)
     39 
     40 #ifdef GHS
     41 #define d_packet_format(pfx, decode, pkt, count, p)
     42 #endif
     43 
     44 /* Maximum name length of export elements. */
     45 #define BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX       30
     46 
     47 /*
     48  * Maximum packet size we will read in.
     49  */
     50 #define PW_PACKET_SIZE    10240
     51 
     52 #define PW_COUNT_DEFAULT  100
     53 
     54 
     55 static char ft_rmon_name[SOC_MAX_NUM_DEVICES][16];
     56 
     57 /*
     58  * Define 2 of the public fields in the dv structure for our use.
     59  */
     60 #define  dv_ft_rmon_pup   dv_public1.ptr
     61 #define  dv_ft_rmon_chan  dv_public2.u32
     62 
     63 
     64 /*
     65  * Typedef:  pup_t
     66  * Purpose:  Maps out each packet array entry - pkt_cnt is sort of
     67  *           useless, but it makes life easier so we use it to track
     68  *           the pack # received.
     69  *
     70  * Notes:    Each entry is either FREE or on a circular/double linked
     71  *           list used for the LOG. When the LOG is full, there are 3 extra
     72  *           pups used to suppor the up to 3 outstanding DMA operations.
     73  */
     74 typedef struct pup_s {
     75     struct pup_s *pup_next, *pup_prev; /* Next and previous pointers */
     76     dv_t         *pup_esw_dv;   /* DMA descriptor, ESW SOC mode only */
     77     int           pup_seqno;    /* Packet # */
     78     void         *pup_pkt;      /* Actual packet pointer, for soc */
     79     bcm_pkt_t    rx_pkt;        /* Packet data for RX */
     80 } pup_t;
     81 
     82 #define REPORT_COUNT    0x01    /* Report packet count */
     83 #define REPORT_RAW      0x02    /* Report Raw packet data */
     84 #define REPORT_DECODE   0x04    /* Report Decode */
     85 #define REPORT_DMA      0x08    /* Report RX Dma */
     86 #define REPORT_CHANNEL  0x10    /* Report RX channel */
     87 
     88 typedef struct pwu_s {
     89     volatile uint32 pu_flags;       /* Flags this unit PU_F_XXX */
     90 #   define      PU_F_RUN    0x01
     91 #   define      PU_F_STOP   0x02
     92 #   define      PU_F_SYNC   0x04    /* Wake up request thread */
     93     sal_mutex_t pu_lock;            /* Syncronize updates */
     94     sal_spinlock_t  pu_spinlock;    /* Protect updates */
     95     int32   pu_channel;             /* RX channel list 1 << ch # */
     96 #   define  PU_CHANNEL(_c)  (1 << (_c))
     97     uint32  pu_report;      /* Reporting level */
     98     uint32  pu_dump_options;    /* Reporting level when dumping logs */
     99     COMPILER_DOUBLE pu_count_last;  /* Last count displayed */
    100     COMPILER_DOUBLE pu_count_time;  /* Last time count was displayed */
    101     sal_thread_t pu_pid;    /* pid this unit */
    102     sal_sem_t   pu_sema;        /* Sleep semaphore this unit */
    103     sal_sem_t   pu_sync;        /* Sync command semaphore */
    104 
    105     /*
    106      * pu_pending - a single linked list, where the head's prev pointer
    107      *                 points to the tail.
    108      * pu_ch_active  - pointers to DMA active on the given channel.
    109      */
    110 
    111     VOL pup_t   *pu_pending;    /* Pending interrupt servicing */
    112     VOL pup_t   *pu_ch_active[MAX_N_DMA_CHAN+1]; /* Active DMA operations */
    113     int     pu_ch_count[MAX_N_DMA_CHAN+1]; /* # received on channel */
    114     pup_t   *pu_log;        /* Last N packets - head is LRU */
    115     pup_t   *pu_log_free;       /* Last N packets - head is LRU */
    116     pup_t   *pup_list;      /* List of all PUPs for free */
    117     int     pu_log_cnt;     /* # packets on LOG list */
    118     int     pu_log_max;     /* Max # packets logged */
    119 #   define  PU_LOG_CNT  64  /* Default # log entries */
    120     uint32  pu_packet_received; /* total # received packets */
    121     int     pu_interval;        /* usec between pkt rcv & next dma */
    122 
    123     int         mode;                   /* What mode are we in */
    124 #define         PW_MODE_RX              0
    125 #define         PW_MODE_PMUX            2
    126 #define PW_INIT_STRINGS \
    127     "RX", \
    128     "PMUX"
    129     int         chan;
    130     int         rx_pri;
    131     uint32      rx_flags;
    132     int         pkt_size;
    133     bcm_rx_cfg_t  rx_cfg;
    134     int         rate;      /* Current global rate, pps */
    135     int         last_pkt_count;   /* How many pkts processed last wake */
    136 
    137     int         init_done;
    138     uint32      hdr_dump;         /* Header dump for cmicx */
    139 } pwu_t;
    140 
    141 char *ft_rmon_modes[2] = {PW_INIT_STRINGS};
    142 
    143 STATIC bcm_rx_t         ft_rmon_rx_callback(int unit, bcm_pkt_t *pkt,
    144                                        void *cookie);
    145 
    146 STATIC pup_t *          ft_rmon_pup_alloc(int unit);
    147 STATIC void             ft_rmon_pup_free(int unit, pup_t *pup);
    148 STATIC void             ft_rmon_dump_packet(int unit, pup_t *pup, uint32 report);
    149 STATIC int              ft_rmon_channel_config(int unit);
    150 STATIC void             ft_rmon_thread(void *up);
    151 STATIC void             ft_rmon_process_pending(int unit);
    152 STATIC cmd_result_t     ft_rmon_dump_log(int unit, int n);
    153 
    154 pwu_t   ft_rmon_units[SOC_MAX_NUM_DEVICES];
    155 
    156 STATIC void
    157 ft_rmon_init(int unit)
    158 {
    159     pwu_t   *pu = &ft_rmon_units[unit]; /* Control this unit */
    160 
    161     if (pu->init_done) {
    162         return;
    163     }
    164 
    165     sal_snprintf(ft_rmon_name[unit], sizeof(ft_rmon_name[unit]), "bcmFtRMon.%d", unit);
    166 
    167     /*
    168      * sync and lock semaphores are only created once, the others
    169      * are created and destroyed every time the packet watcher is
    170      * started and stopped.
    171      *
    172      * We need to check if they already exist to support the
    173      * pw reset option.
    174      */
    175     if (!pu->pu_sync) {
    176         pu->pu_sync = sal_sem_create("ft_rmon_sync", sal_sem_BINARY, 0);
    177     }
    178     if (!pu->pu_lock) {
    179         pu->pu_lock = sal_mutex_create("ft_rmon_lock");
    180     }
    181     if (!pu->pu_spinlock) {
    182         pu->pu_spinlock = sal_spinlock_create("ft_rmon_spinlock");
    183     }
    184 
    185     if (!pu->pu_sync || !pu->pu_lock || !pu->pu_spinlock) {
    186         cli_out("%s ERROR:  Could not allocate sync/lock\n", ft_rmon_name[unit]);
    187     }
    188     pu->chan = 0;
    189     pu->rx_pri = 100;
    190     pu->rx_flags = BCM_RCO_F_ALL_COS;
    191     pu->pkt_size = 10 * 1024;
    192 
    193     bcm_rx_cfg_get(unit, &pu->rx_cfg);
    194     pu->rate = pu->rx_cfg.global_pps;
    195 
    196     pu->init_done = TRUE;
    197 }
    198 
    199 STATIC int
    200 _ft_rmon_set_rate(int unit)
    201 {
    202     pwu_t   *pu = &ft_rmon_units[unit]; /* Control this unit */
    203     int          rv = BCM_E_NONE;
    204 
    205     /* Always calculate SOC interval in case modes are switched. */
    206     if (pu->rate <= 0) {
    207     pu->pu_interval = 1000000;
    208     pu->rate = 0;
    209     } else {
    210     pu->pu_interval = 1000000 / pu->rate;
    211     }
    212 
    213     switch (pu->mode) {
    214         case PW_MODE_RX:
    215             if ((rv = bcm_rx_rate_set(unit, pu->rate)) < 0) {
    216                 cli_out("PW RX rate set error: %s.\n", bcm_errmsg(rv));
    217             }
    218             /* Then set the burst size to equal the rate */
    219             if ((rv = bcm_rx_burst_set(unit, pu->rate)) < 0) {
    220                 cli_out("PW RX burst set error: %s.\n", bcm_errmsg(rv));
    221             }
    222             break;
    223         default:
    224             break;
    225     }
    226 
    227     return rv;
    228 }
    229 
    230 #define PW_LOCK(_u) sal_mutex_take(ft_rmon_units[_u].pu_lock, \
    231                        sal_mutex_FOREVER)
    232 #define PW_UNLOCK(_u)   sal_mutex_give(ft_rmon_units[_u].pu_lock)
    233 #define PW_SPIN_LOCK(_u)    sal_spinlock_lock(ft_rmon_units[_u].pu_spinlock)
    234 #define PW_SPIN_UNLOCK(_u)  sal_spinlock_unlock(ft_rmon_units[_u].pu_spinlock)
    235 
    236 int
    237 ft_rmon_start(int unit, int sync)
    238 /*
    239  * Function:    ft_rmon_start
    240  * Purpose: Start the ipfix packet monitor
    241  * Parameters:  unit - unit to start.
    242  *      sync - if true, wait for mon to start.
    243  * Returns: 0 - success, -1 failed.
    244  */
    245 {
    246     pwu_t   *pu = &ft_rmon_units[unit]; /* Control this unit */
    247 
    248     ft_rmon_init(unit);
    249     if (pu->pu_sync == NULL || pu->pu_lock == NULL || pu->pu_spinlock == NULL) {
    250         return -1;
    251     }
    252 
    253     sal_memset(pu->pu_ch_active, 0, sizeof(pu->pu_ch_active));
    254     sal_memset(pu->pu_ch_count, 0, sizeof(pu->pu_ch_count));
    255 
    256     pu->pu_pending = NULL;
    257     pu->pu_log = NULL;
    258     pu->pu_log_free = NULL;
    259     pu->pu_log_cnt = 0;
    260 
    261         if (ft_rmon_channel_config(unit) < 0) {
    262             return -1;
    263         }
    264 
    265     pu->pu_sema = sal_sem_create("ft_rmon_thread", sal_sem_BINARY, 0);
    266     if (pu->pu_sema == 0) {
    267         return -1;
    268     }
    269 
    270     pu->pu_flags |= PU_F_RUN;
    271     if (sync) {
    272         pu->pu_flags |= PU_F_SYNC;
    273     }
    274 
    275     pu->pu_pid =
    276         sal_thread_create(ft_rmon_name[unit], SAL_THREAD_STKSZ,
    277                           soc_property_get(unit, spn_DIAG_PW_THREAD_PRI, 100),
    278               ft_rmon_thread, INT_TO_PTR(unit));
    279 
    280     if (pu->pu_pid == SAL_THREAD_ERROR) {
    281         cli_out("%s: Unable to start task\n", ft_rmon_name[unit]);
    282         sal_sem_destroy(pu->pu_sema);
    283         pu->pu_sema = 0;
    284         pu->pu_flags &= PU_F_RUN|PU_F_SYNC;
    285         return -1;
    286     }
    287 
    288     pu->pu_count_last = 0;
    289     pu->pu_count_time = SAL_TIME_DOUBLE();
    290 
    291     pu->pu_packet_received = 0;
    292 
    293     if (sync) {
    294         if (sal_sem_take(pu->pu_sync, sal_sem_FOREVER)) {
    295             cli_out("%s: Failed to wait for start\n", ft_rmon_name[unit]);
    296             return -1;
    297         }
    298     }
    299 
    300     return 0;
    301 }
    302 
    303 cmd_result_t
    304 ft_rmon_stop(int unit, int sync)
    305 /*
    306  * Function:    ft_rmon_stop
    307  * Purpose: Stop the ipfix packet monitor
    308  * Parameters:  unit - unit to stop.
    309  *      sync - if true, wait for rmon to finish.
    310  * Returns: 0 - success, -1 failed.
    311  */
    312 {
    313     pwu_t   *pu = &ft_rmon_units[unit]; /* Control this unit */
    314     soc_timeout_t  to;
    315     sal_usecs_t     ft_rmon_timeout;
    316 
    317     ft_rmon_timeout = soc_property_get(unit, spn_CDMA_TIMEOUT_USEC, 10000000);
    318 
    319     pu->pu_flags |= PU_F_STOP;
    320     if (sync) {
    321     pu->pu_flags |= PU_F_SYNC;
    322     }
    323     sal_sem_give(pu->pu_sema);
    324     soc_timeout_init(&to, ft_rmon_timeout, 0);
    325 
    326     /* Check for ft_rmon_thread exit */
    327     while (pu->pu_pid != SAL_THREAD_ERROR) {
    328          /* Handle the case of ft_rmon_thread not exiting */
    329          if (soc_timeout_check(&to)) {
    330              cli_out("ft_rmon_stop: ft_rmon_thread did not exit\n");
    331              pu->pu_pid = SAL_THREAD_ERROR;
    332              break;
    333          }
    334 
    335          sal_usleep(80000);
    336     }
    337 
    338     if  (pu->pu_pid == SAL_THREAD_ERROR) {
    339         /* Abnormal thread exit: Free semaphore resource */
    340     /*    coverity[check_after_deref]    */
    341         if (pu->pu_sema) {
    342             /* Must check, because may have been destroyed by ft_rmon_exit */
    343             sal_sem_destroy(pu->pu_sema);
    344             pu->pu_sema = 0;
    345         }
    346     }
    347 
    348     if (sync) {
    349         (void)sal_sem_take(pu->pu_sync, sal_sem_FOREVER);
    350     } else {
    351         cli_out("%s: Termination requested...\n", ft_rmon_name[unit]);
    352     }
    353     return CMD_OK;
    354 }
    355 
    356 int
    357 ft_rmon_running(int unit)
    358 /*
    359  * Function:    ft_rmon_running
    360  * Purpose: Determine if ipfix rmon is running for the specified
    361  *      unit.
    362  * Parameters:  unit - unit #
    363  * Returns: 0 - not running, !0 - running
    364  */
    365 {
    366     return ft_rmon_units[unit].pu_flags & PU_F_RUN;
    367 }
    368 
    369 STATIC  void
    370 ft_rmon_exit(int unit, int stat)
    371 /*
    372  * Function:    ft_rmon_exit
    373  * Purpose: Exit a ftrmon thread.
    374  * Parameters:  unit - unit #.
    375  *      stat - exit status (passed to exit).
    376  * Returns: Does not return.
    377  *
    378  * Notes:   ASSUMES LOCK held on entry, released in this routine
    379  */
    380 {
    381     pwu_t *pu = &ft_rmon_units[unit];
    382     int rv;
    383     char thread_name[SAL_THREAD_NAME_MAX_LEN];
    384     sal_thread_t    thread;
    385 
    386     thread = sal_thread_self();
    387     thread_name[0] = 0;
    388     sal_thread_name(thread, thread_name, sizeof (thread_name));
    389 
    390     switch (pu->mode) {
    391         case PW_MODE_RX:
    392             /* ft_rmon_exit() is called holding the lock. Give it up
    393              * momentarily while we stop the RX task.
    394              */
    395             PW_UNLOCK(unit);
    396             if ((rv = bcm_rx_stop(unit, NULL)) < 0) {
    397                 cli_out("FtRemoteMon stop error: Cannot stop RX: %s.\n",
    398                         bcm_errmsg(rv));
    399             }
    400             if ((rv = bcm_rx_queue_unregister(unit, BCM_RX_COS_ALL,
    401                                               ft_rmon_rx_callback, pu->rx_pri))
    402                        < 0) {
    403                 cli_out("FtRemoteMon stop error: Cannot unregister handler: %s.\n",
    404                         bcm_errmsg(rv));
    405             }
    406             PW_LOCK(unit);
    407 
    408             break;
    409         default:
    410             break;
    411     }
    412 
    413     if (pu->pu_sema) {
    414     sal_sem_destroy(pu->pu_sema);
    415     pu->pu_sema = 0;
    416     }
    417 
    418     pu->pu_pid = SAL_THREAD_ERROR;
    419 
    420     /* Put logs on the free list - not fast but .... oh well */
    421 
    422     if (pu->pu_log != NULL) {
    423     pu->pu_log->pup_prev->pup_next = NULL; /* NUll list */
    424     while (pu->pu_log != NULL) {
    425         pup_t   *pup = pu->pu_log->pup_next;
    426         ft_rmon_pup_free(unit, pu->pu_log);
    427         pu->pu_log = pup;
    428     }
    429     }
    430 
    431     /* Now free the free list */
    432 
    433     while (pu->pu_log_free) {
    434     pup_t   *pup = pu->pu_log_free;
    435     pu->pu_log_free = pup->pup_next;
    436     }
    437     if (pu->pup_list) {
    438         sal_free(pu->pup_list);
    439     }
    440 
    441     if (pu->pu_flags & PU_F_SYNC) {
    442     sal_sem_give(pu->pu_sync);
    443     } else {
    444         LOG_VERBOSE(BSL_LS_SOC_COMMON,
    445                     (BSL_META_U(unit,
    446                                 "FtRemoteMon-Daemon[%d]: Exiting\n"), unit));
    447     }
    448 
    449     pu->pu_flags = 0;
    450 
    451     PW_UNLOCK(unit);   
    452     if (stat < 0) {
    453         LOG_ERROR(BSL_LS_SOC_PKT,
    454                   (BSL_META_U(unit,
    455                               "AbnormalThreadExit:%s\n"), thread_name));
    456     }
    457 
    458     sal_thread_exit(stat);
    459 }
    460 
    461 /* Start the ipfix packet rmon operation depending on the mode */
    462 STATIC int
    463 _ft_rmon_start_op(int unit)
    464 {
    465     pwu_t       *pu = &ft_rmon_units[unit];
    466     int pkt_size;
    467     int rv = BCM_E_NONE;
    468 
    469     switch (pu->mode) {
    470     case PW_MODE_RX:
    471         pu->rx_cfg.global_pps = pu->rate;
    472 
    473         /*
    474          * Allow the ipfix rmon to run in truncating mode
    475          * by allocating smaller Rx buffers and accepting
    476          * oversized packets on all Rx DMA channels.
    477          */
    478         pkt_size = soc_property_get(unit, spn_DIAG_PW_BUFFER_SIZE, -1);
    479 
    480         if (pkt_size >= 68) {
    481             int chan;
    482             dma_chan_t  dma_chan;
    483             pu->rx_cfg.pkt_size = pkt_size;
    484 
    485             if (soc_feature(unit, soc_feature_cmicx)) {
    486                 dma_chan = BCM_CMICX_RX_CHANNELS;
    487             } else {
    488                 dma_chan = BCM_RX_CHANNELS;
    489             }
    490 
    491             for (chan = 0; chan < dma_chan; chan++) {
    492                 pu->rx_cfg.chan_cfg[chan].flags |= BCM_RX_F_OVERSIZED_OK;
    493             }
    494         }
    495 
    496         if ((rv = bcm_rx_start(unit, &pu->rx_cfg)) < 0) {
    497             return rv;
    498         }
    499 
    500         if ((rv = bcm_rx_queue_register(unit, "RX CMD", BCM_RX_COS_ALL,
    501                       ft_rmon_rx_callback, pu->rx_pri, NULL, pu->rx_flags)) < 0) {
    502             return rv;
    503         }
    504         break;
    505     default:
    506         assert("Unknown pkt watcher mode");
    507         break;
    508     }
    509 
    510     return rv;
    511 }
    512 
    513 STATIC void
    514 ft_rmon_thread(void *up)
    515 /*
    516  * Function:    ft_rmon_thread
    517  * Purpose:     Waits for packets to arrive destined for the CPU and
    518  *              saves them in a queue.
    519  * Parameters:  unit - SOC unit #
    520  * Returns:     Does not return.
    521  */
    522 {
    523     int         unit = PTR_TO_INT(up);
    524     int         i;
    525     pwu_t       *pu = &ft_rmon_units[unit];
    526     int         rv;
    527     int         pup_count;
    528     pup_t      *pup;
    529 
    530     PW_LOCK(unit);
    531 
    532     /* Allocate packet pointer array */
    533 
    534     if (0 == pu->pu_log_max) {
    535         pu->pu_log_max = PW_COUNT_DEFAULT;
    536     }
    537 
    538     pup_count = pu->pu_log_max;
    539 
    540     /* Bump up pup_count to be twice the log size so pups will
    541      * be available even when log queue is full.
    542      */
    543     pup_count += pu->pu_log_max;
    544 
    545     pu->pup_list = sal_alloc(sizeof(pup_t) * pup_count, "FtRemoteMon-pup");
    546     if (pu->pup_list == NULL) {
    547         ft_rmon_exit(unit, -1);
    548     }
    549     /* No forwaqrding null. If the allocation failed, the call to ft_rmon_exit will end the process and we sould never reach here. */
    550     /* coverity[var_deref_model:FALSE] */
    551     sal_memset(pu->pup_list, 0, sizeof(pup_t) * pup_count);
    552 
    553     for (i = 0; i < pup_count; i++) {
    554 
    555         pup = &pu->pup_list[i];
    556 
    557         ft_rmon_pup_free(unit, pup);         /* Put on free list */
    558     }
    559 
    560     if (pu->pu_flags & PU_F_SYNC) {
    561         pu->pu_flags &= ~PU_F_SYNC;
    562         sal_sem_give(pu->pu_sync);
    563     } else {
    564         cli_out("FtRemoteMon-daemon[%d] -- Started\n", unit);
    565     }
    566 
    567     /* Kick Start channels */
    568     if ((rv = _ft_rmon_start_op(unit)) < 0) {
    569         cli_out("FtRemoteMon rx mode: Cannot start %s: %s.\n", ft_rmon_modes[pu->mode],
    570                 bcm_errmsg(rv));
    571         ft_rmon_exit(unit, -1);
    572     }
    573 
    574     PW_UNLOCK(unit);
    575 
    576     /*
    577      * Check if there are any actions for us.
    578      */
    579     while (1) {
    580         int     sem_rv;
    581 
    582         sem_rv = sal_sem_take(ft_rmon_units[unit].pu_sema, sal_sem_FOREVER);
    583 
    584         if (sem_rv < 0) {
    585             cli_out("Failed sem_take, exiting\n");
    586             ft_rmon_exit(unit, -1);
    587         }
    588 
    589         PW_LOCK(unit);                  /* Block log dumps */
    590 
    591         if (pu->pu_flags & PU_F_STOP) { /* Time to exit */
    592             ft_rmon_exit(unit, 0);
    593         }
    594 
    595         ft_rmon_process_pending(unit);
    596 
    597         PW_UNLOCK(unit);
    598     }
    599 
    600     ft_rmon_exit(unit, 0);
    601 }
    602 
    603 STATIC int
    604 ft_rmon_channel_config(int unit)
    605 /*
    606  * Function:    ft_rmon_channel_config
    607  * Purpose: Configure DMA RX channels for PW.
    608  * Parameters:  unit - unit to configure.
    609  * Returns: 0 - success
    610  *      -1 - failed.
    611  */
    612 {
    613     pwu_t   *pu = &ft_rmon_units[unit]; /* Control this unit */
    614     dma_chan_t  tx, i;
    615     int     rv = SOC_E_NONE;
    616     dma_chan_t  dma_chan;
    617 
    618     if (pu->pu_channel == 0) {      /* Use default */
    619     return 0;
    620     }
    621 
    622     if (soc_feature(unit, soc_feature_cmicx)) {
    623         dma_chan = CMICX_N_DMA_CHAN;
    624     } else {
    625         dma_chan = N_DMA_CHAN;
    626     }
    627 
    628     /* Pick lowest # free channel for TX default */
    629     tx = -1;
    630     for (i = 0; i < dma_chan; i++) {
    631     if (pu->pu_channel & (1 << i)) {
    632         rv = soc_dma_chan_config(unit, i, DV_RX, SOC_DMA_F_INTR);
    633         if (rv < 0) {
    634         cli_out("%s: DMA channel configuration failed: %s\n",
    635                         ft_rmon_name[unit], soc_errmsg(rv));
    636         }
    637     } else if (tx == -1) {
    638         tx = i;
    639     }
    640     }
    641 
    642     if ((tx == -1) ||
    643     ((rv = soc_dma_chan_config(unit, tx, DV_TX,
    644                    SOC_DMA_F_INTR |SOC_DMA_F_DEFAULT)) < 0)) {
    645     cli_out("%s: Unable to configure TX DMA channel: %s\n",
    646                 ft_rmon_name[unit],
    647                 tx == -1 ? "No remaining channels" : soc_errmsg(rv));
    648 
    649     rv = soc_dma_init(unit);
    650     cli_out("%s: Unable to re-initialize DMA: %s\n",
    651                 ft_rmon_name[unit],
    652                 soc_errmsg(rv));
    653 
    654     return -1;
    655     }
    656     return 0;
    657 }
    658 
    659 static const parse_pm_t ft_rmon_report_table[] = {
    660     {"Count",   REPORT_COUNT},
    661     {"DECode",  REPORT_DECODE},
    662     {"Raw",     REPORT_RAW},
    663     {"DMA",     REPORT_DMA},
    664     {"CHannel", REPORT_CHANNEL},
    665     {"@ALL",    ~0},
    666     {"@*",  ~0},
    667     {NULL,  0}
    668 };
    669 
    670 static const parse_pm_t ft_rmon_channel_table[] = {
    671     {"0",   1 << 0},
    672     {"1",   1 << 1},
    673     {"2",   1 << 2},
    674     {"3",   1 << 3},
    675     {"4",   1 << 4},
    676     {"5",   1 << 5},
    677     {"6",   1 << 6},
    678     {"7",   1 << 7},
    679     {NULL,  0}
    680 };
    681 
    682 /****************************************************************
    683  *
    684  * Common ipfix rmon routines
    685  */
    686 
    687 
    688 STATIC  pup_t *
    689 ft_rmon_pup_alloc(int unit)
    690 /*
    691  * Function:    ft_rmon_alloc
    692  * Purpose:     Alloc a pup off the free list.
    693  * Parameters:  unit - unit #
    694  * Returns:     Pointer to pup.
    695  */
    696 {
    697     pwu_t       *pu = &ft_rmon_units[unit];
    698     pup_t       *pup;
    699 
    700     PW_LOCK(unit);
    701     pup = pu->pu_log_free;
    702     if (pup) {
    703         pu->pu_log_free = pup->pup_next;
    704     }
    705     PW_UNLOCK(unit);
    706 
    707     return(pup);
    708 }
    709 
    710 STATIC  void
    711 ft_rmon_pup_free(int unit, pup_t *pup)
    712 /*
    713  * Function:    ft_rmon_pup_free
    714  * Purpose:     Put a pup on the free list.
    715  * Parameters:  unit - unit #
    716  *              pup - pointer to pup to free.
    717  * Returns:     Nothing.
    718  */
    719 {
    720     pwu_t       *pu = &ft_rmon_units[unit];
    721 
    722     pup->pup_next = pu->pu_log_free;
    723     pu->pu_log_free = pup;
    724 
    725     if (pu->mode == PW_MODE_RX) {
    726         bcm_rx_free(unit, pup->rx_pkt.alloc_ptr);
    727     }
    728 }
    729 
    730 STATIC void
    731 ft_rmon_dump_start(int unit, char *pfx, pup_t *pup, uint32 report,
    732               int chan, int count)
    733 {
    734     char        *channel;
    735 
    736     if (!report) {
    737         return;
    738     }
    739 
    740     cli_out("\n");
    741 
    742     if (report & REPORT_CHANNEL) {
    743         switch (chan) {
    744         case -1:        channel = "";           break;
    745         case 0:         channel = "-chn0";      break;
    746         case 1:         channel = "-chn1";      break;
    747         case 2:         channel = "-chn2";      break;
    748         case 3:         channel = "-chn3";      break;
    749         case 4:         channel = "-chn4";      break;
    750         case 5:         channel = "-chn5";      break;
    751         case 6:         channel = "-chn6";      break;
    752         case 7:         channel = "-chn7";      break;
    753         default:        channel = "-----";      break;
    754         }
    755     } else {
    756         channel = "";
    757     }
    758 
    759     sal_sprintf(pfx, "Packet[%d]%s: ", pup->pup_seqno, channel);
    760 
    761     if ((report & REPORT_COUNT) && (count >= 0)) {
    762         cli_out("%sTotal %d\n", pfx, count);
    763     }
    764 
    765 }
    766 
    767 
    768 extern int
    769 bcma_ft_setid_template_id_get(int unit, uint16 setid,
    770                               bcm_flowtracker_export_template_t *template_id);
    771 
    772 #define BCMI_FT_XLATE_ELEM(_name, _size) \
    773         bcmFlowtrackerExportElementType##_name, \
    774         _size, \
    775         #_name
    776 
    777 
    778 typedef struct bcma_ft_export_elements_map_s {
    779     bcm_flowtracker_export_element_type_t export_element;
    780     int default_data_size;
    781     char element_name[BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX];
    782 } bcma_ft_export_elements_map_t;
    783 
    784 
    785 static bcma_ft_export_elements_map_t bcma_ft_export_elements_map[] = {
    786             {   BCMI_FT_XLATE_ELEM(SrcIPv4,            4  )   },
    787             {   BCMI_FT_XLATE_ELEM(DstIPv4,            4  )   },
    788             {   BCMI_FT_XLATE_ELEM(L4SrcPort,          2  )   },
    789             {   BCMI_FT_XLATE_ELEM(L4DstPort,          2  )   },
    790             {   BCMI_FT_XLATE_ELEM(SrcIPv6,            16 )   },
    791             {   BCMI_FT_XLATE_ELEM(DstIPv6,            16 )   },
    792             {   BCMI_FT_XLATE_ELEM(IPProtocol,         1  )   },
    793             {   BCMI_FT_XLATE_ELEM(PktCount,           4  )   },
    794             {   BCMI_FT_XLATE_ELEM(ByteCount,          4  )   },
    795             {   BCMI_FT_XLATE_ELEM(VRF,                2  )   },
    796             {   BCMI_FT_XLATE_ELEM(TTL,                1  )   },
    797             {   BCMI_FT_XLATE_ELEM(IPLength,           2  )   },
    798             {   BCMI_FT_XLATE_ELEM(IP6Length,          2  )   },
    799             {   BCMI_FT_XLATE_ELEM(TcpWindowSize,      2  )   },
    800             {   BCMI_FT_XLATE_ELEM(DosAttack,          4  )   },
    801             {   BCMI_FT_XLATE_ELEM(VxlanNetworkId,     3  )   },
    802             {   BCMI_FT_XLATE_ELEM(NextHeader,         1  )   },
    803             {   BCMI_FT_XLATE_ELEM(HopLimit,           1  )   },
    804             {   BCMI_FT_XLATE_ELEM(InnerSrcIPv4,       4  )   },
    805             {   BCMI_FT_XLATE_ELEM(InnerDstIPv4,       4  )   },
    806             {   BCMI_FT_XLATE_ELEM(InnerL4SrcPort,     2  )   },
    807             {   BCMI_FT_XLATE_ELEM(InnerL4DstPort,     2  )   },
    808             {   BCMI_FT_XLATE_ELEM(InnerSrcIPv6,       16 )   },
    809             {   BCMI_FT_XLATE_ELEM(InnerDstIPv6,       16 )   },
    810             {   BCMI_FT_XLATE_ELEM(InnerIPProtocol,    1  )   },
    811             {   BCMI_FT_XLATE_ELEM(InnerTTL,           1  )   },
    812             {   BCMI_FT_XLATE_ELEM(InnerIPLength,      2  )   },
    813             {   BCMI_FT_XLATE_ELEM(InnerNextHeader,    1  )   },
    814             {   BCMI_FT_XLATE_ELEM(InnerHopLimit,      1  )   },
    815             {   BCMI_FT_XLATE_ELEM(InnerIP6Length,     2  )   },
    816             {   BCMI_FT_XLATE_ELEM(TcpFlags,           1  )   },
    817             {   BCMI_FT_XLATE_ELEM(OuterVlanTag,       2  )   },
    818             {   BCMI_FT_XLATE_ELEM(FlowtrackerGroup,   2  )   },
    819             {   BCMI_FT_XLATE_ELEM(ExportReasons,      2  )   },
    820             {   BCMI_FT_XLATE_ELEM(ExportFlags,        1  )   },
    821             {   BCMI_FT_XLATE_ELEM(Reserved,           1  )   },
    822             {   BCMI_FT_XLATE_ELEM(TimestampNewLearn,     6  )   },
    823             {   BCMI_FT_XLATE_ELEM(TimestampFlowStart,    6  )   },
    824             {   BCMI_FT_XLATE_ELEM(TimestampFlowEnd,      6  )   },
    825             {   BCMI_FT_XLATE_ELEM(TimestampCheckEvent1, 6  )   },
    826             {   BCMI_FT_XLATE_ELEM(TimestampCheckEvent2, 6  )   },
    827             {   BCMI_FT_XLATE_ELEM(InnerDosAttack,        4  )   },
    828             {   BCMI_FT_XLATE_ELEM(TunnelClass,           3  )   },
    829             {   BCMI_FT_XLATE_ELEM(FlowtrackerCheck,      4  )   },
    830 };
    831 
    832 STATIC int
    833 bcma_ft_export_elem_name_get(int unit,
    834                              bcm_flowtracker_export_element_type_t info_elem,
    835                              int *data_size,
    836                              char *elem_name)
    837 {
    838     int ix;
    839 
    840     for (ix = 0; ix < COUNTOF(bcma_ft_export_elements_map); ix++) {
    841         if (bcma_ft_export_elements_map[ix].export_element == info_elem) {
    842             if (elem_name) {
    843                 sal_strncpy(elem_name, bcma_ft_export_elements_map[ix].element_name,
    844                     BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX);
    845             }
    846             if (data_size) {
    847                 *data_size = bcma_ft_export_elements_map[ix].default_data_size;
    848             }
    849             break;
    850         }
    851     }
    852 
    853     if (ix == COUNTOF(bcma_ft_export_elements_map)) {
    854         return BCM_E_PARAM;
    855     }
    856 
    857     return BCM_E_NONE;
    858 }
    859 
    860 void
    861 format_ts(char buf[20], uint8 *ts)
    862 {
    863     sal_sprintf(buf, "%x%x%x%x%x%x",
    864         (uint8)ts[0], (uint8)ts[1], (uint8)ts[2],
    865         (uint8)ts[3], (uint8)ts[4], (uint8)ts[5]);
    866 }
    867 
    868 
    869 STATIC int
    870 bcma_ipfix_data_record_print(int unit,
    871                              int set_length,
    872                              uint8 *data_set,
    873                              int num_elems,
    874                              bcm_flowtracker_export_element_info_t *list_elems)
    875 {
    876     int ix, ex;
    877     char elem_name[BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX];
    878     uint8 u8;
    879     uint16 u16;
    880     uint32 u32;
    881     uint8 *data, *data_tmp;
    882     int data_size;
    883     bcm_ip6_t ip6;
    884     char ip_str[IP6ADDR_STR_LEN];
    885     bcm_flowtracker_export_element_info_t *elem;
    886     uint8 ts[6];
    887     char ts_str[20];
    888 
    889 
    890     data = data_set;
    891 
    892     if (0) {
    893         int ix;
    894         for (ix = 0; ix < (set_length - 4); ix+=8) {
    895             cli_out("%04d: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
    896                     (ix/8), data[ix], data[ix+1], data[ix+2], data[ix+3],
    897                             data[ix+4], data[ix+5], data[ix+6], data[ix+7]);
    898         }
    899     }
    900 
    901 
    902     for (ex = 0; ex <  num_elems; ex++) {
    903         elem = &(list_elems[ex]);
    904         data_tmp = data;
    905 
    906         if (BCM_FAILURE(bcma_ft_export_elem_name_get(unit, elem->element, &data_size, elem_name))) {
    907             cli_out("Element name not found: elem = %d\n", elem->element);
    908             return -1;
    909         }
    910         data_size = elem->data_size;
    911 
    912         switch (elem->element) {
    913             case bcmFlowtrackerExportElementTypeSrcIPv4:
    914             case bcmFlowtrackerExportElementTypeDstIPv4:
    915             case bcmFlowtrackerExportElementTypeInnerSrcIPv4:
    916             case bcmFlowtrackerExportElementTypeInnerDstIPv4:
    917                 SHR_PKT_UNPACK_U32(data_tmp, u32);
    918                 format_ipaddr(ip_str, u32);
    919                 cli_out("Info Element:: %02d (%20s) | Size: %02d | Value: (%s)\n", elem->element, elem_name, elem->data_size, ip_str);
    920                 break;
    921             case bcmFlowtrackerExportElementTypeSrcIPv6:
    922             case bcmFlowtrackerExportElementTypeDstIPv6:
    923             case bcmFlowtrackerExportElementTypeInnerSrcIPv6:
    924             case bcmFlowtrackerExportElementTypeInnerDstIPv6:
    925                 for (ix = 0; ix < 16; ix++) {
    926                     SHR_PKT_UNPACK_U8(data_tmp, u8);
    927                     ip6[ix] = u8;
    928                 }
    929                 format_ip6addr(ip_str, ip6);
    930                 cli_out("Info Element:: %02d (%20s) | Size: %02d | Value: (%s)\n", elem->element, elem_name, elem->data_size, ip_str);
    931                 break;
    932             case bcmFlowtrackerExportElementTypeTimestampNewLearn:
    933             case bcmFlowtrackerExportElementTypeTimestampFlowStart:
    934             case bcmFlowtrackerExportElementTypeTimestampFlowEnd:
    935             case bcmFlowtrackerExportElementTypeTimestampCheckEvent1:
    936             case bcmFlowtrackerExportElementTypeTimestampCheckEvent2:
    937                 for (ix = 0; ix < 6; ix++) {
    938                     SHR_PKT_UNPACK_U8(data_tmp, u8);
    939                     ts[ix] = u8;
    940                 }
    941                 sal_memset(ts_str, 0, 20);
    942                 format_ts(ts_str, ts);
    943                 cli_out("Info Element:: %02d (%20s) | Size: %02d | Value: (%s)\n", elem->element, elem_name, data_size, ts_str);
    944                 break;
    945 
    946             case bcmFlowtrackerExportElementTypeReserved:
    947                 cli_out("Info Element:: %02d (%20s) | Size: %02d | Value: (%s)\n", elem->element, elem_name, elem->data_size, "????");
    948                 break;
    949             default:
    950                 switch (data_size) {
    951                     case 1:
    952                         SHR_PKT_UNPACK_U8(data_tmp, u8);
    953                         cli_out("Info Element:: %02d (%20s) | Size: %02d | Value: 0x%02x(%02d)\n", elem->element, elem_name, elem->data_size, u8, u8);
    954                         break;
    955                     case 2:
    956                         SHR_PKT_UNPACK_U16(data_tmp, u16);
    957                         cli_out("Info Element:: %02d (%20s) | Size: %02d | Value: 0x%04x(%04d)\n", elem->element, elem_name, elem->data_size, u16, u16);
    958                         break;
    959                     case 3:
    960                         SHR_PKT_UNPACK_U8(data_tmp, u8);
    961                         SHR_PKT_UNPACK_U16(data_tmp, u16);
    962                         u32 = ((u8 << 16) | u16);
    963                         cli_out("Info Element:: %02d (%20s) | Size: %02d | Value: 0x%06x(%06d)\n", elem->element, elem_name, elem->data_size, u32, u32);
    964                         break;
    965                     case 4:
    966                         SHR_PKT_UNPACK_U32(data_tmp, u32);
    967                         cli_out("Info Element:: %02d (%20s) | Size: %02d | Value: 0x%08x(%08d)\n", elem->element, elem_name, elem->data_size, u32, u32);
    968                         break;
    969                     default:
    970                         break;
    971 
    972                 }
    973         }
    974 
    975         data += (elem->data_size);
    976     }
    977 
    978     return BCM_E_NONE;
    979 }
    980 
    981 
    982 int bcma_ft_ipfix_print_record(int unit, int set_c, int payload_length, uint8 *data)
    983 {
    984     uint8 *data_set;
    985     uint16 set_id, set_length;
    986     int ix, num_els;
    987     bcm_flowtracker_export_template_t template_id;
    988     bcm_flowtracker_export_element_info_t *elem_list;
    989     char elem_name[BCMI_FT_EXPORT_ELEMENT_NAME_LEN_MAX];
    990     int rv = BCM_E_NONE;
    991 
    992     data_set = data;
    993     SHR_PKT_UNPACK_U16(data_set, set_id);
    994     SHR_PKT_UNPACK_U16(data_set, set_length);
    995     if (set_length == 0) {
    996         cli_out("Data Set with invalid length: id= %02d len = %02d\n", set_id, set_length);
    997         return -1;
    998     }
    999 
   1000     cli_out("*************************************************\n");
   1001     cli_out("IPFIX data set # %02d, set_id = %02d (0x%02x) record length = %02d\n",
   1002             set_c, set_id, set_id, set_length);
   1003 
   1004     rv = bcma_ft_setid_template_id_get(unit, set_id, &template_id);
   1005     if (BCM_FAILURE(rv)) {
   1006         cli_out("No template created with set_id = %d\n", set_id);
   1007         return -1;
   1008     }
   1009 
   1010     rv = bcm_flowtracker_export_template_get(unit, template_id,
   1011                                              &set_id, 0, NULL, &num_els);
   1012     if (BCM_FAILURE(rv)) {
   1013         cli_out("template_get count failed with rv = %d\n", rv);
   1014         return -1;
   1015     }
   1016 
   1017 
   1018     elem_list = sal_alloc((sizeof(bcm_flowtracker_export_element_info_t) * num_els), "template_get element list");
   1019 
   1020     rv = bcm_flowtracker_export_template_get(unit, template_id,
   1021                                              &set_id, num_els,
   1022                                              elem_list, &num_els);
   1023     if (BCM_FAILURE(rv)) {
   1024         cli_out("template_get list failed with rv = %d\n", rv);
   1025         return -1;
   1026     }
   1027 
   1028     cli_out("Template Id matching with set id %d is %d and num of elements = %d\n", set_id, template_id, num_els);
   1029     for (ix = 0; ix < num_els; ix++) {
   1030 
   1031         rv = bcma_ft_export_elem_name_get(unit, elem_list[ix].element, NULL, elem_name);
   1032         BCM_IF_ERROR_RETURN(rv);
   1033         if (elem_list[ix].element == bcmFlowtrackerExportElementTypeFlowtrackerCheck) {
   1034             cli_out("Template Id: %2d Info Element(%2d) = %2d (%20s) Size = %02d"
   1035                     " (0x%x)\n", template_id, ix, elem_list[ix].element,
   1036                     elem_name, elem_list[ix].data_size, elem_list[ix].check_id);
   1037         } else {
   1038             cli_out("Template Id: %2d Info Element(%2d) = %2d (%20s) Size = %02d\n",
   1039                     template_id, ix, elem_list[ix].element, elem_name, elem_list[ix].data_size);
   1040         }
   1041     }
   1042 
   1043     rv = bcma_ipfix_data_record_print(unit, set_length, data_set,
   1044                                       num_els, elem_list);
   1045     if (BCM_FAILURE(rv)) {
   1046         cli_out("ipfix data_set parsing failed for set = %d\n", set_id);
   1047         return -1;
   1048     }
   1049 
   1050     cli_out("*************************************************\n");
   1051 
   1052 
   1053     return BCM_E_NONE;
   1054 }
   1055 
   1056 
   1057 int bcma_ft_ipfix_template_print(int unit, int payload_length, uint8 *payload_data)
   1058 {
   1059     uint16 d16;
   1060     uint32 d32;
   1061     uint16 set_id;
   1062     int ix, set_c, set_length;
   1063     uint8 *data, *data_set;
   1064 
   1065     data = payload_data;
   1066 
   1067     if (0) {
   1068         for (ix = 0; ix < (payload_length - 4); ix+=8) {
   1069             cli_out("%04d: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
   1070                     (ix/8), data[ix], data[ix+1], data[ix+2], data[ix+3],
   1071                             data[ix+4], data[ix+5], data[ix+6], data[ix+7]);
   1072         }
   1073     }
   1074 
   1075     /* Print ipfix header. */
   1076     cli_out("*************************************************\n");
   1077     SHR_PKT_UNPACK_U16(data, d16);
   1078     cli_out("IPFIX version = %02d (0x%02x)\n", d16, d16);
   1079 
   1080     SHR_PKT_UNPACK_U16(data, d16);
   1081     cli_out("IPFIX message length = %02d (0x%02x)\n", d16, d16);
   1082 
   1083     SHR_PKT_UNPACK_U32(data, d32);
   1084     cli_out("IPFIX export timestamp = %02d (0x%02x)\n", d32, d32);
   1085 
   1086     SHR_PKT_UNPACK_U32(data, d32);
   1087     cli_out("IPFIX sequence number = %02d (0x%02x)\n", d32, d32);
   1088 
   1089     SHR_PKT_UNPACK_U32(data, d32);
   1090     cli_out("IPFIX observation domain id = %02d (0x%02x)\n", d32, d32);
   1091     cli_out("*************************************************\n");
   1092 
   1093     payload_length -= 16;
   1094 
   1095     set_c = 1;
   1096     while (payload_length > 0) {
   1097         data_set = data;
   1098         SHR_PKT_UNPACK_U16(data_set, set_id);
   1099         SHR_PKT_UNPACK_U16(data_set, set_length);
   1100 
   1101         data_set = data;
   1102         if (bcma_ft_ipfix_print_record(unit, set_c, set_length, data_set) != BCM_E_NONE) {
   1103             cli_out("set_id:%d, set:%d:ipfix parsing failed\n", set_id, set_c);
   1104             return BCM_E_FAIL;
   1105         }
   1106 
   1107         set_c++;
   1108         data += set_length;
   1109         payload_length -= set_length;
   1110     }
   1111 
   1112     return BCM_E_NONE;
   1113 
   1114 }
   1115 
   1116 STATIC char *_ft_rmon_reason_names[bcmRxReasonCount] = BCM_RX_REASON_NAMES_INITIALIZER;
   1117 
   1118 STATIC void
   1119 ft_rmon_dump_packet_rx(int unit, pup_t *pup, uint32 report)
   1120 {
   1121     bcm_pkt_t *pkt;
   1122     char        pfx[64];
   1123     char        info_str[256];
   1124     pwu_t       *pu = &ft_rmon_units[unit];
   1125     int         i;
   1126 
   1127     pkt = &pup->rx_pkt;
   1128 
   1129 
   1130     ft_rmon_dump_start(unit, pfx, pup, report, pkt->dma_channel,
   1131                   pu->pu_packet_received);
   1132 
   1133     if (report & REPORT_DMA) {
   1134         if (pkt->_dv) {
   1135             soc_dma_dump_dv(unit, pfx, (dv_t *)pkt->_dv);
   1136         }
   1137     }
   1138 
   1139     if (report & REPORT_RAW) {
   1140 #if defined(BCM_CMICX_SUPPORT)
   1141             if (soc_feature(unit, soc_feature_cmicx)) {
   1142                 if (pu->hdr_dump == 1) {
   1143                     soc_dma_ep_to_cpu_hdr_dump(unit, pfx, pkt->_pkt_data.data - pkt->egress_to_cpu_hdr_size,
   1144                             pkt->egress_to_cpu_hdr_size, 0);
   1145                 }
   1146 
   1147                 if (report & REPORT_DMA) {
   1148                     uint8 *c = (uint8 *)pkt->_pkt_data.data;
   1149                     c -= pkt->egress_to_cpu_hdr_size;
   1150 #ifdef  LE_HOST
   1151                 {
   1152                     /* Higig field accessors expect network byte ordering,
   1153                      * so we must reverse the bytes on LE hosts */
   1154                     int word;
   1155                     uint32 *hg_data = (uint32 *)c;
   1156                     for (word = 0; word < BYTES2WORDS(pkt->egress_to_cpu_hdr_size); word++) {
   1157                         hg_data[word] = _shr_swap32(hg_data[word]);
   1158                     }
   1159                     c = (uint8 *)hg_data;
   1160                 }
   1161 #endif
   1162                     soc_dma_higig_dump(unit, pfx, c, 0, 0, NULL);
   1163                     soc_dma_ep_to_cpu_hdr_decoded_dump(unit, pfx, (void *)c, 1, pkt->egress_to_cpu_hdr_size);
   1164                 }
   1165             }
   1166 #endif
   1167             soc_dma_ether_dump(unit, pfx, pkt->_pkt_data.data, pkt->pkt_len, 0);
   1168             if (SOC_IS_TRIDENT3X(unit)) {
   1169                 cli_out("%slength %d (%d). rx-port %d. cos %d. prio_int %d. vlan %d. "
   1170                     "reason 0x%x. %s.\n", pfx,
   1171                     pkt->pkt_len, pkt->tot_len, pkt->rx_port,
   1172                     pkt->cos, pkt->prio_int, pkt->vlan,
   1173                     pkt->rx_reason,
   1174                     (pkt->rx_untagged) ?
   1175                     "Untagged" : "Ingress tagged");
   1176             } else {
   1177                 cli_out("%slength %d (%d). rx-port %d. cos %d. prio_int %d. vlan %d. "
   1178                     "reason 0x%x. %s.\n", pfx,
   1179                     pkt->pkt_len, pkt->tot_len, pkt->rx_port,
   1180                     pkt->cos, pkt->prio_int, pkt->vlan,
   1181                     pkt->rx_reason,
   1182                     (pkt->rx_untagged & BCM_PKT_OUTER_UNTAGGED) ?
   1183                     ((pkt->rx_untagged & BCM_PKT_INNER_UNTAGGED) ?
   1184                     "Untagged" : "Inner tagged") :
   1185                     ((pkt->rx_untagged & BCM_PKT_INNER_UNTAGGED) ?
   1186                     "Outer tagged" : "Double tagged"));
   1187             }
   1188         if ((pkt->stk_flags & BCM_PKT_STK_F_SRC_PORT) &&
   1189             (pkt->stk_flags & BCM_PKT_STK_F_DST_PORT)) {
   1190 
   1191             sal_sprintf(info_str,
   1192                 "dest-gport %d. src-gport %d. ",
   1193                 pkt->dst_gport, pkt->src_gport);
   1194         } else if ((pkt->stk_flags & BCM_PKT_STK_F_SRC_PORT)) {
   1195 
   1196             sal_sprintf(info_str,
   1197                 "dest-port %d. dest-mod %d. src-gport %d. ",
   1198                 pkt->dest_port, pkt->dest_mod, pkt->src_gport);
   1199         } else if ((pkt->stk_flags & BCM_PKT_STK_F_DST_PORT)) {
   1200 
   1201             sal_sprintf(info_str,
   1202                 "dest-gport %d. %s %d. src-mod %d. ",
   1203                 pkt->dst_gport,
   1204                 (pkt->flags & BCM_PKT_F_TRUNK) ? "src-trunk" : "src-port",
   1205                 (pkt->flags & BCM_PKT_F_TRUNK) ? pkt->src_trunk : pkt->src_port,
   1206                 pkt->src_mod);
   1207         } else {
   1208 
   1209             sal_sprintf(info_str,
   1210                 "dest-port %d. dest-mod %d. %s %d. src-mod %d. ",
   1211                 pkt->dest_port, pkt->dest_mod,
   1212                 (pkt->flags & BCM_PKT_F_TRUNK) ? "src-trunk" : "src-port",
   1213                 (pkt->flags & BCM_PKT_F_TRUNK) ? pkt->src_trunk : pkt->src_port,
   1214                 pkt->src_mod);
   1215         }
   1216 
   1217             cli_out("%s%sopcode %d. %s matched %d. classification-tag %d.\n",
   1218                 pfx, info_str,
   1219                 pkt->opcode,
   1220                 (pkt->flags & BCM_RX_TRUNCATED) ? "Truncated." : "",
   1221                 pkt->rx_matched, pkt->rx_classification_tag);
   1222 
   1223         for (i = 0; i < bcmRxReasonCount; i++) {
   1224             if (BCM_RX_REASON_GET(pkt->rx_reasons, i)) {
   1225                 cli_out("%sreasons: %s\n", pfx, _ft_rmon_reason_names[i]);
   1226             }
   1227         }
   1228 
   1229         /*
   1230          * Seamless Redundancy(SR) copy to CPU
   1231          * SR custom RX reason code (1~63) for IFP action bcmFieldActionSrCopyToCpu .
   1232          * construct reason code (1~63) from 6-bit binary encoding
   1233          */
   1234         #define SR_CUSTOM_RX_REASON_CODE \
   1235             ((BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit0) << 0)| \
   1236              (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit1) << 1)| \
   1237              (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit2) << 2)| \
   1238              (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit3) << 3)| \
   1239              (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit4) << 4)| \
   1240              (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit5) << 5))
   1241 
   1242         /* no copy to CPU when SR_CUSTOM_RX_REASON_CODE == 0 */
   1243         if(SR_CUSTOM_RX_REASON_CODE != 0) {
   1244             cli_out("%sSR custom RX reason code: %d\n",
   1245                     pfx,
   1246                     SR_CUSTOM_RX_REASON_CODE);
   1247         }
   1248     }
   1249 
   1250 #ifndef NO_SAL_APPL
   1251 #ifndef __STRICT_ANSI__
   1252 #ifndef __KERNEL__
   1253     if (report & REPORT_DECODE) {
   1254         if (pkt->_dv) {
   1255             int ix;
   1256             uint8 *data;
   1257             int encap_length;
   1258 
   1259             cli_out("*************************************************\n");
   1260             data = &(pkt->_pkt_data.data[0]);
   1261             for (ix = 0; ix < (pkt->pkt_len); ix+=8) {
   1262                 cli_out("%04d: %02x %02x %02x %02x %02x %02x %02x %02x\n",
   1263                         (ix/8), data[ix], data[ix+1], data[ix+2], data[ix+3], data[ix+4], data[ix+5], data[ix+6], data[ix+7]);
   1264             }
   1265             cli_out("*************************************************\n");
   1266 
   1267             d_packet_format(pfx, DECODE_ETHER, pkt->_pkt_data.data,
   1268                             pkt->pkt_len, NULL);
   1269 
   1270             /* DA+SA+TPID+VTAG+TPID+IP+UDP */
   1271             encap_length = 46;
   1272 
   1273             if (bcma_ft_ipfix_template_print(unit,
   1274                     (pkt->pkt_len - encap_length - 4), &(pkt->_pkt_data.data[encap_length]))) {
   1275                 cli_out("ipfix parsing failed\n");
   1276             }
   1277 
   1278 
   1279         }
   1280     }
   1281 #endif /* __KERNEL__ */
   1282 #endif /* __STRICT_ANSI__ */
   1283 #endif /* NO_SAL_APPL */
   1284 
   1285 }
   1286 
   1287 STATIC void
   1288 ft_rmon_dump_packet(int unit, pup_t *pup, uint32 report)
   1289 {
   1290     pwu_t       *pu = &ft_rmon_units[unit];
   1291 
   1292     switch (pu->mode) {
   1293         case PW_MODE_RX:
   1294             ft_rmon_dump_packet_rx(unit, pup, report);
   1295             break;
   1296         default:
   1297             break;
   1298     }
   1299 }
   1300 
   1301 STATIC cmd_result_t
   1302 ft_rmon_dump_log(int unit, int n)
   1303 /*
   1304  * Function:    ft_rmon_dump_log
   1305  * Purpose:     Dump out currently logged packets
   1306  * Parameters:  unit - unit #
   1307  *              n - number of packets to dump, -n means last "n"
   1308  *                  packets.
   1309  * Returns:     CMD_OK - success
   1310  */
   1311 {
   1312     pwu_t    *pu = &ft_rmon_units[unit];
   1313     pup_t    *pup;
   1314     int       abs_n;
   1315 
   1316     PW_LOCK(unit); /* Stop updates */
   1317 
   1318     if ((pu->pu_log == NULL) || (n == 0)) { /* Nothing to show */
   1319     PW_UNLOCK(unit);
   1320     cli_out("ft_rmon_dump_log[%d]: Warning: no packets logged "
   1321                 "or selected to dump\n", unit);
   1322     return CMD_OK;          /* Return nothing */
   1323     }
   1324 
   1325     /*
   1326      * Loop through list of packets, stop when we have dumped the correct
   1327      * number - we know there is at least one logged since we checked above.
   1328      * If dumping the last n packets, move backwards, otherwise move forwards.
   1329      * Anything on this list is complete, so the PW_LOCK protects this
   1330      * operation.
   1331      */
   1332     abs_n = n < 0 ? -n : n;
   1333     abs_n = abs_n > pu->pu_log_cnt ? pu->pu_log_cnt : abs_n;
   1334 
   1335     if (n < 0) {            /* Dump last N packets */
   1336     for (pup = pu->pu_log; abs_n-- != 0; pup = pup->pup_next) {
   1337         ft_rmon_dump_packet(unit, pup, pu->pu_dump_options);
   1338     }
   1339     } else {                /* Dump first N packets */
   1340     for (pup = pu->pu_log->pup_prev; abs_n-- != 0; pup = pup->pup_prev) {
   1341         ft_rmon_dump_packet(unit, pup, pu->pu_dump_options);
   1342     }
   1343     }
   1344     PW_UNLOCK(unit);
   1345 
   1346     return CMD_OK;
   1347 }
   1348 
   1349 STATIC  void
   1350 ft_rmon_log_packet(int unit, pup_t *pup)
   1351 /*
   1352  * Function:    ft_rmon_log_packet
   1353  * Purpose: Commit a recieved packet to the logs.
   1354  * Parameters:  unit - unit #
   1355  *      pup - pointer to pup to add to log.
   1356  * Returns: Nothing.
   1357  *
   1358  * Notes:   Assumes PW_LOCK held.
   1359  */
   1360 {
   1361     pwu_t   *pu = &ft_rmon_units[unit];
   1362 
   1363     /*
   1364      * There are 2 cases:
   1365      * 1) First entry
   1366      * 2) Log is full so the LRU packet is dropped (common case)
   1367      * 3) Log is not full, no packet is dropped.
   1368      */
   1369 
   1370     if (pu->pu_log_cnt == 0) {      /* 1) First entry */
   1371         pu->pu_log = pup->pup_next = pup->pup_prev = pup;
   1372         pu->pu_log_cnt = 1;
   1373     } else if (pu->pu_log_cnt == pu->pu_log_max) { /* 2) Full log, drop one */
   1374         pup_t   *tp;
   1375 
   1376         tp = pu->pu_log->pup_prev;  /* Entry to delete */
   1377         pup->pup_next = pu->pu_log; /* Link new one in at head */
   1378         pup->pup_prev = tp->pup_prev;
   1379         pup->pup_next->pup_prev = pup;
   1380         pup->pup_prev->pup_next = pup;
   1381 
   1382         ft_rmon_pup_free(unit, tp);
   1383     } else {                /* 3) Just add to chain */
   1384         /*
   1385          * Case 2 - add new entry and increment log count.
   1386          */
   1387         pu->pu_log_cnt++;
   1388         pup->pup_next = pu->pu_log;
   1389         pup->pup_prev = pu->pu_log->pup_prev;
   1390         pup->pup_next->pup_prev = pup;
   1391         pup->pup_prev->pup_next = pup;
   1392     }
   1393     pu->pu_log = pup;           /* Set new list */
   1394 }
   1395 
   1396 
   1397 STATIC  void
   1398 ft_rmon_process_pending(int unit)
   1399 /*
   1400  * Function:    ft_rmon_process_pending
   1401  * Purpose: Process packets queued from interrupt
   1402  * Parameters:  unit - unit #
   1403  * Returns: Nothing.
   1404  *
   1405  * Notes:   Can be called only from a non-interrupt context.
   1406  */
   1407 {
   1408     pwu_t       *pu = &ft_rmon_units[unit];
   1409     pup_t       *pup;
   1410     int         chan;
   1411     chan = 0;
   1412     /*
   1413      * Pick up current done list and process in order.
   1414      */
   1415     PW_SPIN_LOCK(unit);
   1416     pup = (pup_t *)pu->pu_pending;
   1417     pu->pu_pending = NULL;
   1418     PW_SPIN_UNLOCK(unit);
   1419 
   1420     pu->last_pkt_count = 0;
   1421     while (pup) {
   1422         pup_t  *tp = pup->pup_next;
   1423 
   1424         pup->pup_seqno = ++pu->pu_packet_received;
   1425         ft_rmon_log_packet(unit, (pup_t *)pup);
   1426         chan = 0; /* Per-channel counted in Rx call-back */
   1427         pu->pu_ch_count[chan]++;
   1428         ft_rmon_dump_packet(unit, (pup_t *)pup, pu->pu_report); /* Dump packet */
   1429         pup = tp;
   1430         pu->last_pkt_count++;
   1431     }
   1432 }
   1433 
   1434 /****************************************************************
   1435  *
   1436  * RX API packet watcher code, non-interrupt
   1437  */
   1438 STATIC bcm_rx_t
   1439 ft_rmon_rx_callback(int unit, bcm_pkt_t *pkt, void *cookie)
   1440 {
   1441     pup_t *pup;
   1442     pwu_t   *pu = &ft_rmon_units[unit];
   1443     int8        chan;
   1444     dma_chan_t  dma_chan;
   1445 
   1446     chan = pkt->dma_channel;
   1447 
   1448     if (soc_feature(unit, soc_feature_cmicx)) {
   1449         dma_chan = CMICX_N_DMA_CHAN;
   1450     } else {
   1451         dma_chan = N_DMA_CHAN;
   1452     }
   1453 
   1454     if (chan >= 0 && chan < dma_chan) {
   1455         pu->pu_ch_count[chan + 1]++;
   1456     }
   1457     if (pu->pu_report == 0 && pu->pu_log_max == 1) {
   1458         /* No post-processing - just count packet */
   1459         return BCM_RX_HANDLED;
   1460     }
   1461 
   1462     pup = ft_rmon_pup_alloc(unit);
   1463     if (!pup) {
   1464         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1465                     (BSL_META_U(unit,
   1466                                 "FtRemoteMon: Failed to allocate pup struct.  Discarding\n")));
   1467         return BCM_RX_NOT_HANDLED;
   1468     }
   1469 
   1470     sal_memcpy(&pup->rx_pkt, pkt, sizeof(bcm_pkt_t));
   1471 
   1472     PW_SPIN_LOCK(unit);
   1473     pup->pup_next = NULL;
   1474     if (pu->pu_pending == NULL) {
   1475         pup->pup_prev = pup;
   1476         pu->pu_pending = pup;
   1477     } else {
   1478         pu->pu_pending->pup_prev->pup_next = pup;
   1479         pu->pu_pending->pup_prev = pup;
   1480     }
   1481     PW_SPIN_UNLOCK(unit);
   1482 
   1483     sal_sem_give(ft_rmon_units[unit].pu_sema);
   1484     return BCM_RX_HANDLED_OWNED;
   1485 }
   1486 
   1487 #endif /* BCM_FLOWTRACKER_SUPPORT */
   1488 
   1489 char cmd_ft_rmon_usage[] =
   1490     "Parameters: [report +/-<values>] [stop|start] [count]\n"
   1491 #ifndef COMPILER_STRING_CONST_LIMIT
   1492     "\tlog # - specifies # packets to remember\n"
   1493     "\tdump [# | options] - # > 0 dumps # packets from start of log\n"
   1494     "\t                     # < 0 dumps last # packets\n"
   1495     "\t                     nothing - dumps all logs\n"
   1496     "\t                     options - count   - print packet # only\n"
   1497     "\t                               decode  - attempt to decode packet\n"
   1498     "\t                               raw     - dump raw byte stream (host order)\n"
   1499     "\t                               Prepend + to set, - to clear, nothing to toggle\n"
   1500     "\treport- count   - print packet # only\n"
   1501     "\t        decode  - attempt to decode packet\n"
   1502     "\t        raw     - dump raw byte stream (host order)\n"
   1503     "\t        Prepend + to set, - to clear, nothing to toggle\n"
   1504     "\tquiet - disable all reporting\n"
   1505     "\tstart - start the FtRemoteMon-daemon\n"
   1506     "\tstop  - stop the FtRemoteMon-daemon and deallocate log space\n"
   1507     "\tcount - print # packets received.\n"
   1508     "\treset - reinitialize configuration from bcm_rx_* API state\n"
   1509 #endif
   1510     ;
   1511 
   1512 cmd_result_t
   1513 cmd_ft_rmon_command(int unit, args_t *a)
   1514 /*
   1515  * Function:    ft_rmon_command
   1516  * Purpose: Command interface to the "ipfix rmon" thread.
   1517  * Parameters:
   1518  *      "verbose" - print lots of stuff.
   1519  *      "start" - start ipfix rmon  thread.
   1520  *      "stop" - stop ipfix rmon thread.
   1521  *      "quiet" - print no stuff.
   1522  * Returns: CMD_OK - success
   1523  *      CMD_FAIL - failed
   1524  *      CMD_USAGE - print usage instructions
   1525  */
   1526 {
   1527 #if defined(BCM_FLOWTRACKER_SUPPORT)
   1528     char    *c;
   1529     int     n;
   1530     uint32  on = 0;         /* flags to turn on */
   1531     pwu_t   *pu = &ft_rmon_units[unit]; /* Control this unit */
   1532 
   1533     if (!sh_check_attached(ARG_CMD(a), unit)) {
   1534     return(CMD_FAIL);
   1535     }
   1536 
   1537     if (!pu->init_done) {
   1538         ft_rmon_init(unit);
   1539     }
   1540 
   1541     if (!ARG_CNT(a)) {          /* Nothing passed */
   1542     cli_out("%s: Status: %s. Mode %s. Buffering up to %d packets.%s\n",
   1543                 ft_rmon_name[unit],
   1544                 (pu->pu_flags & PU_F_RUN) ? "Running" : "Not Running",
   1545                 ft_rmon_modes[pu->mode], pu->pu_log_max,
   1546                 (pu->pu_flags & PU_F_STOP) ? " STOP Requested." : "");
   1547         if (pu->rate <= 0) {
   1548             cli_out("Rate limiting is off.\n");
   1549         } else {
   1550             cli_out("Rate limit is %d (soc intvl %d).\n", pu->rate,
   1551                     pu->pu_interval);
   1552         }
   1553 
   1554     cli_out("Reporting is enabled for: ");
   1555     parse_mask_format(80, ft_rmon_report_table, pu->pu_report);
   1556     cli_out("Reporting is disabled for: ");
   1557     parse_mask_format(80, ft_rmon_report_table, pu->pu_report ^ ~0);
   1558 
   1559         cli_out("Dump options are enabled for: ");
   1560     parse_mask_format(80, ft_rmon_report_table, pu->pu_dump_options);
   1561     cli_out("Dump options are disabled for: ");
   1562     parse_mask_format(80, ft_rmon_report_table, pu->pu_dump_options ^ ~0);
   1563 
   1564         cli_out("RX on for channel(s): ");
   1565     if (pu->pu_channel) {
   1566         parse_mask_format(50, ft_rmon_channel_table, pu->pu_channel);
   1567         cli_out("RX off for channel(s): ");
   1568         parse_mask_format(50, ft_rmon_channel_table, ~pu->pu_channel);
   1569     } else {
   1570         cli_out(" -- using default --\n");
   1571     }
   1572 #ifdef BROADCOM_DEBUG
   1573         if (pu->mode == PW_MODE_RX) {
   1574             bcm_rx_show(unit);
   1575         }
   1576 #endif /* BROADCOM_DEBUG */
   1577     return(CMD_OK);
   1578     }
   1579 
   1580     /* Scan args and see what's up */
   1581 
   1582     while ((c = ARG_GET(a)) != NULL) {
   1583     if (!sal_strcasecmp(c, "start")) {
   1584         if (pu->pu_flags & PU_F_RUN) {
   1585         cli_out("%s: WARNING: Already running\n", ft_rmon_name[unit]);
   1586         } else {
   1587         on |= PU_F_RUN;
   1588         }
   1589     } else if (!sal_strcasecmp(c, "stop")) {
   1590         if (!(pu->pu_flags & PU_F_RUN)) {
   1591         cli_out("%s: WARNING: Not running\n", ft_rmon_name[unit]);
   1592         return(CMD_OK);     /* Return OK to avoid rc aborts */
   1593         }
   1594         on |= PU_F_STOP;
   1595     } else if (!sal_strcasecmp(c, "reset")) {
   1596         if (pu->pu_flags & PU_F_RUN) {
   1597         cli_out("%s: Unable to reset configuration "
   1598                         "while running\n", ft_rmon_name[unit]);
   1599         return(CMD_FAIL);
   1600         } else {
   1601                 pu->init_done = FALSE;
   1602                 ft_rmon_init(unit);
   1603                 return CMD_OK;
   1604             }
   1605     } else if (!sal_strcasecmp(c, "channel")) {
   1606         if (ARG_CNT(a) == 0) {
   1607         cli_out("%s: RX on for channel(s): ", ft_rmon_name[unit]);
   1608         if (pu->pu_channel) {
   1609             parse_mask_format(50, ft_rmon_channel_table, pu->pu_channel);
   1610             cli_out("%s: RX off for channel(s): ", ft_rmon_name[unit]);
   1611             parse_mask_format(50, ft_rmon_channel_table, ~pu->pu_channel);
   1612         } else {
   1613             cli_out(" -- using default --\n");
   1614         }
   1615         return(CMD_OK);
   1616         } else if (pu->pu_flags & PU_F_RUN) {
   1617         cli_out("%s: Unable to configure DMA channels "
   1618                         "while running\n", ft_rmon_name[unit]);
   1619         return(CMD_FAIL);
   1620         }
   1621 
   1622         /* Set channels */
   1623         while ((c = ARG_CUR(a)) != NULL &&
   1624            !parse_mask(c, ft_rmon_channel_table,
   1625                    (uint32 *)&pu->pu_channel)) {
   1626         ARG_NEXT(a);    /* Bump arg if matched report */
   1627         }
   1628 
   1629         if (pu->pu_flags & PU_F_RUN) {
   1630         cli_out("%s: Warning channel re-assignment will not take\n"
   1631                         "%s: until restarted.\n",
   1632                         ft_rmon_name[unit], ft_rmon_name[unit]);
   1633         }
   1634     } else if (!sal_strcasecmp(c, "quiet")) {
   1635         pu->pu_report = 0;
   1636     } else if (!sal_strcasecmp(c, "rate")) {
   1637         c = ARG_GET(a);
   1638             if (c == NULL) {
   1639                 if (pu->rate <= 0) {
   1640                     cli_out("%s: No rate limiting.\n", ft_rmon_name[unit]);
   1641                 } else {
   1642                     cli_out("%s: Rate limit is currently %d pkts/sec.\n",
   1643                             ft_rmon_name[unit], pu->rate);
   1644                 }
   1645                 return CMD_OK;
   1646             }
   1647             pu->rate = strtoul(c, NULL, 10);
   1648             if (_ft_rmon_set_rate(unit) < 0) {
   1649                 return CMD_FAIL;
   1650             }
   1651             return CMD_OK;
   1652     } else if (!sal_strcasecmp(c, "report")) {
   1653         if (ARG_CNT(a)) {
   1654         while ((c = ARG_CUR(a)) != NULL &&
   1655                !parse_mask(c, ft_rmon_report_table, &pu->pu_report)) {
   1656             ARG_NEXT(a);    /* Bump arg if matched report */
   1657         }
   1658         } else {            /* Print values */
   1659         cli_out("%s: Reporting on for: ", ft_rmon_name[unit]);
   1660         parse_mask_format(50, ft_rmon_report_table, pu->pu_report);
   1661         cli_out("%s: Reporting off for: ", ft_rmon_name[unit]);
   1662         parse_mask_format(50, ft_rmon_report_table, ~pu->pu_report);
   1663         }
   1664     } else if (!sal_strcasecmp(c, "log")) {
   1665         c = ARG_GET(a);
   1666         if (c) {            /* We have an option */
   1667         if (pu->pu_flags & PU_F_RUN) {
   1668             cli_out("%s: Can not change \"log\" "
   1669                             "while FtRemoteMon-daemon running\n", ft_rmon_name[unit]);
   1670             return(CMD_FAIL);
   1671         }
   1672         if (!sal_strcasecmp(c, "on")) {
   1673             n = PU_LOG_CNT;
   1674         } else if (!sal_strcasecmp(c, "off")) {
   1675             n = 1;
   1676         } else if (isint(c)) {  /* Set log size */
   1677             n = parse_integer(c);
   1678             if (n < 1) {
   1679             cli_out("%s: What is %s?\n", ft_rmon_name[unit], c);
   1680             n = 1;
   1681             }
   1682         } else {
   1683             cli_out("%s: Invalid count \"%s\"\n", ft_rmon_name[unit], c);
   1684             return(CMD_FAIL);
   1685         }
   1686         pu->pu_log_max = n;
   1687         }
   1688         cli_out("%s: Logging(%d-packets)\n",
   1689                     ft_rmon_name[unit], pu->pu_log_max);
   1690         if (!c || !*c) {
   1691         return(CMD_OK);
   1692         }
   1693     } else if (!sal_strcasecmp(c, "dump")) {
   1694         c = ARG_GET(a);
   1695         if (!c) {           /* no args */
   1696         n = pu->pu_log_cnt;
   1697         } else if (!isint(c)) {
   1698                 if (!sal_strcasecmp(c, "options")) {
   1699                     if (ARG_CNT(a)) {
   1700                         while ((c = ARG_CUR(a)) != NULL &&
   1701                                !parse_mask(c, ft_rmon_report_table,
   1702                                            &pu->pu_dump_options)) {
   1703                             ARG_NEXT(a);    /* Bump arg if matched report */
   1704                         }
   1705                     } else {            /* Print values */
   1706                         cli_out("%s: Dump options on for: ", ft_rmon_name[unit]);
   1707                         parse_mask_format(50, ft_rmon_report_table, pu->pu_dump_options);
   1708                         cli_out("%s: Dump options off for: ", ft_rmon_name[unit]);
   1709                         parse_mask_format(50, ft_rmon_report_table, ~pu->pu_dump_options);
   1710                     }
   1711                     return(CMD_OK);
   1712                 } else {
   1713                     cli_out("%s: Invalid log count \"%s\"\n", ft_rmon_name[unit], c);
   1714                     return(CMD_FAIL);
   1715                 }
   1716             } else {
   1717         n = parse_integer(c);
   1718         }
   1719         return(ft_rmon_dump_log(unit, n));
   1720     } else if (!sal_strcasecmp(c, "count")) {
   1721         COMPILER_DOUBLE cur_time, last_time;
   1722         int     cur_count, last_count;
   1723         int     rate;
   1724 
   1725         cur_time = SAL_TIME_DOUBLE();
   1726 
   1727         last_time = pu->pu_count_time;
   1728         last_count = pu->pu_count_last;
   1729         cur_count = pu->pu_packet_received;
   1730 
   1731         if (cur_time == last_time) {
   1732         rate = 0;
   1733         } else {
   1734         rate = (int) ((cur_count - last_count) /
   1735                   (cur_time - last_time));
   1736         }
   1737 
   1738         cli_out("%s: Received %d packets [(%d),%d,%d,%d,%d] (%d/sec), "
   1739                     "last %d packet(s) logged\n",
   1740                     ft_rmon_name[unit],
   1741                     pu->pu_packet_received,
   1742                     pu->pu_ch_count[0],
   1743                     pu->pu_ch_count[1],
   1744                     pu->pu_ch_count[2],
   1745                     pu->pu_ch_count[3],
   1746                     pu->pu_ch_count[4],
   1747                     rate,
   1748                     pu->pu_log_cnt);
   1749 
   1750         pu->pu_count_last = cur_count;
   1751         pu->pu_count_time = cur_time;
   1752     } else if (!sal_strcasecmp(c, "interval")) {
   1753         c = ARG_GET(a);
   1754         if (!c || !isint(c)) {
   1755         return(CMD_USAGE);
   1756         }
   1757         n = parse_integer(c);
   1758         if (n < 0) {
   1759         cli_out("%s: Invalid interval: %s\n", ft_rmon_name[unit], c);
   1760         return(CMD_FAIL);
   1761         }
   1762         pu->pu_interval = n;
   1763     } else if (!sal_strcasecmp(c, "mode")) {
   1764         if ((c = ARG_GET(a)) == NULL) {
   1765         cli_out("Current mode is %s\n", ft_rmon_modes[pu->mode]);
   1766         return CMD_OK;
   1767         }
   1768 
   1769         if (ft_rmon_running(unit)) {
   1770         cli_out("Can't set modes while running\n");
   1771         return CMD_FAIL;
   1772         }
   1773 
   1774         if (!sal_strcasecmp(c, "rx")) {
   1775         pu->mode = PW_MODE_RX;
   1776         } else {
   1777         cli_out("Unknown mode: %s\n", c);
   1778         return CMD_FAIL;
   1779         }
   1780 
   1781         return CMD_OK;
   1782         } else if (!sal_strcasecmp(c, "hdr")) {
   1783             c = ARG_GET(a);
   1784             if (c) {            /* We have an option */
   1785                 if (!sal_strcasecmp(c, "on")) {
   1786                     pu->hdr_dump = 1;
   1787                 } else if (!sal_strcasecmp(c, "off")) {
   1788                     pu->hdr_dump = 0;
   1789                 }
   1790             }
   1791     } else {
   1792         return(CMD_USAGE);
   1793     }
   1794     }
   1795 
   1796     /* Everything OK, start or stop ipfix rmon now */
   1797 
   1798     if (on & PU_F_RUN) {        /* start off thread */
   1799     return(ft_rmon_start(unit, TRUE));
   1800     } else if (on & PU_F_STOP) {    /* stop task */
   1801     return(ft_rmon_stop(unit, TRUE));
   1802     }
   1803 #endif
   1804 
   1805     return(CMD_OK);
   1806 }