/**
 * ============================================================================
 * = COPYRIGHT
 *              INTEL CORPORATION PROPRIETARY INFORMATION
 *   This software is supplied under the terms of a license agreement or
 *   nondisclosure agreement with Intel Corporation and may not be copied 
 *   or disclosed except in accordance with the terms in that agreement.
 *      Copyright (C) 2000-2001 Intel Corporation. All rights reserved.
 *
 * = PRODUCT
 *      Intel(r) IXA SDK 3.0 for the IXP2000 Network Processor
 *
 * = LIBRARY
 *      
 *
 * = MODULE
 *      IPv4 Forwarder Core Component - CCI - init function
 *
 * = FILENAME
 *      ix_cc_ipv4_init.c
 *
 * = DESCRIPTION
 *      The file defines for init interface and internal functions.
 *
 * = AUTHOR
 *       Govindan Nair
 *       govindan.nair@intel.com
 *
 * = AKNOWLEDGEMENTS
 *      
 *
 * = CREATION TIME
 *      06/24/2002
 *
 * = CHANGE HISTORY
 *
 * ============================================================================
 */
#define IX_ERROR_FILE_IDENT "$Id: ix_cc_ipv4_init.c,v 1.38 2003/12/12 00:47:19 ktseng Exp $";

#include "ix_ossl.h"
#include "ix_rm.h"

#include "ix_cc_error.h"

#include "cc/ix_cc_rtmv4.h"

#include "ix_cc.h"
#include "ix_cc_macros.h"
#include "ix_config.h"
#include "bindings.h"
#include "ipv4_fwder_uc.h"
#include "cc/ix_cc_ipv4.h"
#include "cc/ipv4/internal/ix_cc_ipv4_init.h"
#include "cc/ipv4/internal/ix_cc_ipv4_fini.h" 
#include "cc/ipv4/internal/icmp.h"

/**
 * Preprocessor symbols and Macros used in this file
 */

/**
 * Type definitions whose scope is limited to this file
 */

/**
 * Variable declarations global to this file only. Externs are followed by 
 * static variables.
 */

ix_cc_ipv4_context* g_pIpv4Context;
ix_cc_ipv4_registry_data g_Ipv4RegistryData;

extern ix_uint16 g_IcmpSleepTime; /* To set ICMP event handler sleep time */


int ipTraceLevel = 1;	/* It controls traces produced by IpTrace() macro */


/** 
 * Extern function prototypes.
 */


/** 
 * Static function prototypes.
 */


/** 
 * Function definitions.
 */


/**
 * NAME: _ix_cc_ipv4_retrieve_registry_data
 *
 * DESCRIPTION: This primitive will be used to retrieve data from registry 
 * for a given property type.
 *           .
 * 
 * @Param:  - IN arg_pPropertyName - pointer to property name string 
 *
 * @Param:  - OUT arg_pPropertyValue - pointer to property value 
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_REGISTRY  - failed to access registry
 * 
 */

ix_error _ix_cc_ipv4_retrieve_registry_data(const char* arg_pPropertyName,
                                            ix_uint32* arg_pPropertyValue)
{
    ix_configuration_property_handle hIpv4PropertyHandle; 

    /* Get static data from registry */    
    IX_ERROR_CRT(ix_rm_cp_property_open(IX_CP_CORE_PROPERTY_ROOT,
                                 arg_pPropertyName,
                                 &hIpv4PropertyHandle),
                 IX_CC_IPV4_ERROR_REGISTRY,
                 IX_ERROR_LEVEL_WARNING);

    IX_ERROR_CRT(ix_rm_cp_property_get_value_uint32(hIpv4PropertyHandle,arg_pPropertyValue),
                 IX_CC_IPV4_ERROR_REGISTRY,
                 IX_ERROR_LEVEL_WARNING);

    IX_ERROR_CRT(ix_rm_cp_property_close(hIpv4PropertyHandle),
                 IX_CC_IPV4_ERROR_REGISTRY,
                 IX_ERROR_LEVEL_WARNING);

    return IX_SUCCESS;
}/* end _ix_cc_ipv4_retrieve_registry_data */




/**
 * NAME: _ix_cc_ipv4_registry
 *
 * DESCRIPTION: This primitive will be used to retreive data from registry for
 * all IPV4 static data and stored in ipv4RegistyData 
 *           .
 * 
 * @Param:  - IN none
 *
 * @Param:  - OUT  none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_REGISTRY  - not able to access registry.
 * 
 */

