//===========================================================================
//  @(#) $Name: cflowd-2-1-b1 $
//  @(#) $Id: CflowdCiscoFlowEngine.hh,v 1.4 1999/02/18 08:00:44 dwm Exp $
//===========================================================================
//  CAIDA Copyright Notice
//
//  By accessing this software, cflowd++, you are duly informed
//  of and agree to be bound by the conditions described below in this
//  notice:
//
//  This software product, cflowd++, is developed by Daniel W. McRobb, and
//  copyrighted(C) 1998 by the University of California, San Diego
//  (UCSD), with all rights reserved.  UCSD administers the CAIDA grant,
//  NCR-9711092, under which part of this code was developed.
//
//  There is no charge for cflowd++ software. You can redistribute it
//  and/or modify it under the terms of the GNU General Public License,
//  v.  2 dated June 1991 which is incorporated by reference herein.
//  cflowd++ is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF
//  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use
//  of it will not infringe on any third party's intellectual property
//  rights.
//
//  You should have received a copy of the GNU GPL along with cflowd++.
//  Copies can also be obtained from:
//
//    http://www.gnu.org/copyleft/gpl.html
//
//  or by writing to:
//
//    University of California, San Diego
//
//    SDSC/CAIDA
//    9500 Gilman Dr., MS-0505
//    La Jolla, CA 92093 - 0505  USA
//
//  Or contact:
//
//    info@caida.org
//===========================================================================

#ifndef _CFLOWDCISCOFLOWENGINE_HH_
#define _CFLOWDCISCOFLOWENGINE_HH_

extern "C" {
#include <syslog.h>
}

#include "CflowdFlowPdu.h"

//---------------------------------------------------------------------------
//  class CflowdCiscoFlowEngine
//---------------------------------------------------------------------------
//  This class abstracts a flow-export engine on a Cisco.  We only
//  use it to track sequence numbers in flow-export (which are
//  per-engine; a VIP can send flow-export just as an RSP can, and
//  will use its own sequence numbers).
//  Note that with the addition of v8 flow-export support, we created
//  an array of sequence numbers, since the sequence numbers are per
//  aggregation cache.  We use the 0th entry to track sequence numbers
//  for older versions of flow-export, and index into the other entries
//  of the array using the agg_method from the flow packet header (which
//  we propagate wherever we need it).
//---------------------------------------------------------------------------
class CflowdCiscoFlowEngine
{
public:
  //-------------------------------------------------------------------------
  //                      inline CflowdCiscoFlowEngine()
  //.........................................................................
  //  constructor
  //-------------------------------------------------------------------------
  inline CflowdCiscoFlowEngine()
  {
    memset(this->_seqNumber,0,
           sizeof(this->_seqNumber[0]) * (k_CiscoV8FlowExportNumAggTypes + 1));
    memset(this->_missedFlows,0,
           (sizeof(this->_missedFlows[0]) *
            (k_CiscoV8FlowExportNumAggTypes + 1)));
    memset(this->_flowsReceived,0,
           (sizeof(this->_flowsReceived[0]) *
            (k_CiscoV8FlowExportNumAggTypes + 1)));
  }

  //-------------------------------------------------------------------------
  //                         ~CflowdCiscoFlowEngine()
  //.........................................................................
  //  destructor
  //-------------------------------------------------------------------------
  inline ~CflowdCiscoFlowEngine()
  {
  }
  
  //-------------------------------------------------------------------------
  //          uint32_t SequenceNumber(uint8_t aggMethod = 0) const
  //.........................................................................
  //  Returns the current flow-export sequence number for the
  //  flow engine for the given aggregation method.
  //-------------------------------------------------------------------------
  inline uint32_t  SequenceNumber(uint8_t aggMethod = 0) const
  {
    if (aggMethod > k_CiscoV8FlowExportMaxAggType) {
      syslog(LOG_ERR,
             "[E] CflowdCiscoFlowEngine::SequenceNumber(uint8_t aggMethod)"
             " called with bogus aggMethod (%u) {%s:%d}",
             aggMethod,__FILE__,__LINE__);
      return(0);
    }
    return(this->_seqNumber[aggMethod]);
  }
  
  //--------------------------------------------------------------------------
  //            inline uint32_t SequenceNumber(uint32_t seqNumber,           
  //                                           uint8_t aggMethod = 0)        
  //..........................................................................
  //  Sets and returns the current flow-export sequence number for the
  //  flow engine for the given aggregation method.
  //--------------------------------------------------------------------------
  inline uint32_t SequenceNumber(uint32_t seqNumber,
                                 uint8_t aggMethod = 0)
  {
    if (aggMethod > k_CiscoV8FlowExportMaxAggType) {
      syslog(LOG_ERR,
             "[E] CflowdCiscoFlowEngine::SequenceNumber(uint32_t seqNumber,"
             "uint8_t aggMethod) called with bogus aggMethod (%u) {%s:%d}",
             aggMethod,__FILE__,__LINE__);
      return(0);
    }

    this->_seqNumber[aggMethod] = seqNumber;
    return(this->_seqNumber[aggMethod]);
  }

