mirror of
https://github.com/ipxe/ipxe
synced 2026-01-21 09:57:23 +03:00
[tcp] Report TCP statistics via the "ipstat" command
Gather some basic statistics on TCP connections to allow out-of-order packets and duplicate packets to be observed even in non-debug builds. Report these statistics via the existing "ipstat" command, rather than introducing a separate "tcpstat" command, on the basis that we do not need the additional overhead of a separate command. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -439,6 +439,23 @@ static inline int tcp_in_window ( uint32_t seq, uint32_t start,
|
|||||||
*/
|
*/
|
||||||
#define TCP_FINISH_TIMEOUT ( 1 * TICKS_PER_SEC )
|
#define TCP_FINISH_TIMEOUT ( 1 * TICKS_PER_SEC )
|
||||||
|
|
||||||
|
/** TCP statistics */
|
||||||
|
struct tcp_statistics {
|
||||||
|
/** Number of packets received */
|
||||||
|
unsigned long in_segs;
|
||||||
|
/** Total number of packets discarded due to lack of memory */
|
||||||
|
unsigned long in_discards;
|
||||||
|
/** Total number of packets received out of order */
|
||||||
|
unsigned long in_out_of_order;
|
||||||
|
|
||||||
|
/** Number of octets received (including duplicate data) */
|
||||||
|
unsigned long in_octets;
|
||||||
|
/** Number of octets processed and passed to upper layer */
|
||||||
|
unsigned long in_octets_good;
|
||||||
|
};
|
||||||
|
|
||||||
extern struct tcpip_protocol tcp_protocol __tcpip_protocol;
|
extern struct tcpip_protocol tcp_protocol __tcpip_protocol;
|
||||||
|
|
||||||
|
extern struct tcp_statistics tcp_stats;
|
||||||
|
|
||||||
#endif /* _IPXE_TCP_H */
|
#endif /* _IPXE_TCP_H */
|
||||||
|
|||||||
@@ -167,6 +167,9 @@ struct tcp_rx_queued_header {
|
|||||||
*/
|
*/
|
||||||
static LIST_HEAD ( tcp_conns );
|
static LIST_HEAD ( tcp_conns );
|
||||||
|
|
||||||
|
/** TCP statistics */
|
||||||
|
struct tcp_statistics tcp_stats;
|
||||||
|
|
||||||
/** Transmit profiler */
|
/** Transmit profiler */
|
||||||
static struct profiler tcp_tx_profiler __profiler = { .name = "tcp.tx" };
|
static struct profiler tcp_tx_profiler __profiler = { .name = "tcp.tx" };
|
||||||
|
|
||||||
@@ -1216,6 +1219,9 @@ static int tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq,
|
|||||||
/* Acknowledge new data */
|
/* Acknowledge new data */
|
||||||
tcp_rx_seq ( tcp, len );
|
tcp_rx_seq ( tcp, len );
|
||||||
|
|
||||||
|
/* Update statistics */
|
||||||
|
tcp_stats.in_octets_good += len;
|
||||||
|
|
||||||
/* Deliver data to application */
|
/* Deliver data to application */
|
||||||
profile_start ( &tcp_xfer_profiler );
|
profile_start ( &tcp_xfer_profiler );
|
||||||
if ( ( rc = xfer_deliver_iob ( &tcp->xfer, iobuf ) ) != 0 ) {
|
if ( ( rc = xfer_deliver_iob ( &tcp->xfer, iobuf ) ) != 0 ) {
|
||||||
@@ -1299,6 +1305,7 @@ static void tcp_rx_enqueue ( struct tcp_connection *tcp, uint32_t seq,
|
|||||||
size_t len;
|
size_t len;
|
||||||
uint32_t seq_len;
|
uint32_t seq_len;
|
||||||
uint32_t nxt;
|
uint32_t nxt;
|
||||||
|
uint32_t gap;
|
||||||
|
|
||||||
/* Calculate remaining flags and sequence length. Note that
|
/* Calculate remaining flags and sequence length. Note that
|
||||||
* SYN, if present, has already been processed by this point.
|
* SYN, if present, has already been processed by this point.
|
||||||
@@ -1330,12 +1337,18 @@ static void tcp_rx_enqueue ( struct tcp_connection *tcp, uint32_t seq,
|
|||||||
tcpqhdr->flags = flags;
|
tcpqhdr->flags = flags;
|
||||||
|
|
||||||
/* Add to RX queue */
|
/* Add to RX queue */
|
||||||
|
gap = tcp->rcv_ack;
|
||||||
list_for_each_entry ( queued, &tcp->rx_queue, list ) {
|
list_for_each_entry ( queued, &tcp->rx_queue, list ) {
|
||||||
tcpqhdr = queued->data;
|
tcpqhdr = queued->data;
|
||||||
if ( tcp_cmp ( seq, tcpqhdr->seq ) < 0 )
|
if ( tcp_cmp ( seq, tcpqhdr->seq ) < 0 )
|
||||||
break;
|
break;
|
||||||
|
gap = tcpqhdr->nxt;
|
||||||
}
|
}
|
||||||
list_add_tail ( &iobuf->list, &queued->list );
|
list_add_tail ( &iobuf->list, &queued->list );
|
||||||
|
|
||||||
|
/* Update statistics */
|
||||||
|
if ( seq != gap )
|
||||||
|
tcp_stats.in_out_of_order++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1459,6 +1472,10 @@ static int tcp_rx ( struct io_buffer *iobuf,
|
|||||||
seq_len = ( len + ( ( flags & TCP_SYN ) ? 1 : 0 ) +
|
seq_len = ( len + ( ( flags & TCP_SYN ) ? 1 : 0 ) +
|
||||||
( ( flags & TCP_FIN ) ? 1 : 0 ) );
|
( ( flags & TCP_FIN ) ? 1 : 0 ) );
|
||||||
|
|
||||||
|
/* Update statistics */
|
||||||
|
tcp_stats.in_segs++;
|
||||||
|
tcp_stats.in_octets += len;
|
||||||
|
|
||||||
/* Dump header */
|
/* Dump header */
|
||||||
DBGC2 ( tcp, "TCP %p RX %d<-%d %08x %08x..%08x %4zd",
|
DBGC2 ( tcp, "TCP %p RX %d<-%d %08x %08x..%08x %4zd",
|
||||||
tcp, ntohs ( tcphdr->dest ), ntohs ( tcphdr->src ),
|
tcp, ntohs ( tcphdr->dest ), ntohs ( tcphdr->src ),
|
||||||
@@ -1569,6 +1586,9 @@ static unsigned int tcp_discard ( void ) {
|
|||||||
list_del ( &iobuf->list );
|
list_del ( &iobuf->list );
|
||||||
free_iob ( iobuf );
|
free_iob ( iobuf );
|
||||||
|
|
||||||
|
/* Update statistics */
|
||||||
|
tcp_stats.in_discards++;
|
||||||
|
|
||||||
/* Report discard */
|
/* Report discard */
|
||||||
discarded++;
|
discarded++;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -24,23 +24,25 @@
|
|||||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <ipxe/tcp.h>
|
||||||
#include <ipxe/ipstat.h>
|
#include <ipxe/ipstat.h>
|
||||||
#include <usr/ipstat.h>
|
#include <usr/ipstat.h>
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
*
|
*
|
||||||
* IP statistics
|
* TCP/IP statistics
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print IP statistics
|
* Print TCP/IP statistics
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void ipstat ( void ) {
|
void ipstat ( void ) {
|
||||||
struct ip_statistics_family *family;
|
struct ip_statistics_family *family;
|
||||||
struct ip_statistics *stats;
|
struct ip_statistics *stats;
|
||||||
|
|
||||||
|
/* Print per-family statistics */
|
||||||
for_each_table_entry ( family, IP_STATISTICS_FAMILIES ) {
|
for_each_table_entry ( family, IP_STATISTICS_FAMILIES ) {
|
||||||
stats = family->stats;
|
stats = family->stats;
|
||||||
printf ( "IP version %d:\n", family->version );
|
printf ( "IP version %d:\n", family->version );
|
||||||
@@ -63,4 +65,12 @@ void ipstat ( void ) {
|
|||||||
stats->out_mcast_pkts, stats->out_bcast_pkts,
|
stats->out_mcast_pkts, stats->out_bcast_pkts,
|
||||||
stats->out_octets );
|
stats->out_octets );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Print TCP statistics */
|
||||||
|
printf ( "TCP:\n" );
|
||||||
|
printf ( " InSegs:%ld InOctets:%ld InOctetsGood:%ld\n",
|
||||||
|
tcp_stats.in_segs, tcp_stats.in_octets,
|
||||||
|
tcp_stats.in_octets_good );
|
||||||
|
printf ( " InDiscards:%ld InOutOfOrder:%ld\n",
|
||||||
|
tcp_stats.in_discards, tcp_stats.in_out_of_order );
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user