ix_error _ix_cc_ipv4_registry()
{
       
    /* Get route table size from registry */
    IX_ERROR_CR(_ix_cc_ipv4_retrieve_registry_data(IX_CC_IPV4_REGISTRY_KEY_ROUTE_TABLE_SIZE,
                                            &g_Ipv4RegistryData.rtmConfig.routeTableSizeHint));

   /* Get route table type from registry */
    IX_ERROR_CR(_ix_cc_ipv4_retrieve_registry_data(IX_CC_IPV4_REGISTRY_KEY_ROUTE_TABLE_TYPE,
                                            (ix_uint32 *)&g_Ipv4RegistryData.rtmConfig.lkupType));

    /* Get RTM lookup memory type from registry */
    IX_ERROR_CR(_ix_cc_ipv4_retrieve_registry_data(IX_CC_IPV4_REGISTRY_KEY_RTM_LOOKUP_MEMORY_TYPE,
                                            (ix_uint32 *)&g_Ipv4RegistryData.rtmConfig.lkupMemType));

     /* Get RTM lookup memory channel number from registry */
    IX_ERROR_CR(_ix_cc_ipv4_retrieve_registry_data(IX_CC_IPV4_REGISTRY_KEY_RTM_LOOKUP_CHANNEL,
                                            &g_Ipv4RegistryData.rtmConfig.lkupChannel));

    /* Get next hop table size from registry */
    IX_ERROR_CR(_ix_cc_ipv4_retrieve_registry_data(IX_CC_IPV4_REGISTRY_KEY_NEXT_HOP_TABLE_SIZE,
                                            &g_Ipv4RegistryData.rtmConfig.nhdbSizeHint));

    /* Get next hop data base memory type from registry */
    IX_ERROR_CR(_ix_cc_ipv4_retrieve_registry_data(IX_CC_IPV4_REGISTRY_KEY_NEXT_HOP_DATABASE_MEMORY_TYPE ,
                                            (ix_uint32 *)&g_Ipv4RegistryData.rtmConfig.nhdbMemType));
 
    /* Get next hop data base memory channel from registry */
    IX_ERROR_CR(_ix_cc_ipv4_retrieve_registry_data(IX_CC_IPV4_REGISTRY_KEY_NEXT_HOP_DATABASE_CHANNEL ,
                                            &g_Ipv4RegistryData.rtmConfig.nhdbChannel));

    /* Get micro engine numbers from registry */
    IX_ERROR_CR(_ix_cc_ipv4_retrieve_registry_data(IX_CC_IPV4_REGISTRY_KEY_ME_FOR_IPV4,
                                             &g_Ipv4RegistryData.meNumbers));
   
    return IX_SUCCESS;
}/* end _ix_cc_ipv4_registry */


/**
 * NAME: _ix_cc_ipv4_alloc_symbols
 *
 * DESCRIPTION: This primitive will be used to allocate memory for symbols to be patched. 
 * 
 * @Param:  - IN - none
 *
 * @Param:  - OUT  - none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_OOM  - not able to allocate memory
 * 
 */

ix_error _ix_cc_ipv4_alloc_symbols()
{
    ix_error err = IX_SUCCESS;
    ix_uint32 memSize;

#if (_IX_HARDWARE_TYPE_ == _IX_HW_2800_)

    /* Allocate memory for microblock DCAST table */
    memSize = (IX_CC_IPV4_DBCAST_TABLE_BLOCK_SIZE * sizeof(ix_uint32) *
              IX_CC_IPV4_NUMBER_OF_DBCAST_TABLE_BLOCK) +
              (IX_CC_IPV4_DBCAST_TABLE_BLOCK_SIZE * sizeof(ix_uint32) *
              IX_CC_IPV4_NUMBER_OF_DBCAST_EXTRA_BUCKETS);

    err = ix_rm_mem_alloc(IX_MEMORY_TYPE_SRAM,
                          IX_CC_IPV4_SRAM_CHANNEL_DBCAST_TBL,
                          memSize,
                          (void**)&g_pIpv4Context->pMbDbBase);
    if(err != IX_SUCCESS)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_OOM,
                                ("Memory allocation failed for symbols to be patched"));
    }
     
    /* Initialize the memory with 0s */
    ix_ossl_memset(g_pIpv4Context->pMbDbBase,0,memSize);

    /* Allocate memory for microblock CONTROL BLOCK */
	
    /* In uCode we have ipv4 statistics per port
    we have to change it in Core Components so that no illegal use of 
    SCRATCH is done. This may be a temporary solution */

     memSize = (IX_CC_IPV4_NUMBER_OF_MB_COUNTERS * sizeof(ix_uint32)) *
		MAX_NUMBER_OF_PORTS_PER_BLADE;

    

    err = ix_rm_mem_alloc(IX_MEMORY_TYPE_SRAM,
                          IX_CC_IPV4_SRAM_CHANNEL_CTRL_BLOCK,
                          memSize,
                          (void**)&g_pIpv4Context->pMbCbBase);
    if(err != IX_SUCCESS)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_OOM,
                                ("Memory allocation failed for symbols to be patched"));
    }
     
    /* Initialize the memory with 0s */
    ix_ossl_memset(g_pIpv4Context->pMbCbBase,0,memSize);

#else /* (_IX_HARDWARE_TYPE_ == _IX_HW_2800_) */

    memSize = IX_CC_IPV4_DBCAST_TABLE_BLOCK_SIZE * sizeof(ix_uint32) *
              IX_CC_IPV4_NUMBER_OF_DBCAST_TABLE_BLOCK +
              IX_CC_IPV4_DBCAST_TABLE_BLOCK_SIZE * sizeof(ix_uint32) *
              IX_CC_IPV4_NUMBER_OF_DBCAST_EXTRA_BUCKETS  +
              IX_CC_IPV4_SIZE_OF_CONTROL_BLOCK * sizeof(ix_uint32);

    /* Allocation of memory for  microblock DCAST table and CONTROL BLOCK */
    err = ix_rm_mem_alloc(IX_MEMORY_TYPE_SRAM,
                          IX_CC_IPV4_SRAM_CHANNEL,
                          memSize,
                          (void**)&g_pIpv4Context->pMbBase);
    if(err != IX_SUCCESS)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_OOM,
                                ("Memory allocation failed for symbols to be patched"));
    }/* end if (err != IX_SUCCESS) */
     
    ix_ossl_memset(g_pIpv4Context->pMbBase,0,memSize);
    /*
     * Function successfully allocated memory for control block, 
     * directed broadcast table.
     */

    g_pIpv4Context->pMbCbBase = (ix_cc_ipv4_mb_ctrl*)g_pIpv4Context->pMbBase;
    g_pIpv4Context->pMbDbBase = g_pIpv4Context->pMbBase + IX_CC_IPV4_SIZE_OF_CONTROL_BLOCK;