  //--------------------------------------------------------------------------
  //     uint32_t SequenceNumber(uint32_t seqNumber, uint16_t flowCount,     
  //                             uint8_t aggMethod = 0)
  //..........................................................................
  //  Sets and returns the current flow-export sequence number for the
  //  flow engine for the given aggregation method.  Also updates the
  //  flows received for the engine, as well as handling the missed
  //  flows counter.  This can be used as a single function call from
  //  cflowd to keep track of the sequence number and missed flows.
  //--------------------------------------------------------------------------
  uint32_t SequenceNumber(uint32_t seqNumber, uint16_t flowCount,
                          uint8_t aggMethod = 0);

  //-------------------------------------------------------------------------
  //                       uint32_t MissedFlows() const                   
  //.........................................................................
  //  Returns the number of missed flows for the flow engine for a given
  //  aggregation method.
  //-------------------------------------------------------------------------
  inline uint32_t MissedFlows(uint8_t aggMethod = 0) const
  {
    if (aggMethod > k_CiscoV8FlowExportMaxAggType) {
      syslog(LOG_ERR,
             "[E] CflowdCiscoFlowEngine::MissedFlows(uint8_t aggMethod)"
             " called with bogus aggMethod (%u) {%s:%d}",
             aggMethod,__FILE__,__LINE__);
      return(0);
    }
    
    return(this->_missedFlows[aggMethod]);
  }

  //--------------------------------------------------------------------------
  // inline uint32_t MissedFlows(uint32_t missedFlows, uint8_t aggMethod = 0) 
  //..........................................................................
  //  Sets and returns the number of missed flows for the flow engine for
  //  a given aggregaiton method.
  //--------------------------------------------------------------------------
  inline uint32_t MissedFlows(uint32_t missedFlows, uint8_t aggMethod = 0)
  {
    if (aggMethod > k_CiscoV8FlowExportMaxAggType) {
      syslog(LOG_ERR,
             "[E] CflowdCiscoFlowEngine::MissedFlows(uint32_t missedFlows,"
             "uint8_t aggMethod) called with bogus aggMethod (%u) {%s:%d}",
             aggMethod,__FILE__,__LINE__);
      return(0);
    }
    
    this->_missedFlows[aggMethod] = missedFlows;
    return(this->_missedFlows[aggMethod]);
  }

  //-------------------------------------------------------------------------
  //          uint32_t FlowsReceived(uint8_t aggMethod = 0) const
  //.........................................................................
  //  Returns the number of flows received from the flow engine for
  //  a given aggregation method.
  //-------------------------------------------------------------------------
  inline uint32_t FlowsReceived(uint8_t aggMethod = 0) const
  {
    if (aggMethod > k_CiscoV8FlowExportMaxAggType) {
      syslog(LOG_ERR,
             "[E] CflowdCiscoFlowEngine::FlowsReceived(uint8_t aggMethod)"
             " called with bogus aggMethod (%u) {%s:%d}",
             aggMethod,__FILE__,__LINE__);
      return(0);
    }
    
    return(this->_flowsReceived[aggMethod]);
  }

  //--------------------------------------------------------------------------
  //          inline uint32_t FlowsReceived(uint32_t flowsReceived,          
  //                                        uint8_t aggMethod = 0)           
  //..........................................................................
  //  Sets and returns the number of flows received from the flow
  //  engine for a given aggregation method.
  //--------------------------------------------------------------------------
  inline uint32_t FlowsReceived(uint32_t flowsReceived,
                                uint8_t aggMethod = 0)
  {
    if (aggMethod > k_CiscoV8FlowExportMaxAggType) {
      syslog(LOG_ERR,
             "[E] CflowdCiscoFlowEngine::FlowsReceived(uint32_t flowsReceived,"
             "uint8_t aggMethod) called with bogus aggMethod (%u) {%s:%d}",
             aggMethod,__FILE__,__LINE__);
      return(0);
    }
    
    this->_flowsReceived[aggMethod] = flowsReceived;
    return(this->_flowsReceived[aggMethod]);
  }

private:
  uint32_t     _seqNumber[k_CiscoV8FlowExportNumAggTypes+1];
  uint32_t     _missedFlows[k_CiscoV8FlowExportNumAggTypes+1];
  uint32_t     _flowsReceived[k_CiscoV8FlowExportNumAggTypes+1];
};

#endif  // _CFLOWDCISCOFLOWENGINE_HH_
