blob: 3d82ec8da3bcd08c3cad517dc5336a66e7630af8 [file] [log] [blame]
/*
* Copyright (c) 2011, 2014 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "module_tunnel.h"
/* This function returns total bridge entries configured
in a given hash index */
static int Tnl_Get_Hash_Entries(int hash_index)
{
int tot_tunnels = 0;
if (hash_index < 0)
{
int i;
PTnlEntry pTnlEntry;
for (i = 0; i < TNL_MAX_TUNNEL_DMEM; i++)
{
pTnlEntry = &gTNLCtx.tunnel_table[i];
if (pTnlEntry->state != TNL_STATE_FREE)
tot_tunnels++;
}
}
else
{
PTnlEntry pStatTunnelEntry;
struct slist_entry *entry;
slist_for_each(pStatTunnelEntry, entry, &gre_tunnel_cache[hash_index], list)
{
tot_tunnels++;
}
}
return tot_tunnels;
}
/* This function fills in the snapshot of all tunnel entries of a tunnel cache */
static void fill_snapshot(PTNLCommand_query pTnlSnapshot, PTnlEntry pTnlEntry)
{
memset(pTnlSnapshot , 0, sizeof(TNLCommand_query));
pTnlSnapshot->mode = pTnlEntry->mode;
pTnlSnapshot->secure = pTnlEntry->secure;
SFL_memcpy(pTnlSnapshot->name, get_onif_name(pTnlEntry->itf.index), 16);
SFL_memcpy(pTnlSnapshot->local, pTnlEntry->local, IPV6_ADDRESS_LENGTH);
SFL_memcpy(pTnlSnapshot->remote, pTnlEntry->remote, IPV6_ADDRESS_LENGTH);
pTnlSnapshot->fl=pTnlEntry->fl;
pTnlSnapshot->frag_off = pTnlEntry->frag_off;
pTnlSnapshot->enabled = pTnlEntry->state;
pTnlSnapshot->elim = pTnlEntry->elim;
pTnlSnapshot->hlim = pTnlEntry->hlim;
pTnlSnapshot->mtu = pTnlEntry->tnl_mtu;
}
static int Tnl_Get_Hash_Snapshot(int hash_index, int tnl_entries, PTNLCommand_query pTnlSnapshot)
{
int tot_tnls = 0;
PTnlEntry pTnlEntry;
if (hash_index < 0)
{
int i;
for (i = 0; i < TNL_MAX_TUNNEL_DMEM; i++)
{
pTnlEntry = &gTNLCtx.tunnel_table[i];
if (pTnlEntry->state == TNL_STATE_FREE)
continue;
fill_snapshot(pTnlSnapshot, pTnlEntry);
pTnlSnapshot++;
tot_tnls++;
tnl_entries--;
if (tnl_entries == 0)
break;
}
}
else
{
struct slist_entry *entry;
slist_for_each(pTnlEntry, entry, &gre_tunnel_cache[hash_index], list)
{
fill_snapshot(pTnlSnapshot, pTnlEntry);
pTnlSnapshot++;
tot_tnls++;
tnl_entries--;
if (tnl_entries == 0)
break;
}
}
return tot_tnls;
}
U16 Tnl_Get_Next_Hash_Entry(PTNLCommand_query pTnlCmd, int reset_action)
{
int total_tnl_entries;
PTNLCommand_query pTnl;
static PTNLCommand_query pTnlSnapshot = NULL;
static int tnl_hash_index = -1, tnl_snapshot_entries = 0, tnl_snapshot_index = 0;
if(reset_action)
{
tnl_hash_index = -1;
tnl_snapshot_entries = 0;
tnl_snapshot_index = 0;
if (pTnlSnapshot)
{
Heap_Free(pTnlSnapshot);
pTnlSnapshot = NULL;
}
}
if (tnl_snapshot_index == 0)
{
while (tnl_hash_index < NUM_GRE_TUNNEL_ENTRIES)
{
total_tnl_entries = Tnl_Get_Hash_Entries(tnl_hash_index);
if (total_tnl_entries == 0)
{
tnl_hash_index++;
continue;
}
if (pTnlSnapshot)
Heap_Free(pTnlSnapshot);
pTnlSnapshot = Heap_Alloc(total_tnl_entries * sizeof(TNLCommand_query));
if (!pTnlSnapshot)
return ERR_NOT_ENOUGH_MEMORY;
tnl_snapshot_entries = Tnl_Get_Hash_Snapshot(tnl_hash_index, total_tnl_entries, pTnlSnapshot);
break;
}
if (tnl_hash_index >= NUM_GRE_TUNNEL_ENTRIES)
{
tnl_hash_index = -1;
if (pTnlSnapshot)
{
Heap_Free(pTnlSnapshot);
pTnlSnapshot = NULL;
}
return ERR_TNL_ENTRY_NOT_FOUND;
}
}
pTnl = &pTnlSnapshot[tnl_snapshot_index++];
SFL_memcpy(pTnlCmd, pTnl, sizeof(TNLCommand_query));
if (tnl_snapshot_index == tnl_snapshot_entries)
{
tnl_snapshot_index = 0;
tnl_hash_index ++;
}
return NO_ERR;
}
#ifdef CFG_STATS
static void stat_tunnel_get(PTnlEntry pEntry, PStatTunnelEntryResponse snapshot, U32 do_reset)
{
PHw_TnlEntry_gre hw_tnl_entry = pEntry->hw_tnl_entry;
class_statistics_get_ddr(hw_tnl_entry->total_packets_received, &snapshot->total_packets_received,
sizeof(snapshot->total_packets_received), do_reset);
class_statistics_get_ddr(hw_tnl_entry->total_packets_transmitted, &snapshot->total_packets_transmitted,
sizeof(snapshot->total_packets_transmitted), do_reset);
class_statistics_get_ddr(hw_tnl_entry->total_bytes_received, &snapshot->total_bytes_received,
sizeof(snapshot->total_bytes_received), do_reset);
class_statistics_get_ddr(hw_tnl_entry->total_bytes_transmitted, &snapshot->total_bytes_transmitted,
sizeof(snapshot->total_bytes_transmitted), do_reset);
}
void stat_tunnel_reset(PTnlEntry pEntry)
{
StatTunnelEntryResponse temp_snapshot;
stat_tunnel_get(pEntry, &temp_snapshot, TRUE);
}
/* This function fills in the snapshot of all tunnel entries of a tunnel cache along with statistics information*/
static int stat_tunnel_Get_Session_Snapshot(int hash_index, int stat_tunnel_entries, PStatTunnelEntryResponse pStatTunnelSnapshot)
{
int stat_tot_tunnel = 0;
PTnlEntry pStatTunnelEntry;
struct slist_entry *entry;
slist_for_each(pStatTunnelEntry, entry, &gre_tunnel_cache[hash_index], list)
{
memset(pStatTunnelSnapshot, 0, sizeof(StatTunnelEntryResponse));
strcpy((char *)pStatTunnelSnapshot->ifname, get_onif_name(pStatTunnelEntry->itf.index));
stat_tunnel_get(pStatTunnelEntry, pStatTunnelSnapshot, gStatTunnelQueryStatus & STAT_TUNNEL_QUERY_RESET);
pStatTunnelSnapshot++;
stat_tot_tunnel++;
if (--stat_tunnel_entries <= 0)
break;
}
return stat_tot_tunnel;
}
int stat_tunnel_Get_Next_SessionEntry(PStatTunnelEntryResponse pResponse, int reset_action)
{
int stat_total_tunnel_entries;
PStatTunnelStatusCmd pCommand = (PStatTunnelStatusCmd)pResponse;
PStatTunnelEntryResponse pStatTunnel;
static PStatTunnelEntryResponse pStatTunnelSnapshot = NULL;
static int stat_tunnel_hash_index = 0, stat_tunnel_snapshot_entries = 0, stat_tunnel_snapshot_index = 0;
static char stat_tunnel_name[IF_NAME_SIZE];
if(reset_action)
{
stat_tunnel_hash_index = 0;
stat_tunnel_snapshot_entries = 0;
stat_tunnel_snapshot_index = 0;
if (pStatTunnelSnapshot)
{
Heap_Free(pStatTunnelSnapshot);
pStatTunnelSnapshot = NULL;
}
memcpy(stat_tunnel_name, pCommand->ifname, IF_NAME_SIZE - 1);
return NO_ERR;
}
top:
if (stat_tunnel_snapshot_index == 0)
{
while(stat_tunnel_hash_index < NUM_GRE_TUNNEL_ENTRIES)
{
stat_total_tunnel_entries = Tnl_Get_Hash_Entries(stat_tunnel_hash_index);
if (stat_total_tunnel_entries == 0)
{
stat_tunnel_hash_index++;
continue;
}
if(pStatTunnelSnapshot)
Heap_Free(pStatTunnelSnapshot);
pStatTunnelSnapshot = Heap_Alloc(stat_total_tunnel_entries * sizeof(StatTunnelEntryResponse));
if (!pStatTunnelSnapshot)
{
stat_tunnel_hash_index = 0;
return ERR_NOT_ENOUGH_MEMORY;
}
stat_tunnel_snapshot_entries = stat_tunnel_Get_Session_Snapshot(stat_tunnel_hash_index,stat_total_tunnel_entries,pStatTunnelSnapshot);
break;
}
if (stat_tunnel_hash_index >= NUM_GRE_TUNNEL_ENTRIES)
{
stat_tunnel_hash_index = 0;
if(pStatTunnelSnapshot)
{
Heap_Free(pStatTunnelSnapshot);
pStatTunnelSnapshot = NULL;
}
return ERR_TNL_ENTRY_NOT_FOUND;
}
}
pStatTunnel = &pStatTunnelSnapshot[stat_tunnel_snapshot_index++];
SFL_memcpy(pResponse, pStatTunnel, sizeof(StatTunnelEntryResponse));
if (stat_tunnel_snapshot_index == stat_tunnel_snapshot_entries)
{
stat_tunnel_snapshot_index = 0;
stat_tunnel_hash_index++;
}
if (stat_tunnel_name[0])
{
// If name is specified, and no match, keep looking
if (strcmp(stat_tunnel_name, pResponse->ifname) != 0)
goto top;
// If name matches, force EOF on next call
stat_tunnel_hash_index = NUM_GRE_TUNNEL_ENTRIES;
stat_tunnel_snapshot_index = 0;
}
return NO_ERR;
}
#endif // CFG_STATS