#endif /* (_IX_HARDWARE_TYPE_ == _IX_HW_2800_) */

    /* Allocate memory for statistics from SCRATCH */
    memSize = IX_CC_IPV4_NUMBER_OF_MB_COUNTERS * sizeof(ix_uint32);

#ifdef IPV4_COUNTERS_SRAM

    err = ix_rm_mem_alloc(IX_MEMORY_TYPE_SRAM,
                          0,
                          memSize,
                          (void**)&g_pIpv4Context->pMbStatsBase);
#else

    err = ix_rm_mem_alloc(IX_MEMORY_TYPE_SCRATCH,
                          0,
                          memSize,
                          (void**)&g_pIpv4Context->pMbStatsBase);
#endif
   
    ix_ossl_memset(g_pIpv4Context->pMbStatsBase,0,memSize);       
  
    return IX_SUCCESS;

}/* end _ix_cc_ipv4_alloc_symbols */



/**
 * NAME: _ix_cc_ipv4_patch_symbols
 *
 * DESCRIPTION: This primitive will be used to patch symbols to ipv4 microblocks. 
 * 
 * @Param:  - IN  none
 *
 * @Param:  - OUT none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * IX_CC_IPV4_ERROR_RTM - error from RTM module
 * IX_CC_IPV4_ERROR_FAILED_PATCHING - failed patching by calling resource manager function
 * 
 */

ix_error _ix_cc_ipv4_patch_symbols()
{
    ix_cc_rtmv4_symbols rtmSymbols;
    ix_imported_symbol ipv4Symbols[IX_CC_IPV4_NUMBER_OF_SYMBOLS]; 
    ix_uint32 ipv4Index;
    ix_memory_type memType;
    ix_uint32 memChannel;
    ix_uint32 memOffset;
    void* pPhysAddr;
    
    /* Get RTM symbols */
    IX_ERROR_CRT(ix_cc_rtmv4_get_symbols(g_pIpv4Context->hRtm, &rtmSymbols),
                IX_CC_IPV4_ERROR_RTM,
                IX_ERROR_LEVEL_WARNING);

    /* Patch base address for statistics,control block and directed broadcast table */

#if (_IX_HARDWARE_TYPE_ == _IX_HW_2800_)

    /* Get the pghysical offset */
    IX_ERROR_CRT(ix_rm_get_phys_offset(g_pIpv4Context->pMbStatsBase,
                                       &memType,
                                       &memChannel,
                                       &memOffset,
                                       &pPhysAddr),
                 IX_CC_IPV4_ERROR_FAILED_PATCHING,
                 IX_ERROR_LEVEL_WARNING); 
    if(memType == IX_MEMORY_TYPE_SRAM)
    {
        IX_CC_SET_SRAM_CHANNEL_INTO_OFFSET(memChannel,memOffset);
    }/* end if memorry type */   
    ipv4Symbols[0].m_Value = memOffset; 
    ipv4Symbols[0].m_Name = IX_CC_IPV4_PATCHNAME_STATS_TABLE;

    IX_ERROR_CRT(ix_rm_get_phys_offset(g_pIpv4Context->pMbDbBase,
                                       &memType,
                                       &memChannel,
                                       &memOffset,
                                       &pPhysAddr),
                 IX_CC_IPV4_ERROR_FAILED_PATCHING,
                 IX_ERROR_LEVEL_WARNING);
    if(memType == IX_MEMORY_TYPE_SRAM)
    {
        IX_CC_SET_SRAM_CHANNEL_INTO_OFFSET(memChannel,memOffset);
    }/* end if memorry type */  
    ipv4Symbols[1].m_Value = memOffset;
    ipv4Symbols[1].m_Name = IX_CC_IPV4_PATCHNAME_DBCAST_TABLE;

    ipv4Symbols[2].m_Value = g_Ipv4RegistryData.localBladeId;
    ipv4Symbols[2].m_Name = IX_CC_IPV4_PATCHNAME_ID;

    ipv4Symbols[3].m_Value = rtmSymbols.lkupTableID;
    ipv4Symbols[3].m_Name = IX_CC_IPV4_PATCHNAME_TRIE_TABLE;

    ipv4Symbols[4].m_Value =rtmSymbols.nextHopBase;
    ipv4Symbols[4].m_Name = IX_CC_IPV4_PATCHNAME_NEXTHOP_TABLE;
 
#else /* (_IX_HARDWARE_TYPE_ != _IX_HW_2800_) */

    /* Get the pghysical offset */
    IX_ERROR_CRT(ix_rm_get_phys_offset(g_pIpv4Context->pMbStatsBase,
                                       &memType,
                                       &memChannel,
                                       &memOffset,
                                       &pPhysAddr),
                 IX_CC_IPV4_ERROR_FAILED_PATCHING,
                 IX_ERROR_LEVEL_WARNING); 
    if(memType == IX_MEMORY_TYPE_SRAM)
    {
        IX_CC_SET_SRAM_CHANNEL_INTO_OFFSET(memChannel,memOffset);
    }/* end if memorry type */   
    ipv4Symbols[0].m_Value = memOffset; 
    ipv4Symbols[0].m_Name = IX_CC_IPV4_PATCHNAME_STATS_TABLE;

    IX_ERROR_CRT(ix_rm_get_phys_offset(g_pIpv4Context->pMbDbBase,
                                       &memType,
                                       &memChannel,
                                       &memOffset,
                                       &pPhysAddr),
                 IX_CC_IPV4_ERROR_FAILED_PATCHING,
                 IX_ERROR_LEVEL_WARNING);
    if(memType == IX_MEMORY_TYPE_SRAM)
    {
        IX_CC_SET_SRAM_CHANNEL_INTO_OFFSET(memChannel,memOffset);
    }/* end if memorry type */  
    ipv4Symbols[1].m_Value = memOffset;
    ipv4Symbols[1].m_Name = IX_CC_IPV4_PATCHNAME_DBCAST_TABLE;

    IX_ERROR_CRT(ix_rm_get_phys_offset(g_pIpv4Context->pMbCbBase,
                                       &memType,
                                       &memChannel,
                                       &memOffset,
                                       &pPhysAddr),
                 IX_CC_IPV4_ERROR_FAILED_PATCHING,
                 IX_ERROR_LEVEL_WARNING);
    if(memType == IX_MEMORY_TYPE_SRAM)
    {
        IX_CC_SET_SRAM_CHANNEL_INTO_OFFSET(memChannel,memOffset);
    }/* end if memorry type */ 
    ipv4Symbols[2].m_Value = memOffset;
    ipv4Symbols[2].m_Name = IX_CC_IPV4_PATCHNAME_CONTROL_BLOCK;


    ipv4Symbols[3].m_Value = g_Ipv4RegistryData.localBladeId;
    ipv4Symbols[3].m_Name = IX_CC_IPV4_PATCHNAME_ID;

    ipv4Symbols[4].m_Value = rtmSymbols.lkupTableID;
    ipv4Symbols[4].m_Name = IX_CC_IPV4_PATCHNAME_TRIE_TABLE;

    ipv4Symbols[5].m_Value =rtmSymbols.nextHopBase;
    ipv4Symbols[5].m_Name = IX_CC_IPV4_PATCHNAME_NEXTHOP_TABLE;
 
#endif /* (_IX_HARDWARE_TYPE_ == _IX_HW_2800_) */

    for (ipv4Index = 0; ipv4Index < IX_CC_IPV4_NUMBER_OF_MICROENGINES; ipv4Index++)
    {
         /* if the bit is set, then patch the symbols */
        if(((g_Ipv4RegistryData.meNumbers) & (1 << ipv4Index)) != 0)
        {
            IX_ERROR_CRT(ix_rm_ueng_patch_symbols(g_aMicroengineNumberMapping[ipv4Index],
                         IX_CC_IPV4_NUMBER_OF_SYMBOLS,ipv4Symbols),
                         IX_CC_IPV4_ERROR_FAILED_PATCHING,
                         IX_ERROR_LEVEL_WARNING);
        }/* end if */
    }/* end for (index = 0; index < IX_CC_IPV4_NUMBER_OF_MICROENGINES; index++) */


    return IX_SUCCESS;
}/* end _ix_cc_ipv4_patch_symbols */




