summaryrefslogtreecommitdiffstats
path: root/src/net/ipv4.c
diff options
context:
space:
mode:
authorMichael Brown2014-03-02 21:33:35 +0100
committerMichael Brown2014-03-02 21:33:35 +0100
commit11963c4f5f235c07380e4004082ca0bcf4aefa40 (patch)
tree85310531a78e1ed1387b3a80937cc4c508172151 /src/net/ipv4.c
parent[image] Ensure every image has a fully resolved URI (diff)
downloadipxe-11963c4f5f235c07380e4004082ca0bcf4aefa40.tar.gz
ipxe-11963c4f5f235c07380e4004082ca0bcf4aefa40.tar.xz
ipxe-11963c4f5f235c07380e4004082ca0bcf4aefa40.zip
[tcpip] Add IP statistics collection as per RFC 4293
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net/ipv4.c')
-rw-r--r--src/net/ipv4.c55
1 files changed, 45 insertions, 10 deletions
diff --git a/src/net/ipv4.c b/src/net/ipv4.c
index b57b2f83..d9a54ade 100644
--- a/src/net/ipv4.c
+++ b/src/net/ipv4.c
@@ -15,6 +15,7 @@
#include <ipxe/dhcp.h>
#include <ipxe/settings.h>
#include <ipxe/fragment.h>
+#include <ipxe/ipstat.h>
/** @file
*
@@ -30,6 +31,16 @@ static uint8_t next_ident_high = 0;
/** List of IPv4 miniroutes */
struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
+/** IPv4 statistics */
+static struct ip_statistics ipv4_stats;
+
+/** IPv4 statistics family */
+struct ip_statistics_family
+ipv4_stats_family __ip_statistics_family ( IP_STATISTICS_IPV4 ) = {
+ .version = 4,
+ .stats = &ipv4_stats,
+};
+
/**
* Add IPv4 minirouting table entry
*
@@ -178,6 +189,7 @@ static struct fragment_reassembler ipv4_reassembler = {
.is_fragment = ipv4_is_fragment,
.fragment_offset = ipv4_fragment_offset,
.more_fragments = ipv4_more_fragments,
+ .stats = &ipv4_stats,
};
/**
@@ -232,6 +244,9 @@ static int ipv4_tx ( struct io_buffer *iobuf,
const void *ll_dest;
int rc;
+ /* Update statistics */
+ ipv4_stats.out_requests++;
+
/* Fill up the IP header, except source address */
memset ( iphdr, 0, sizeof ( *iphdr ) );
iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
@@ -255,6 +270,7 @@ static int ipv4_tx ( struct io_buffer *iobuf,
if ( ! netdev ) {
DBGC ( sin_dest->sin_addr, "IPv4 has no route to %s\n",
inet_ntoa ( iphdr->dest ) );
+ ipv4_stats.out_no_routes++;
rc = -ENETUNREACH;
goto err;
}
@@ -282,9 +298,11 @@ static int ipv4_tx ( struct io_buffer *iobuf,
/* Calculate link-layer destination address, if possible */
if ( ( ( next_hop.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0){
/* Broadcast address */
+ ipv4_stats.out_bcast_pkts++;
ll_dest = netdev->ll_broadcast;
} else if ( IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) {
/* Multicast address */
+ ipv4_stats.out_mcast_pkts++;
if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET, &next_hop,
ll_dest_buf ) ) !=0){
DBGC ( sin_dest->sin_addr, "IPv4 could not hash "
@@ -298,6 +316,10 @@ static int ipv4_tx ( struct io_buffer *iobuf,
ll_dest = NULL;
}
+ /* Update statistics */
+ ipv4_stats.out_transmits++;
+ ipv4_stats.out_octets += iob_len ( iobuf );
+
/* Hand off to link layer (via ARP if applicable) */
if ( ll_dest ) {
if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest,
@@ -389,43 +411,53 @@ static int ipv4_rx ( struct io_buffer *iobuf,
uint16_t pshdr_csum;
int rc;
+ /* Update statistics */
+ ipv4_stats.in_receives++;
+ ipv4_stats.in_octets += iob_len ( iobuf );
+ if ( flags & LL_BROADCAST ) {
+ ipv4_stats.in_bcast_pkts++;
+ } else if ( flags & LL_MULTICAST ) {
+ ipv4_stats.in_mcast_pkts++;
+ }
+
/* Sanity check the IPv4 header */
if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
DBGC ( iphdr->src, "IPv4 packet too short at %zd bytes (min "
"%zd bytes)\n", iob_len ( iobuf ), sizeof ( *iphdr ) );
- goto err;
+ goto err_header;
}
if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
DBGC ( iphdr->src, "IPv4 version %#02x not supported\n",
iphdr->verhdrlen );
- goto err;
+ goto err_header;
}
hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
if ( hdrlen < sizeof ( *iphdr ) ) {
DBGC ( iphdr->src, "IPv4 header too short at %zd bytes (min "
"%zd bytes)\n", hdrlen, sizeof ( *iphdr ) );
- goto err;
+ goto err_header;
}
if ( hdrlen > iob_len ( iobuf ) ) {
DBGC ( iphdr->src, "IPv4 header too long at %zd bytes "
"(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
- goto err;
+ goto err_header;
}
if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
DBGC ( iphdr->src, "IPv4 checksum incorrect (is %04x "
"including checksum field, should be 0000)\n", csum );
- goto err;
+ goto err_header;
}
len = ntohs ( iphdr->len );
if ( len < hdrlen ) {
DBGC ( iphdr->src, "IPv4 length too short at %zd bytes "
"(header is %zd bytes)\n", len, hdrlen );
- goto err;
+ goto err_header;
}
if ( len > iob_len ( iobuf ) ) {
DBGC ( iphdr->src, "IPv4 length too long at %zd bytes "
"(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
- goto err;
+ ipv4_stats.in_truncated_pkts++;
+ goto err_other;
}
/* Truncate packet to correct length */
@@ -443,7 +475,8 @@ static int ipv4_rx ( struct io_buffer *iobuf,
( ! ipv4_has_addr ( netdev, iphdr->dest ) ) ) {
DBGC ( iphdr->src, "IPv4 discarding non-local unicast packet "
"for %s\n", inet_ntoa ( iphdr->dest ) );
- goto err;
+ ipv4_stats.in_addr_errors++;
+ goto err_other;
}
/* Perform fragment reassembly if applicable */
@@ -470,7 +503,7 @@ static int ipv4_rx ( struct io_buffer *iobuf,
pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
iob_pull ( iobuf, hdrlen );
if ( ( rc = tcpip_rx ( iobuf, netdev, iphdr->protocol, &src.st,
- &dest.st, pshdr_csum ) ) != 0 ) {
+ &dest.st, pshdr_csum, &ipv4_stats ) ) != 0 ) {
DBGC ( src.sin.sin_addr, "IPv4 received packet rejected by "
"stack: %s\n", strerror ( rc ) );
return rc;
@@ -478,7 +511,9 @@ static int ipv4_rx ( struct io_buffer *iobuf,
return 0;
- err:
+ err_header:
+ ipv4_stats.in_hdr_errors++;
+ err_other:
free_iob ( iobuf );
return -EINVAL;
}