929 lines
30 KiB
C
929 lines
30 KiB
C
/*
|
|
******************************************************************************
|
|
* SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_cmd_ctrl.c,v $ $Revision: 1.85.10.8 $
|
|
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_cmd_ctrl.c,v $
|
|
* $Author: svc-cmnet $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
* Prints information about internal structures in IPNET.
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPCOM_KERNEL
|
|
#undef IPCOM_KERNEL
|
|
#endif
|
|
#include "ipnet_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_file.h>
|
|
#include <ipcom_getopt.h>
|
|
|
|
#include "ipnet.h"
|
|
#include "ipnet_cmd.h"
|
|
#include "ipnet_h.h"
|
|
#include "ipnet_peer_info.h"
|
|
#include "ipnet_timeout.h"
|
|
|
|
#ifdef IPTCP
|
|
#include <iptcp.h>
|
|
#endif
|
|
|
|
|
|
#ifdef IPNET_DEBUG
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPNET_CTRL_PRINT_BUF_SIZE 1024*1024
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_PKT_ID_UNINITIALIZED 0xffff
|
|
|
|
#ifdef IPNET_USE_PACKET_POOL
|
|
IP_STATIC Ipcom_cmd_int_str_map ipnet_ctrl_id_map[] =
|
|
{
|
|
{ IPCOM_PKT_ID_INIT, "Init" },
|
|
{ IPCOM_PKT_ID_UNINITIALIZED, "Uninitialized" },
|
|
{ IPCOM_PKT_ID_MALLOC, "Just allocated" },
|
|
{ IPCOM_PKT_ID_RX, "Driver input irq" },
|
|
{ IPCOM_PKT_ID_TX, "Driver output" },
|
|
{ IPCOM_PKT_ID_FREEQ, "Free queue" },
|
|
{ IPCOM_PKT_ID_DELREF, "Delete ref" },
|
|
{ IPCOM_PKT_ID_ADDREF, "Add ref" },
|
|
{ IPCOM_PKT_ID_INPUT, "Pkt input" },
|
|
{ IPCOM_PKT_ID_INQ, "Input queue" },
|
|
{ IPCOM_PKT_ID_OUTQ, "Output queue" },
|
|
{ IPCOM_PKT_ID_NETIF_OUTQ, "Netif output queue" },
|
|
{ IPCOM_PKT_ID_SOCKRECVQ, "Recv. queue" },
|
|
{ IPCOM_PKT_ID_TCP, "TCP" },
|
|
{ IPCOM_PKT_ID_TCP_INPUT, "TCP input" },
|
|
{ IPCOM_PKT_ID_TCP_OUTPUT, "TCP output" },
|
|
{ IPCOM_PKT_ID_TCP_SOCKOOORECVQ, "TCP out-of-order" },
|
|
{ IPCOM_PKT_ID_TCP_RETRANSQ, "TCP retrans. queue" },
|
|
{ IPCOM_PKT_ID_IP4_INPUT, "IPv4 input" },
|
|
{ IPCOM_PKT_ID_IP4_OUTPUT, "IPv4 output" },
|
|
{ IPCOM_PKT_ID_IP4_REASSEMBLY, "IPv4 reassembly" },
|
|
{ IPCOM_PKT_ID_IP6_INPUT, "IPv6 input" },
|
|
{ IPCOM_PKT_ID_IP6_OUTPUT, "IPv6 output" },
|
|
{ IPCOM_PKT_ID_IP6_REASSEMBLY, "IPv6 reassembly" },
|
|
{ IPCOM_PKT_ID_REMOVE, "Removed from queue" },
|
|
{ IPCOM_PKT_ID_IPSEC_INPUT, "input ipsec" },
|
|
{ IPCOM_PKT_ID_IPSEC_OUTPUT, "output ipsec(new)" },
|
|
{ IPCOM_PKT_ID_IPSEC_OUTPUT_ORG, "output ipsec(org)" },
|
|
{ IPCOM_PKT_ID_IPSEC_PF_KEY_IN, "PF_KEY input" },
|
|
{ IPCOM_PKT_ID_PPP, "PPP" },
|
|
{ IPCOM_PKT_ID_PPP_ORGOUT, "PPP orgout" },
|
|
{ IPCOM_PKT_ID_PPP_INPUT, "PPP input" },
|
|
{ IPCOM_PKT_ID_PPP_OUTPUT, "PPP output" },
|
|
{ IPCOM_PKT_ID_RTSOCK, "Route sock" },
|
|
{ IPCOM_PKT_ID_UDP_INPUT, "UDP input" },
|
|
{ IPCOM_PKT_ID_NETIF_DEQUEUE, "Dequeued from netif" },
|
|
{ IPCOM_PKT_ID_SOCKSENDQ, "Send queue" },
|
|
{ IPCOM_PKT_ID_SENT_PIPE, "Send to pipe" },
|
|
{ IPCOM_PKT_ID_RECV_PIPE, "Received from pipe" },
|
|
{ IPCOM_PKT_ID_FRAG, "New fragment" },
|
|
{ IPCOM_PKT_ID_PRE_SEND_SIG, "Before SEND signature" },
|
|
{ IPCOM_PKT_ID_POST_SEND_SIG, "After SEND signature" },
|
|
{ IPCOM_PKT_ID_CACHE, "Packet cache" },
|
|
{ IPCOM_PKT_ID_SCTP_INPUT, "SCTP input" },
|
|
{ IPCOM_PKT_ID_ETH_TX, "Ethernet TX" },
|
|
{ IPCOM_PKT_ID_FWD_TX, "Forwarder TX" },
|
|
{ IPCOM_PKT_ID_TUNNEL_RX, "Tunnel interface RX" },
|
|
{ IPCOM_PKT_ID_TUNNEL_TX, "Tunnel interface TX" },
|
|
{ -1, IP_NULL }
|
|
};
|
|
#endif
|
|
|
|
#define IPNET_CTRL_PKT_FOUND (-2) /* Must no be a valid socket or IP_SOCKERR */
|
|
#define IPNET_CTRL_CREATE_CPU_RETVAL(cpu) ((cpu) - 10000)
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 LOCAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPNET_USE_PACKET_POOL
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_verify_inq
|
|
*===========================================================================
|
|
* Description: Verifies that a packet can be found in the input queue.
|
|
* Parameters: pkt - Packet to find.
|
|
* Returns: IPNET_CTRL_INQ if the packet was found in the input queue,
|
|
* IP_SOCKERR if it was not found.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_ctrl_verify_inq(Ipcom_pkt *pkt)
|
|
{
|
|
Ipcom_pkt *ipkt;
|
|
|
|
for (ipkt = ipnet->task.inq.head; ipkt != IP_NULL; ipkt = ipkt->next)
|
|
if (ipkt == pkt)
|
|
return IPNET_CTRL_PKT_FOUND;
|
|
return IP_SOCKERR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_verify_pkt_cache
|
|
*===========================================================================
|
|
* Description: Verify that this packet can be found in one of the pkt cache.
|
|
* Parameters: pkt - packet to find
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_ctrl_verify_pkt_cache(Ipcom_pkt *pkt)
|
|
{
|
|
Ipnet_pkt_cache_entry *pce;
|
|
int i;
|
|
int ret = IP_SOCKERR;
|
|
|
|
if (pkt->data_freefunc_cookie == (void *)ipnet->slabs.pkt_buf_1500)
|
|
pce = &ipnet->pkt_cache.pkts;
|
|
else
|
|
pce = &ipnet->pkt_cache.hdrs;
|
|
|
|
ipcom_spinlock_lock(&pce->lock);
|
|
for (i = pce->top; i < IPNET_PKT_CACHE_MAX_COUNT; i++)
|
|
if (pce->stack[i] == pkt)
|
|
ret = IPNET_CTRL_PKT_FOUND;
|
|
ipcom_spinlock_unlock(&pce->lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_verify_reassembly
|
|
*===========================================================================
|
|
* Description: Verifies that a packet can be found in the input queue.
|
|
* Parameters: pkt - Packet to find.
|
|
* Returns: IPNET_CTRL_INQ if the packet was found in the reassembly queue,
|
|
* IP_SOCKERR if it was not found.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_ctrl_verify_reassembly(Ipcom_pkt *pkt)
|
|
{
|
|
Ipnet_peer_info **ppeer_info;
|
|
Ipcom_pkt *fragment_list;
|
|
Ipcom_pkt *fragment;
|
|
Ipcom_pkt *pkt_list_head = IP_NULL;
|
|
|
|
ppeer_info = ipcom_pkt_get_info(pkt, IPNET_PKT_INFO_PEER_INFO_PTR);
|
|
if (ppeer_info != IP_NULL)
|
|
pkt_list_head = (*ppeer_info)->reassembly_list;
|
|
|
|
for (fragment_list = pkt_list_head;
|
|
fragment_list != IP_NULL;
|
|
fragment_list = fragment_list->next)
|
|
{
|
|
for (fragment = fragment_list;
|
|
fragment != IP_NULL;
|
|
fragment = fragment->next_fragment)
|
|
if (fragment == pkt)
|
|
return IPNET_CTRL_PKT_FOUND;
|
|
}
|
|
return IP_SOCKERR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_verify_socksendq
|
|
*===========================================================================
|
|
* Description: Verify that the packet is located at one of the sockets
|
|
* send queue.
|
|
* Parameters: pkt - Packet to find.
|
|
* Returns: The socket descriptor where the packet is in send queue.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_fd
|
|
ipnet_ctrl_verify_socksendq(Ipcom_pkt *pkt)
|
|
{
|
|
int i;
|
|
Iptcp_socket *sock;
|
|
|
|
for (i = 0; i < ipnet_conf_max_sockets; i++)
|
|
{
|
|
sock = ipstack->sockets[i];
|
|
if (sock != IP_NULL && pkt == sock->snd_head)
|
|
return sock->ipcom.fd;
|
|
}
|
|
return IP_SOCKERR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_verify_location
|
|
*===========================================================================
|
|
* Description: Verifies that the packet can be found in the location specified
|
|
* by the 'id' field.
|
|
* Parameters: pkt - Packet to find.
|
|
* str - Buffer to print the status.
|
|
* Returns: A description of the location status.
|
|
*
|
|
*/
|
|
IP_STATIC IP_CONST char *
|
|
ipnet_ctrl_verify_location(Ipcom_pkt *pkt, char *str)
|
|
{
|
|
Ip_fd fd;
|
|
enum Ipcom_pkt_id id;
|
|
|
|
id = IPCOM_GET_PKT_ID(pkt);
|
|
switch (id)
|
|
{
|
|
#ifdef IPTCP
|
|
case IPCOM_PKT_ID_TCP_RETRANSQ:
|
|
fd = iptcp_ctrl_verify_retransq(pkt);
|
|
break;
|
|
case IPCOM_PKT_ID_SOCKRECVQ:
|
|
fd = iptcp_ctrl_verify_sockrecvq(pkt);
|
|
break;
|
|
case IPCOM_PKT_ID_TCP_SOCKOOORECVQ:
|
|
fd = iptcp_ctrl_verify_sockooorecvq(pkt);
|
|
break;
|
|
#endif /* IPTCP */
|
|
#ifdef IPCOM_USE_INET
|
|
case IPCOM_PKT_ID_IP4_REASSEMBLY:
|
|
#endif /* IPCOM_USE_INET */
|
|
#ifdef IPCOM_USE_INET6
|
|
case IPCOM_PKT_ID_IP6_REASSEMBLY:
|
|
#endif /* IPCOM_USE_INET6 */
|
|
fd = ipnet_ctrl_verify_reassembly(pkt);
|
|
break;
|
|
case IPCOM_PKT_ID_SOCKSENDQ:
|
|
fd = ipnet_ctrl_verify_socksendq(pkt);
|
|
break;
|
|
|
|
case IPCOM_PKT_ID_INIT:
|
|
case IPCOM_PKT_ID_ADDREF:
|
|
case IPCOM_PKT_ID_DELREF:
|
|
case IPCOM_PKT_ID_RX:
|
|
case IPCOM_PKT_ID_TX:
|
|
case IPCOM_PKT_ID_INPUT:
|
|
case IPCOM_PKT_ID_OUTQ:
|
|
case IPCOM_PKT_ID_NETIF_OUTQ:
|
|
case IPCOM_PKT_ID_TCP:
|
|
case IPCOM_PKT_ID_TCP_INPUT:
|
|
case IPCOM_PKT_ID_TCP_OUTPUT:
|
|
case IPCOM_PKT_ID_IP4_INPUT:
|
|
case IPCOM_PKT_ID_IP4_OUTPUT:
|
|
case IPCOM_PKT_ID_IP6_INPUT:
|
|
case IPCOM_PKT_ID_IP6_OUTPUT:
|
|
case IPCOM_PKT_ID_REMOVE:
|
|
case IPCOM_PKT_ID_IPSEC_INPUT:
|
|
case IPCOM_PKT_ID_IPSEC_OUTPUT:
|
|
case IPCOM_PKT_ID_IPSEC_OUTPUT_ORG:
|
|
case IPCOM_PKT_ID_IPSEC_PF_KEY_IN:
|
|
case IPCOM_PKT_ID_PPP:
|
|
case IPCOM_PKT_ID_PPP_ORGOUT:
|
|
case IPCOM_PKT_ID_PPP_INPUT:
|
|
case IPCOM_PKT_ID_PPP_OUTPUT:
|
|
case IPCOM_PKT_ID_RTSOCK:
|
|
case IPCOM_PKT_ID_UDP_INPUT:
|
|
case IPCOM_PKT_ID_NETIF_DEQUEUE:
|
|
case IPCOM_PKT_ID_PRE_SEND_SIG:
|
|
case IPCOM_PKT_ID_POST_SEND_SIG:
|
|
case IPCOM_PKT_ID_SENT_PIPE:
|
|
case IPCOM_PKT_ID_RECV_PIPE:
|
|
/* Packet is not located in any list in this state */
|
|
return ipcom_strcpy(str, "Can't check");
|
|
case IPCOM_PKT_ID_INQ:
|
|
fd = ipnet_ctrl_verify_inq(pkt);
|
|
break;
|
|
case IPCOM_PKT_ID_CACHE:
|
|
fd = ipnet_ctrl_verify_pkt_cache(pkt);
|
|
break;
|
|
case IPCOM_PKT_ID_FREEQ:
|
|
/* This can only be caused by a bug! */
|
|
return ipcom_strcpy(str, "BUG!");
|
|
default:
|
|
if (id == IPCOM_PKT_ID_UNINITIALIZED)
|
|
ipcom_strcpy(str, "Can't check");
|
|
else
|
|
ipcom_sprintf(str, "Invalid id: %d", id);
|
|
return str;
|
|
}
|
|
if (fd > 0)
|
|
ipcom_sprintf(str, "Yes: sock=%d", fd);
|
|
else if (fd == IP_SOCKERR)
|
|
ipcom_strcpy(str, "No");
|
|
else if (fd == IPNET_CTRL_PKT_FOUND)
|
|
ipcom_strcpy(str, "Yes");
|
|
else
|
|
ipcom_strcpy(str, "BUG!");
|
|
return str;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_print_allocated_packets
|
|
*===========================================================================
|
|
* Description: Prints information about allocated packets
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_ctrl_print_allocated_packets(char *output)
|
|
{
|
|
char str[20];
|
|
int pos;
|
|
Ipcom_pkt *pkt;
|
|
IP_CONST char *if_name;
|
|
Ipnet_netif *netif;
|
|
char *buffer;
|
|
|
|
IPNET_DATA_LOCK(ipnet->pkt_pool_lock);
|
|
|
|
pos = ipcom_snprintf(output, IPNET_CTRL_PRINT_BUF_SIZE,
|
|
"%-6s%-6s%-6s%-6s%-20s%-16s%-6s%-10s%-10s\n",
|
|
"Start", "End", "Max", "Used", "Location", "Loc-verified", "If", "Flags", "Ptr");
|
|
|
|
for (pkt = ipnet->allocated_pkt_list; pkt != IP_NULL; pkt = pkt->next_alloc)
|
|
{
|
|
netif = ipnet_if_indextonetif(IPCOM_VR_ANY, pkt->ifindex);
|
|
if (netif == IP_NULL)
|
|
if_name = "N/A";
|
|
else
|
|
if_name = netif->ipcom.name;
|
|
pos += ipcom_snprintf(output + pos,
|
|
(Ip_size_t) (IPNET_CTRL_PRINT_BUF_SIZE - pos),
|
|
"%-6d%-6d%-6d%-6u%-20s%-16s%-6s%#08x %p\n",
|
|
pkt->start,
|
|
pkt->end,
|
|
pkt->maxlen,
|
|
(unsigned int) pkt->num_allocated,
|
|
ipcom_cmd_key_to_str(ipnet_ctrl_id_map,
|
|
IPCOM_GET_PKT_ID(pkt),
|
|
IP_NULL,
|
|
0),
|
|
ipnet_ctrl_verify_location(pkt, str),
|
|
if_name,
|
|
(unsigned) pkt->flags,
|
|
(void*) pkt);
|
|
}
|
|
|
|
IPNET_DATA_UNLOCK(ipnet->pkt_pool_lock);
|
|
|
|
buffer = ipcom_malloc(1001);
|
|
buffer[1000] = 0;
|
|
pos = 0;
|
|
do
|
|
{
|
|
strncpy( buffer, output+pos, 1000 );
|
|
pos += 1000;
|
|
(void)ipcom_printf("%s", buffer);
|
|
} while ( 1000 == strlen( buffer ) );
|
|
ipcom_free( buffer );
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_print_packets
|
|
*===========================================================================
|
|
* Description: Prints information about allocated packets
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_ctrl_print_packets(char *output)
|
|
{
|
|
int pos = 0;
|
|
Ipcom_pkt *pkt;
|
|
|
|
IPNET_DATA_LOCK(ipnet->pkt_pool_lock);
|
|
|
|
for (pkt = ipnet->allocated_pkt_list; pkt != IP_NULL; pkt = pkt->next_alloc)
|
|
{
|
|
if ( pkt->num_allocated || IPCOM_PKT_GET_REF_COUNT(pkt) )
|
|
{
|
|
unsigned i;
|
|
|
|
pos += ipcom_snprintf(output + pos,
|
|
(Ip_size_t) (IPNET_CTRL_PRINT_BUF_SIZE - pos),
|
|
"%-10p Allocated: %-6u Ref: %-3u\n",
|
|
(void *) pkt,
|
|
(unsigned int) pkt->num_allocated,
|
|
IPCOM_PKT_GET_REF_COUNT(pkt));
|
|
for (i = (pkt->next_trace == 0 ? IPCOM_PKT_TRACE_BUFFER_LEN : pkt->next_trace) - 1;
|
|
i != pkt->next_trace;
|
|
i = (i == 0 ? IPCOM_PKT_TRACE_BUFFER_LEN : i) - 1)
|
|
{
|
|
Ipcom_pkt_trace_buffer *tb = &pkt->trace_buffer[i];
|
|
|
|
pos += ipcom_snprintf(output + pos,
|
|
(Ip_size_t) (IPNET_CTRL_PRINT_BUF_SIZE - pos),
|
|
"\tPID: %u, ID: %-20s %s:%d\n",
|
|
(unsigned) tb->pid,
|
|
ipcom_cmd_key_to_str(ipnet_ctrl_id_map,
|
|
tb->id,
|
|
IP_NULL,
|
|
0),
|
|
tb->file,
|
|
tb->line);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef FIX_ME_NEED_TO_GET_THE_FREE_PACKET_HEADERS_FROM_THE_SLAB_INSTEAD
|
|
for (pkt = ipnet->pkt_hdr_list; pkt != IP_NULL; pkt = pkt->next)
|
|
{
|
|
if ( pkt->num_allocated || IPCOM_PKT_GET_REF_COUNT(pkt) )
|
|
{
|
|
pos += ipcom_snprintf(output + pos,
|
|
(Ip_size_t) (IPNET_CTRL_PRINT_BUF_SIZE - pos),
|
|
"%-10p %-20s Allocated: %-6u Ref: %-3u\n\t%-40s %-6d\n\t%-40s %-6d\n",
|
|
(void *) pkt,
|
|
ipcom_cmd_key_to_str(ipnet_ctrl_id_map, pkt->id, IP_NULL, 0),
|
|
(unsigned int) pkt->num_allocated,
|
|
IPCOM_PKT_GET_REF_COUNT(pkt),
|
|
pkt->alloc_file == IP_NULL ? "*" : pkt->alloc_file,
|
|
pkt->alloc_line,
|
|
pkt->free_file == IP_NULL ? "*" : pkt->free_file,
|
|
pkt->free_line);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
IPNET_DATA_UNLOCK(ipnet->pkt_pool_lock);
|
|
|
|
/*
|
|
* This below instead of a simple printf because printf can't
|
|
* handle that many characters
|
|
*/
|
|
for (pos = 0; ipcom_strlen(output + pos) > 1000; pos += 1000)
|
|
{
|
|
char *end = output + pos + 1000;
|
|
char tkn = *end;
|
|
|
|
*end = '\0';
|
|
(void)ipcom_printf("%s", output + pos);
|
|
*end = tkn;
|
|
}
|
|
(void)ipcom_printf("%s", output + pos);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* IPNET_USE_PACKET_POOL */
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_print_timeouts
|
|
*===========================================================================
|
|
* Description: Prints all running timeouts in IPNET.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_ctrl_print_timeouts(char *output)
|
|
{
|
|
Ipnet_timeout **tmo_elems = IP_NULL;
|
|
int i = 0;
|
|
int j;
|
|
int num_elem;
|
|
int offset = 0;
|
|
Ipnet_cmd_tmo_handler_to_str *map;
|
|
void *suspend_handle;
|
|
Ip_s64 msec;
|
|
|
|
suspend_handle = ipnet_suspend_stack();
|
|
if (suspend_handle == IP_NULL)
|
|
{
|
|
ipcom_printf("Failed to suspend the stack"IP_LF);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Refresh the stack view of the wall clock time. */
|
|
ipnet->msec_now = ipnet_msec_now();
|
|
|
|
tmo_elems = ipcom_malloc((10 + (Ip_size_t)ipcom_pqueue_size(ipnet->timeouts)) * sizeof(*tmo_elems));
|
|
if (tmo_elems == IP_NULL)
|
|
{
|
|
ipnet_resume_stack(suspend_handle);
|
|
ipcom_printf("Timeout dump failed: out of memory" IP_LF);
|
|
goto cleanup;
|
|
}
|
|
|
|
while (IP_NULL != (tmo_elems[i++] = ipcom_pqueue_remove_next(ipnet->timeouts)))
|
|
/* Do nothing */;
|
|
num_elem = i - 1;
|
|
for (i = 0; i < num_elem; i++)
|
|
{
|
|
msec = ipnet_timeout_msec_until(tmo_elems[i]);
|
|
|
|
if (msec / (1000 * 60 * 60 * 2))
|
|
/* More than 2 hours */
|
|
(void)ipcom_snprintf(ipnet->log_buf, sizeof(ipnet->log_buf), "%5u hours ",
|
|
(unsigned) (msec / (1000 * 60 * 60)));
|
|
else if (msec / (1000 * 60 * 2))
|
|
/* More than 2 minutes */
|
|
(void)ipcom_snprintf(ipnet->log_buf, sizeof(ipnet->log_buf), "%5u minutes ",
|
|
(unsigned) (msec / (1000 * 60)));
|
|
else if (msec / (1000 * 2))
|
|
/* More than 2 seconds */
|
|
(void)ipcom_snprintf(ipnet->log_buf, sizeof(ipnet->log_buf), "%5u seconds ",
|
|
(unsigned) (msec / 1000));
|
|
else
|
|
(void)ipcom_snprintf(ipnet->log_buf, sizeof(ipnet->log_buf), "%5u millisec",
|
|
(unsigned) (msec));
|
|
|
|
offset += ipcom_snprintf(&output[offset],
|
|
(Ip_size_t) (IPNET_CTRL_PRINT_BUF_SIZE - offset),
|
|
"%s ", ipnet->log_buf);
|
|
|
|
for (j = 0, map = IP_NULL; map == IP_NULL && j < ipnet->tmo_map_size; j++)
|
|
if (ipnet->tmo_map[j].key == tmo_elems[i]->handler)
|
|
map = &ipnet->tmo_map[j];
|
|
|
|
if (map != IP_NULL)
|
|
offset += map->to_str_func(tmo_elems[i]->cookie, &output[offset], (Ip_size_t) (IPNET_CTRL_PRINT_BUF_SIZE - offset));
|
|
else
|
|
offset += ipcom_snprintf(&output[offset],
|
|
(Ip_size_t) (IPNET_CTRL_PRINT_BUF_SIZE - offset),
|
|
"Handler is at %p",
|
|
tmo_elems[i]->handler);
|
|
offset += ipcom_snprintf(&output[offset], (Ip_size_t) (IPNET_CTRL_PRINT_BUF_SIZE - offset), IP_LF);
|
|
}
|
|
|
|
for (i = 0; i < num_elem; i++)
|
|
(void)ipcom_pqueue_insert(ipnet->timeouts, tmo_elems[i]);
|
|
|
|
ipnet_resume_stack(suspend_handle);
|
|
|
|
for (i = 0; output[i] != '\0'; i++)
|
|
(void)ipcom_printf("%c", output[i]);
|
|
|
|
|
|
cleanup:
|
|
ipcom_free(tmo_elems);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_print_route_entry
|
|
*===========================================================================
|
|
* Description: Prints an internal or leaf node in the route table.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_ctrl_print_route_entry(char *output, Ipcom_route *rtab, Ipcom_route_entry *rt)
|
|
{
|
|
int i;
|
|
Ipcom_route_entry *h;
|
|
|
|
for (h = rt; h->parent; h = h->parent)
|
|
(void)ipcom_sprintf(output + ipcom_strlen(output), " ");
|
|
|
|
if (rt->on)
|
|
(void)ipcom_sprintf(output + ipcom_strlen(output), "bit:%d", rt->bit);
|
|
else
|
|
{
|
|
if (IP_BIT_ISSET(rt->flags, IPCOM_ROUTE_FLAG_INIT))
|
|
(void)ipcom_sprintf(output + ipcom_strlen(output), "#key:");
|
|
else
|
|
(void)ipcom_sprintf(output + ipcom_strlen(output), " key:");
|
|
|
|
for (i = 0; i < rtab->octet_count; i++)
|
|
(void)ipcom_sprintf(output + ipcom_strlen(output), "%02x" , ((Ip_u8*)rt->key)[i]);
|
|
}
|
|
|
|
if (rt->mask)
|
|
{
|
|
(void)ipcom_sprintf(output + ipcom_strlen(output), " mask:");
|
|
for (i = 0; i < rtab->octet_count; i++)
|
|
(void)ipcom_sprintf(output + ipcom_strlen(output), "%02x", ((Ip_u8*)rt->mask)[i]);
|
|
}
|
|
|
|
if (rt->on == IP_NULL && IP_BIT_ISFALSE(rt->flags, IPCOM_ROUTE_FLAG_INIT))
|
|
{
|
|
Ipnet_route_entry *r = (Ipnet_route_entry *) rt;
|
|
void *a = IP_NULL;
|
|
int a_len;
|
|
if (r->gateway != IP_NULL)
|
|
{
|
|
switch (r->gateway->sa_family)
|
|
{
|
|
case IP_AF_INET:
|
|
a = &((struct Ip_sockaddr_in *)r->gateway)->sin_addr;
|
|
a_len = 4;
|
|
break;
|
|
case IP_AF_INET6:
|
|
a = &((struct Ip_sockaddr_in6 *)r->gateway)->sin6_addr;
|
|
a_len = 16;
|
|
break;
|
|
case IP_AF_LINK:
|
|
a = IP_SOCKADDR_DL_LLADDR(r->gateway);
|
|
a_len = ((struct Ip_sockaddr_dl *)r->gateway)->sdl_alen;
|
|
break;
|
|
default:
|
|
a_len = 0;
|
|
break;
|
|
}
|
|
if (a_len)
|
|
{
|
|
(void)ipcom_sprintf(output + ipcom_strlen(output), " gw:");
|
|
|
|
for (i = 0; i < a_len; i++)
|
|
(void)ipcom_sprintf(output + ipcom_strlen(output), "%02x", ((Ip_u8*)a)[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
ipcom_sprintf(output + ipcom_strlen(output), " flags:%08x", (unsigned) rt->flags);
|
|
(void)ipcom_sprintf(output + ipcom_strlen(output), IP_LF);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_inorder_route_dump
|
|
*===========================================================================
|
|
* Description: Walks through the entire route table and print every node.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_ctrl_inorder_route_dump(char *output, Ipcom_route *rtab, Ipcom_route_entry *rt)
|
|
{
|
|
if (rt == IP_NULL)
|
|
return;
|
|
|
|
ipnet_ctrl_inorder_route_dump(output, rtab, rt->on);
|
|
|
|
if (rt->on == IP_FALSE && IP_BIT_ISFALSE(rt->flags, IPCOM_ROUTE_FLAG_INIT))
|
|
ipnet_ctrl_inorder_route_dump(output, rtab, &((Ipnet_route_entry *) rt)->narrow->hdr);
|
|
|
|
ipnet_ctrl_print_route_entry(output, rtab, rt);
|
|
|
|
if (rt->on == IP_FALSE && IP_BIT_ISFALSE(rt->flags, IPCOM_ROUTE_FLAG_INIT))
|
|
ipnet_ctrl_inorder_route_dump(output, rtab, &((Ipnet_route_entry *) rt)->next->hdr);
|
|
ipnet_ctrl_inorder_route_dump(output, rtab, rt->off);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_dump_route_table
|
|
*===========================================================================
|
|
* Description: Prints all routes in a route table.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
#ifdef IPTESTENGINE
|
|
IP_GLOBAL int ipnet_ctrl_dump_route_table(char *output, int domain, Ip_u16 vrtab, Ip_u32 table);
|
|
IP_GLOBAL int
|
|
#else
|
|
IP_STATIC int
|
|
#endif
|
|
ipnet_ctrl_dump_route_table(char *output, int domain, Ip_u16 vrtab, Ip_u32 table)
|
|
{
|
|
Ipcom_route *rtab;
|
|
|
|
if (ipnet_route_get_rtab(domain, vrtab, table, &rtab) < 0)
|
|
{
|
|
ipcom_printf("Failed to get route table for domain %d, virtual router %d and table ID %d"IP_LF,
|
|
domain, vrtab, table);
|
|
return -1;
|
|
}
|
|
output[0] = '\0';
|
|
ipnet_ctrl_inorder_route_dump(output, rtab, rtab->top);
|
|
(void)ipcom_printf("%s", output);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_suspend_stack
|
|
*===========================================================================
|
|
* Description: Suspends the stack for the specified number of seconds
|
|
* Parameters: sec - number of seconds to suspend the stack.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_ctrl_suspend_stack(unsigned int sec)
|
|
{
|
|
void *suspend_handle;
|
|
|
|
suspend_handle = ipnet_suspend_stack();
|
|
if (suspend_handle == IP_NULL)
|
|
ipcom_printf("Stack could not resume\n");
|
|
else
|
|
{
|
|
ipcom_sleep(sec);
|
|
ipnet_resume_stack(suspend_handle);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_ctrl_print_usage
|
|
*===========================================================================
|
|
* Description: Prints usage for the shell command.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_ctrl_print_usage(void)
|
|
{
|
|
ipcom_printf("\n");
|
|
ipcom_printf("NAME\n");
|
|
ipcom_printf(" ipnet_ctrl - control functions for IPNET\n");
|
|
ipcom_printf(" WARNING: this command will access datastructures internal to IPNET\n");
|
|
ipcom_printf(" and does it in a way that might not work on all OS:es.\n");
|
|
ipcom_printf(" This command is only debug tool for the stack and is only guaranteed\n");
|
|
ipcom_printf(" to work on the user-mode Linux port\n");
|
|
ipcom_printf("\n");
|
|
ipcom_printf("SYNOPSIS\n");
|
|
ipcom_printf(" ipnet_ctrl -p\n");
|
|
ipcom_printf(" ipnet_ctrl -a\n");
|
|
ipcom_printf(" ipnet_ctrl -t\n");
|
|
ipcom_printf(" ipnet_ctrl -r <domain>:<virtrt>\n");
|
|
ipcom_printf("\n");
|
|
ipcom_printf("DESCRIPTION\n");
|
|
ipcom_printf(" ipnet_ctrl is used to check the internal state of the IPNET stack.\n");
|
|
ipcom_printf("\n");
|
|
ipcom_printf(" -p\n"
|
|
" List all allocated packets in the system.\n"
|
|
" -a\n"
|
|
" List all packets in the system.\n"
|
|
" -t\n"
|
|
" List all timeouts.\n"
|
|
" -r <domain>[:<VR>[:<table>]]\n"
|
|
" Dump the routing table.\n"
|
|
" -s <sec>\n"
|
|
" Suspend the stack for <sec> seconds\n"
|
|
"\n");
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_cmd_ctrl
|
|
*===========================================================================
|
|
* Description: Shell command to view internal structures.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipnet_cmd_ctrl(int argc, char **argv)
|
|
{
|
|
Ipcom_getopt opt;
|
|
int c;
|
|
char *output;
|
|
int ret = 0;
|
|
int domain;
|
|
Ip_u16 vrtab = 0;
|
|
Ip_u32 table = IPCOM_ROUTE_TABLE_DEFAULT;
|
|
char *s;
|
|
char *p;
|
|
Ip_bool print_usage = IP_TRUE;
|
|
|
|
output = ipcom_malloc(IPNET_CTRL_PRINT_BUF_SIZE);
|
|
if (output == IP_NULL)
|
|
{
|
|
ipcom_printf("Out of memory for display buffer\n");
|
|
return -1;
|
|
}
|
|
output[0] = '\0';
|
|
|
|
ipcom_getopt_clear_r(&opt);
|
|
while ((c = ipcom_getopt_r(argc, argv, "patr:s:", &opt)) != -1)
|
|
{
|
|
print_usage = IP_FALSE;
|
|
switch (c)
|
|
{
|
|
#ifdef IPNET_USE_PACKET_POOL
|
|
case 'p':
|
|
ret = ipnet_ctrl_print_allocated_packets(output);
|
|
break;
|
|
case 'a':
|
|
ret = ipnet_ctrl_print_packets(output);
|
|
break;
|
|
#endif /* IPNET_USE_PACKET_POOL */
|
|
case 't':
|
|
ret = ipnet_ctrl_print_timeouts(output);
|
|
break;
|
|
case 'r':
|
|
print_usage = IP_TRUE;
|
|
s = ipcom_strtok_r(opt.optarg, ":", &p);
|
|
domain = ipcom_atoi(s);
|
|
s = ipcom_strtok_r(IP_NULL, ":"IP_LF, &p);
|
|
if (s != IP_NULL)
|
|
{
|
|
vrtab = (Ip_u16) ipcom_atoi(s);
|
|
s = ipcom_strtok_r(IP_NULL, IP_LF, &p);
|
|
if (s != IP_NULL)
|
|
table = (Ip_u32) ipcom_atoi(s);
|
|
}
|
|
ret = ipnet_ctrl_dump_route_table(output, domain, vrtab, table);
|
|
print_usage = IP_FALSE;
|
|
break;
|
|
case 's':
|
|
ipnet_ctrl_suspend_stack((unsigned int)ipcom_strtoul(opt.optarg, (char **)IP_NULL, 10));
|
|
break;
|
|
default:
|
|
print_usage = IP_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ipcom_free(output);
|
|
if (print_usage)
|
|
ipnet_ctrl_print_usage();
|
|
return ret;
|
|
}
|
|
|
|
#endif /* IPNET_DEBUG */
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|