/**
 * NAME: _ix_cc_ipv4_create_64bit_counters
 *
 * DESCRIPTION: This primitive will be used to create 64 bit counters.   .
 * 
 * @Param:  - IN none
 *
 * @Param:  - OUT none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * IX_CC_ERROR_OOM_64BIT_COUNTER - error in creating 64 bit counter
 * 
 * 
 */

ix_error _ix_cc_ipv4_create_64bit_counters()
{
   
    
    /* In uCode we have ipv4 statistics per port
    we have to change it in Core Components so that no iligal use of 
    SCRATCH is done. This may be a temporary solution */

    ix_uint32 portIndex;
	ix_uint32 baseAddress;

   /* Create incoming 64-bit counters */
   for (portIndex = 0; portIndex < MAX_NUMBER_OF_PORTS_PER_BLADE; portIndex++)
   {
       baseAddress = (ix_uint32)((ix_uint32*)g_pIpv4Context->pMbStatsBase + 
                     (IX_CC_IPV4_NUMBER_OF_MB_COUNTERS * portIndex));

       /* Create an array of handles and save them */
       IX_ERROR_CRT(ix_rm_counter_64bit_new(
                                IX_CC_IPV4_NUMBER_OF_MB_COUNTERS,
			        (ix_uint32 *)baseAddress,
                                IX_CC_IPV4_COUNTER_OVERFLOW_TIME,
                                g_pIpv4Context->counter64BitHandle[portIndex].ahCounter64BitHandle),

                    IX_CC_ERROR_OOM_64BIT_COUNTER,
                    IX_ERROR_LEVEL_WARNING);
   }


    return IX_SUCCESS;

}/* end _ix_cc_ipv4_create_64bit_counters */




/**
 * NAME: _ix_cc_ipv4_add_reserved_next_hops
 *
 * DESCRIPTION: This primitive will be used to add reserved next hops into RTM    .
 * 
 * @Param:  - IN none
 *
 * @Param:  - OUT  none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * IX_CC_IPV4_ERROR_RTM - error from RTM
 * 
 * 
 */

