diff options
author | Michael Brown <mcb30@ipxe.org> | 2014-03-02 20:33:35 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2014-03-02 20:33:35 +0000 |
commit | 11963c4f5f235c07380e4004082ca0bcf4aefa40 (patch) | |
tree | 85310531a78e1ed1387b3a80937cc4c508172151 /src/net/ipv4.c | |
parent | c165e8d1fc03c12549e222c65505fe954a199d77 (diff) | |
download | ipxe-11963c4f5f235c07380e4004082ca0bcf4aefa40.tar.gz |
[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.c | 55 |
1 files changed, 45 insertions, 10 deletions
diff --git a/src/net/ipv4.c b/src/net/ipv4.c index b57b2f833..d9a54adeb 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; } |