ix_error _ix_cc_ipv4_add_reserved_next_hops()
{

    ix_cc_rtmv4_next_hop_info nextHopInfo;
   
    /* Add reserved next hops to RTM - NH_DROP */
    nextHopInfo.bladeID = 0;
    nextHopInfo.l2Index = 0;
    nextHopInfo.portID = 0;
    nextHopInfo.mtu = 1500;
    nextHopInfo.flags = IPV4_NH_FLAGS_DROP_BIT;
    nextHopInfo.ipAddr = 0;
    nextHopInfo.l2IndexType = 0;
    IX_ERROR_CRT(ix_cc_rtmv4_add_next_hop(g_pIpv4Context->hRtm,IX_CC_IPV4_NH_DROP,&nextHopInfo),
                 IX_CC_IPV4_ERROR_RTM,
                 IX_ERROR_LEVEL_WARNING);

    /* Add reserved next hops to RTM - NH_LOCAL */
    nextHopInfo.flags = IPV4_NH_FLAGS_LOCAL_BIT;
    IX_ERROR_CRT(ix_cc_rtmv4_add_next_hop(g_pIpv4Context->hRtm,IX_CC_IPV4_NH_LOCAL,&nextHopInfo),
                 IX_CC_IPV4_ERROR_RTM,
                 IX_ERROR_LEVEL_WARNING);

    /* Add reserved next hops to RTM - NH_BROADCAST */
    nextHopInfo.flags = IPV4_NH_FLAGS_BROADCAST_BIT;
    IX_ERROR_CRT(ix_cc_rtmv4_add_next_hop(g_pIpv4Context->hRtm,IX_CC_IPV4_NH_BROADCAST,&nextHopInfo),
                 IX_CC_IPV4_ERROR_RTM,
                 IX_ERROR_LEVEL_WARNING);

    /* Add reserved next hops to RTM - NH_MULTICAST */
    nextHopInfo.flags = IPV4_NH_FLAGS_MULTICAST_BIT;
    IX_ERROR_CRT(ix_cc_rtmv4_add_next_hop(g_pIpv4Context->hRtm,IX_CC_IPV4_NH_MULTICAST,&nextHopInfo),
                 IX_CC_IPV4_ERROR_RTM,
                 IX_ERROR_LEVEL_WARNING);



    return IX_SUCCESS;
}/* end _ix_cc_ipv4_add_reserved_next_hops */



/**
 * NAME: _ix_cc_ipv4_add_invalid_routes
 *
 * DESCRIPTION: This primitive will be used to add martian addresses to RTM    .
 * 
 * @Param:  - IN none
 *
 * @Param:  - OUT none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * IX_CC_IPV4_ERROR_RTM - error from RTM function call
 * 
 * 
 */

ix_error _ix_cc_ipv4_add_invalid_routes()
{

    /* Add ip address = 0 in RTM */
    /* Packet will be droped if destination IP address is 0 */ 
    IX_ERROR_CRT(ix_cc_rtmv4_add_route(g_pIpv4Context->hRtm,
                                IX_CC_IPV4_DEST_IP_ZERO,
                                IX_CC_IPV4_DEST_IP_ZERO_MASK,
                                IX_CC_IPV4_NH_DROP),
                 IX_CC_IPV4_ERROR_RTM,
                 IX_ERROR_LEVEL_WARNING);


    /* Add loopback address in RTM */
    /* Packet will be droped if destination IP address is a loopback address */ 

    IX_ERROR_CRT(ix_cc_rtmv4_add_route(g_pIpv4Context->hRtm,
                                IX_CC_IPV4_DEST_IP_LOOPBACK,
                                IX_CC_IPV4_DEST_IP_LOOPBACK_MASK,
                                IX_CC_IPV4_NH_DROP),
                 IX_CC_IPV4_ERROR_RTM,
                 IX_ERROR_LEVEL_WARNING);


    /* Add class D address in RTM */ 
    /* A Packet will be sent to local stack if destination IP address is a class D address */ 

    IX_ERROR_CRT(ix_cc_rtmv4_add_route(g_pIpv4Context->hRtm,
                                IX_CC_IPV4_DEST_IP_CLASS_D,
                                IX_CC_IPV4_DEST_IP_CLASS_D_MASK,
                                IX_CC_IPV4_NH_MULTICAST),
                 IX_CC_IPV4_ERROR_RTM,
                 IX_ERROR_LEVEL_WARNING);


     /* Add class E address in RTM */ 
    /* A Packet will be droped if destination IP address is a class E address */ 
    IX_ERROR_CRT(ix_cc_rtmv4_add_route(g_pIpv4Context->hRtm,
                                IX_CC_IPV4_DEST_IP_CLASS_E,
                                IX_CC_IPV4_DEST_IP_CLASS_E_MASK,
                                IX_CC_IPV4_NH_DROP),
                 IX_CC_IPV4_ERROR_RTM,
                 IX_ERROR_LEVEL_WARNING);

    /* Add limited broadcast address in RTM */
    /* Packet will be sent it to local stack if destination IP address is a 
     * limited  broadcast address */ 
    IX_ERROR_CRT(ix_cc_rtmv4_add_route(g_pIpv4Context->hRtm,
                                IX_CC_IPV4_DEST_IP_LIMITED_BROADCAST,
                                IX_CC_IPV4_DEST_IP_LIMITED_BROADCAST_MASK,
                                IX_CC_IPV4_NH_BROADCAST),
                 IX_CC_IPV4_ERROR_RTM,
                 IX_ERROR_LEVEL_WARNING);

    return IX_SUCCESS;
}/* end _ix_cc_ipv4_add_invalid_routes */





/**
 * NAME: _ix_cc_ipv4_configure_rtm
 *
 * DESCRIPTION: This primitive will be used to configure RTM    .
 * 
 * @Param:  - IN none
 *
 * @Param:  - OUT  none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_RTM - error from RTM function
 * 
 */

ix_error _ix_cc_ipv4_configure_rtm()
{

    /* Initalize RTM */
    IX_ERROR_CRT(ix_cc_rtmv4_init(&g_Ipv4RegistryData.rtmConfig,&g_pIpv4Context->hRtm),
                 IX_CC_IPV4_ERROR_RTM,
                 IX_ERROR_LEVEL_WARNING);

    /* Add reserved next hops to RTM */
    IX_ERROR_CR(_ix_cc_ipv4_add_reserved_next_hops());

    /* Add invalide routes to RTM */
    IX_ERROR_CR(_ix_cc_ipv4_add_invalid_routes());

    return IX_SUCCESS;

}/* _ix_cc_ipv4_configure_rtm */
    

/**
 * NAME: _ix_cc_ipv4_register_message_handler
 *
 * DESCRIPTION: This primitive will be used to register message handler. 
 * 
 * @Param:  - IN none
 *
 * @Param:  - OUT  none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_CCI - Error from CCI
 * 
 */

ix_error _ix_cc_ipv4_register_message_handler()
{
    
    /* Call CCI message handler if CCI is enabled */
    #if defined(IX_EXCLUDE_CCI)
        IX_ERROR_CRT(ix_rm_message_handler_register(IX_CC_IPV4_MSG_INPUT,
                                            ix_cc_ipv4_msg_handler,
                                            g_pIpv4Context),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);
    #else
        IX_ERROR_CRT(ix_cci_cc_add_message_handler(g_pIpv4Context->hIpv4Handle,
                                            IX_CC_IPV4_MSG_INPUT,
                                            ix_cc_ipv4_msg_handler,
                                            IX_INPUT_TYPE_MULTI_SRC),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);

    #endif

    return IX_SUCCESS;
}/* end _ix_cc_ipv4_register_message_handler */



/**
 * NAME: _ix_cc_ipv4_register_cci_packet_handlers
 *
 * DESCRIPTION: This primitive will be used to register packet handler with CCI. 
 * @Param:  - IN  none
 *
 * @Param:  - OUT none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_CCI - error from CCI
 * 
 */

ix_error _ix_cc_ipv4_register_cci_packet_handlers()
{

#if !defined(IX_EXCLUDE_CCI)
    /* High priority packet handler needs to be registered as a message handler */
    IX_ERROR_CRT(ix_cci_cc_add_message_handler(g_pIpv4Context->hIpv4Handle,
                                       IX_CC_IPV4_PKT_MICROBLOCK_HIGH_PRIORITY_INPUT,
                                       ix_cc_ipv4_microblock_high_priority_pkt_handler,
                                       IX_INPUT_TYPE_SINGLE_SRC),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);


    IX_ERROR_CRT(ix_cci_cc_add_packet_handler(g_pIpv4Context->hIpv4Handle,
                                       IX_CC_IPV4_PKT_MICROBLOCK_LOW_PRIORITY_INPUT,
                                       ix_cc_ipv4_microblock_low_priority_pkt_handler,
                                       IX_INPUT_TYPE_SINGLE_SRC),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);


    IX_ERROR_CRT(ix_cci_cc_add_packet_handler(g_pIpv4Context->hIpv4Handle,
                                       IX_CC_IPV4_PKT_STKDRV_INPUT,
                                       ix_cc_ipv4_stkdrv_pkt_handler,
                                       IX_INPUT_TYPE_SINGLE_SRC),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);

    IX_ERROR_CRT(ix_cci_cc_add_packet_handler(g_pIpv4Context->hIpv4Handle,
                                       IX_CC_IPV4_PKT_COMMON_INPUT,
                                       ix_cc_ipv4_common_pkt_handler,
                                       IX_INPUT_TYPE_MULTI_SRC),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);
#endif

    return IX_SUCCESS;

}/* end _ix_cc_ipv4_register_cci_packet_handlers */


/**
 * NAME: _ix_cc_ipv4_register_rm_packet_handlers
 *
 * DESCRIPTION: This primitive will be used to register packet handler with resource manager
 *
 * @Param:  - IN none
 *
 * @Param:  - OUT none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_CCI - error from resource manager
 * 
 */

ix_error _ix_cc_ipv4_register_rm_packet_handlers()
{

    IX_ERROR_CRT(ix_rm_message_handler_register(IX_CC_IPV4_PKT_MICROBLOCK_HIGH_PRIORITY_INPUT,
                                        ix_cc_ipv4_microblock_high_priority_pkt_handler,
                                        g_pIpv4Context),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);


    IX_ERROR_CRT(ix_rm_packet_handler_register(IX_CC_IPV4_PKT_MICROBLOCK_LOW_PRIORITY_INPUT,
                                        ix_cc_ipv4_microblock_low_priority_pkt_handler,
                                        g_pIpv4Context),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);


    IX_ERROR_CRT(ix_rm_packet_handler_register(IX_CC_IPV4_PKT_STKDRV_INPUT,
                                        ix_cc_ipv4_stkdrv_pkt_handler,
                                        g_pIpv4Context),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);

    IX_ERROR_CRT(ix_rm_packet_handler_register(IX_CC_IPV4_PKT_COMMON_INPUT,
                                        ix_cc_ipv4_common_pkt_handler,
                                        g_pIpv4Context),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);

    return IX_SUCCESS;

}/* end _ix_cc_ipv4_register_rm_packet_handlers */





/**
 * NAME: _ix_cc_ipv4_register_packet_handlers
 *
 * DESCRIPTION: This primitive will be used to register packet handlers. 
 * It registers with CCI in level 1 system and register with RM in
 * level 0 system.
 * 
 *           .
 * 
 * @Param:  - IN none
 *
 * @Param:  - OUT none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_CCI - error from CCI/resource manager
 * 
 */

ix_error _ix_cc_ipv4_register_packet_handlers()
{
    /* Call CCI packet handler if CCI is enabled */
    #if defined(IX_EXCLUDE_CCI)
        IX_ERROR_CR(_ix_cc_ipv4_register_rm_packet_handlers());
    #else
        IX_ERROR_CR(_ix_cc_ipv4_register_cci_packet_handlers());
    #endif

    return IX_SUCCESS;
}/* end _ix_cc_ipv4_register_packet_handlers */


/**
 * NAME: _ix_cc_ipv4_create_event_handler
 *
 * DESCRIPTION: This primitive is used to create event handler if there is no
 * CCI.This API needs to be implemented by client in LEVEL0 syatem.
 * User needs to call _ix_cc_ipv4_icmp_send_message function periodically
 * to drain ICMP packets from queue. 
 * 
 * @Param:  - IN arg_pContext: IPv4 context
 *
 * @Param:  - OUT arg_pEventId:Event handler Id
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 *  
 * IX_CC_ERROR_UNIMPL - not implemented
 * 
 */

ix_error _ix_cc_ipv4_create_event_handler(void* arg_pContext,
                                          ix_ossl_thread_t* arg_pEventId)
{ 

    return IX_ERROR_WARNING(IX_CC_ERROR_UNIMPL,("No Event Handler for Icmp\n"));
}/* end _ix_cc_ipv4_create_event_handler */


/**
 * NAME: _ix_cc_ipv4_add_icmp_event_handler
 *
 * DESCRIPTION: This primitive will be used to add icmp event handler.This is useful to
 * drain ICMP packets priodically from queue           .
 * 
 * @Param:  - IN  none
 *
 * @Param:  - OUT none
 *
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_IPV4_ERROR_CCI - error from event handler
 * 
 */

ix_error _ix_cc_ipv4_add_icmp_event_handler()
{

    ix_uint32 eventInterval;
    /* Calculate event interval in milliseconds, data in g_IcmpSleepTime is in seconds */
    eventInterval = g_IcmpSleepTime * IX_CC_IPV4_MILLISECONDS_PER_SECOND;

    
    #if defined(IX_EXCLUDE_CCI) /* compile time flag */
        IX_ERROR_CR(_ix_cc_ipv4_create_event_handler(g_pIpv4Context,&g_pIpv4Context->icmpThreadId));
    #else 
        IX_ERROR_CRT(ix_cci_cc_add_event_handler(g_pIpv4Context->hIpv4Handle,
                                          eventInterval,
                                          _ix_cc_ipv4_icmp_send_message,
                                          IX_EVENT_TYPE_PERIODIC,
                                          IX_CC_IPV4_ICMP_EVENT_PRIORITY,
                                          &g_pIpv4Context->hEventHandle),
                 IX_CC_IPV4_ERROR_CCI,
                 IX_ERROR_LEVEL_WARNING);

    #endif


    return IX_SUCCESS;
}/* end _ix_cc_ipv4_add_icmp_event_handler */


/**
 * NAME: ix_cc_ipv4_init
 *
 * DESCRIPTION: This primitive shall be called and returned successfully before requesting any service
 *              from IPv4 Forwarder core component. This primitive should be called only once to initialize 
 *              IPv4 Forwarder core component.This function performs allocation of memory for symbols to be patched,
 *              Creation of 64 bit counters, registration of packet and message handlers,
 *              initialization and configuration of RTM, allocation and initialization of internal data structures
 *              and creation of event handler for ICMP.
 * 
 * @Param:  - IN arg_hCcHandle - handle to IPV4 forwarder core component, created by core component infrastructure; 
 *            this shall be used later to get other (to add event handler) services from core component infrastructure.
 *
 * @Param:  - IN-OUT arg_ppContext - Buffer free list and dynamic property data will be 
 *            given during by system APPs during initialization. Upon successfull completion, 
 *            it represents the location where the pointer to the control block allocated by 
 *            IPv4 Forwarder core component will be stored. The control block is internal to IPv4 
 *            Forwarder core component and it contains information about IPv4 internal data structures, 
 *            allocated memory and other relevant information. Later this pointer to be passed into  
 *            ix_cc_ipv4_fini function for freeing memory and other house keeping operations 
 *            when IPv4 component is being destroyed.  
 * 
 * @Return: IX_SUCCESS if successful or a valid error token for failure.
 *
 * Error Codes:
 * 
 * IX_CC_ERROR_NULL - input parameter arg_ppContext is null
 * IX_CC_ERROR_OOM   - memory allocation failure      
 * IX_CC_IPV4_ERROR_FAILED_PATCHING   - patching failures                      
 * IX_CC_ERROR_OOM_64BIT_COUNTER - 64 bit counter creation failure
 * IX_CC_IPV4_ERROR_REGISTRY  - registry access failures
 * IX_CC_IPV4_ERROR_RTM - failure from RTM core component
 * IX_CC_IPV4_ERROR_CCI - failure from CCI 
 * 
 */

ix_error ix_cc_ipv4_init(
                         ix_cc_handle arg_hCcHandle,
                         void** arg_ppContext
                        )
{
    ix_error err = IX_SUCCESS;

    /* Variables used in retrieving static data from arg_ppContext */
    ix_cc_init_context *pInitCtx;
    ix_cc_properties_node *pPropNode;

    /* Check for argument validity */
    if(arg_ppContext == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_NULL,
                                ("Input parameter(arg_ppContext) is null"));

    }/* end if (arg_ppContext == NULL) */

    /* Allocate memory for IPv4 Context */
    g_pIpv4Context = (ix_cc_ipv4_context*)ix_ossl_malloc(sizeof(ix_cc_ipv4_context));
    if(g_pIpv4Context == NULL)
    {
        return IX_ERROR_WARNING(IX_CC_ERROR_OOM,
                                ("Failed to allocate memory for ipv4 context"));
     }/* end if (g_pIpv4Context == NULL) */

    /* initialize the structure */
    ix_ossl_memset(g_pIpv4Context,0,sizeof(ix_cc_ipv4_context));

    /* store ipv4 component handle in ix_cc_ipv4_context */
    g_pIpv4Context->hIpv4Handle = arg_hCcHandle;

    /* Get the generic init context */
    pInitCtx = (ix_cc_init_context *)*arg_ppContext;
    /* Store free list handle in g_pIpv4Context */
    g_pIpv4Context->hBufferFreeList = pInitCtx->hFreeList;

    /* Retrieve static configuration from registry. If there is no registry, 
     * then the data structure 
     * will be filled with data from header file. */
    #if defined (IX_INCLUDE_REGISTRY)
        IX_ERROR_CG(_ix_cc_ipv4_registry(),err,cleanupContext);
    #else
        g_Ipv4RegistryData.rtmConfig.routeTableSizeHint  = IX_CC_IPV4_ROUTE_TABLE_SIZE_HINT;
        g_Ipv4RegistryData.rtmConfig.lkupType  = IX_CC_IPV4_RTM_LOOKUP_TYPE;
        g_Ipv4RegistryData.rtmConfig.lkupMemType  = IX_CC_IPV4_RTM_LOOKUP_MEMORY_TYPE;
        g_Ipv4RegistryData.rtmConfig.lkupChannel  = IX_CC_IPV4_RTM_LOOKUP_CHANNEL;
        g_Ipv4RegistryData.rtmConfig.nhdbSizeHint  = IX_CC_IPV4_NEXT_HOP_TABLE_SIZE_HINT;
        g_Ipv4RegistryData.rtmConfig.nhdbMemType  = IX_CC_IPV4_NEXT_HOP_MEMORY_TYPE;
        g_Ipv4RegistryData.rtmConfig.nhdbChannel  = IX_CC_IPV4_NEXT_HOP_CHANNEL;        
        g_Ipv4RegistryData.meNumbers  = IX_CC_IPV4_ME;   
    #endif

    /*Initialization and configuration of RTM */
    /* Add reserved next hops to RTM */
    /* Add martian routes to RTM */
    IX_ERROR_CG(_ix_cc_ipv4_configure_rtm(),err,cleanupContext);
   
    /* Allocate memory for symbols to be patched */
    IX_ERROR_CG(_ix_cc_ipv4_alloc_symbols(),err,cleanupRTM);
    /**
     * Retrieve local blade property information from init context 
     * (This will work for both level-1 and level-0 modes)
     */
    pPropNode = pInitCtx->pPropertyList;
    /* Get blade Id from first node */
    if(pPropNode != NULL)
    {
        g_Ipv4RegistryData.localBladeId  = pPropNode->pPropertyInfo->blade_id;
    }/* end if */

    /* Patch symbols */
    IX_ERROR_CG(_ix_cc_ipv4_patch_symbols(),err,cleanupRmMemory);

    /* 64 bit counter creation */
    IX_ERROR_CG(_ix_cc_ipv4_create_64bit_counters(),err,cleanupRmMemory);   
   
    /* Register Message Handler */
    IX_ERROR_CG(_ix_cc_ipv4_register_message_handler(),err,cleanupCounter);

    /* Register Packet Handler */
    IX_ERROR_CG(_ix_cc_ipv4_register_packet_handlers(),err,cleanupMessageHandler);

    /* Get mutex from OSSL */
    err = ix_ossl_mutex_init(IX_OSSL_MUTEX_UNLOCK,&g_pIpv4Context->ipv4Mutex);
    if(err != IX_SUCCESS)
    {
        err = IX_ERROR_WARNING(IX_CC_ERROR_OOR,
                               ("Failed to create mutext"));
        goto cleanupPacketHandlers;

    }/* end if (g_pIpv4Context == NULL) */

    while(pPropNode != NULL)
    {
        ix_uint32 loop_var;
        ix_uint8 flag;

        
        flag = 0;
        for (loop_var = 0;
             loop_var < pPropNode->pPropertyInfo->no_virtual_if;
             loop_var++)
        {
            if (pPropNode->pPropertyInfo->ip_prop[loop_var].ip_version
                == IX_CC_IP_VERSION_IPV4)
            {
                /* The port status update has to be only once for each port */
                if (flag == 0)
                {
                    IX_ERROR_CG(_ix_cc_ipv4_property_update_port_status(
                           pPropNode->pPropertyInfo->port_id, 
                           pPropNode->pPropertyInfo->physical_if_state), 
                           err, cleanupMutex);
                    flag = 1;
                }

                IX_ERROR_CG(_ix_cc_ipv4_property_update_ip_address(
                                IX_CC_SET_PROPERTY_ADD_INTERFACE_IPV4, 
                                pPropNode->pPropertyInfo->blade_id, 
                                pPropNode->pPropertyInfo->port_id, 
                                pPropNode->pPropertyInfo->ip_prop[loop_var].protocol.ipv4_prop.ipv4_address, 
                                pPropNode->pPropertyInfo->ip_prop[loop_var].protocol.ipv4_prop.ipv4_subnet_mask),
                    err, cleanupMutex);
            }
        }
        pPropNode = pPropNode->pNextPropNode;
    }/* end while */

    /* Initalize ICMP */
    _ix_cc_ipv4_icmp_init();

    /* Register event handler */
    IX_ERROR_CG(_ix_cc_ipv4_add_icmp_event_handler(),err, cleanupMutex);
   
    *arg_ppContext = (void *)g_pIpv4Context;
    return IX_SUCCESS;

    cleanupMutex:
    ix_ossl_mutex_fini(g_pIpv4Context->ipv4Mutex); 
    cleanupPacketHandlers:
    _ix_cc_ipv4_unregister_packet_handlers();
    cleanupMessageHandler:
    _ix_cc_ipv4_unregister_message_handler();
    cleanupCounter:
    _ix_cc_ipv4_delete_64bit_counters();
    cleanupRmMemory:
    _ix_cc_ipv4_free_symbols();
    cleanupRTM:
    _ix_cc_ipv4_terminate_rtm_services();
    cleanupContext:
    ix_ossl_free(g_pIpv4Context);

    return err;

} /* end ix_cc_ipv4_init */

