]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[tcpip] Add IP statistics collection as per RFC 4293
authorMichael Brown <mcb30@ipxe.org>
Sun, 2 Mar 2014 20:33:35 +0000 (20:33 +0000)
committerMichael Brown <mcb30@ipxe.org>
Sun, 2 Mar 2014 20:33:35 +0000 (20:33 +0000)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/include/ipxe/fragment.h
src/include/ipxe/ipstat.h [new file with mode: 0644]
src/include/ipxe/tcpip.h
src/net/fragment.c
src/net/ipv4.c
src/net/ipv6.c
src/net/tcpip.c

index 6b47439d56991bd0d423aac1cd8cea0116f17d8f..e311ad1e460c57a4e20a836bc7802237bb24b15f 100644 (file)
@@ -27,6 +27,8 @@ struct fragment {
        size_t hdrlen;
        /** Reassembly timer */
        struct retry_timer timer;
+       /** Fragment reassembler */
+       struct fragment_reassembler *fragments;
 };
 
 /** A fragment reassembler */
@@ -59,6 +61,8 @@ struct fragment_reassembler {
         * @ret more_frags      More fragments exist
         */
        int ( * more_fragments ) ( struct io_buffer *iobuf, size_t hdrlen );
+       /** Associated IP statistics */
+       struct ip_statistics *stats;
 };
 
 extern struct io_buffer *
diff --git a/src/include/ipxe/ipstat.h b/src/include/ipxe/ipstat.h
new file mode 100644 (file)
index 0000000..c554c18
--- /dev/null
@@ -0,0 +1,187 @@
+#ifndef _IPXE_IPSTATS_H
+#define _IPXE_IPSTATS_H
+
+/** @file
+ *
+ * IP statistics
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/tables.h>
+
+struct io_buffer;
+
+/** IP system statistics
+ *
+ * Definitions are taken from the RFC4293 section 5
+ * "ipSystemStatsEntry" table.
+ *
+ * To minimise code size, we use "unsigned long" as the counter
+ * variable type regardless of whether this type is 32-bit or 64-bit.
+ * On a 32-bit build (e.g. the standard BIOS build), this means that
+ * we omit the "high capacity" 64-bit counters (prefixed with "HC").
+ * This reduces the code size required to maintain the counter values,
+ * and avoids the need to support the "%lld" format in vsprintf.c
+ * (which would require dragging in the 64-bit division library on a
+ * standard 32-bit build).  Since total available memory in a 32-bit
+ * environment is limited to 4GB, it is unlikely that we will overflow
+ * even the 32-bit octet counters under normal operation.
+ *
+ * Counters relating to packet forwarding are omitted, since iPXE
+ * includes no functionality for acting as a router.
+ *
+ * Counters related to output fragmentation are omitted, since iPXE
+ * has no support for fragmenting transmitted packets.
+ *
+ * The ipSystemStatsInDiscards and ipSystemStatsOutDiscards counters
+ * are omitted, since they will always be zero.
+ *
+ * Separate octet counters for multicast packets are omitted to save
+ * code size.
+ */
+struct ip_statistics {
+       /** ipSystemStatsInReceives
+        *
+        * The total number of input IP datagrams received, including
+        * those received in error.
+        */
+       unsigned long in_receives;
+       /** ipSystemStatsInOctets
+        *
+        * The total number of octets received in input IP datagrams,
+        * including those received in error.  Octets from datagrams
+        * counted in ipSystemStatsInReceives MUST be counted here.
+        */
+       unsigned long in_octets;
+       /** ipSystemStatsInHdrErrors
+        *
+        * The number of input IP datagrams discarded due to errors in
+        * their IP headers, including version number mismatch, other
+        * format errors, hop count exceeded, errors discovered in
+        * processing their IP options, etc.
+        */
+       unsigned long in_hdr_errors;
+       /** ipSystemStatsInAddrErrors
+        *
+        * The number of input IP datagrams discarded because the IP
+        * address in their IP header's destination field was not a
+        * valid address to be received at this entity.  This count
+        * includes invalid addresses (e.g., ::0).  For entities that
+        * are not IP routers and therefore do not forward datagrams,
+        * this counter includes datagrams discarded because the
+        * destination address was not a local address.
+        */
+       unsigned long in_addr_errors;
+       /** ipSystemStatsInUnknownProtos
+        *
+        * The number of locally-addressed IP datagrams received
+        * successfully but discarded because of an unknown or
+        * unsupported protocol.
+        */
+       unsigned long in_unknown_protos;
+       /** ipSystemStatsInTruncatedPkts
+        *
+        * The number of input IP datagrams discarded because the
+        * datagram frame didn't carry enough data.
+        */
+       unsigned long in_truncated_pkts;
+       /** ipSystemStatsReasmReqds
+        *
+        * The number of IP fragments received that needed to be
+        * reassembled at this interface.
+        */
+       unsigned long reasm_reqds;
+       /** ipSystemStatsReasmOks
+        *
+        * The number of IP datagrams successfully reassembled.
+        */
+       unsigned long reasm_oks;
+       /** ipSystemStatsReasmFails
+        *
+        * The number of failures detected by the IP re-assembly
+        * algorithm (for whatever reason: timed out, errors, etc.).
+        * Note that this is not necessarily a count of discarded IP
+        * fragments since some algorithms (notably the algorithm in
+        * RFC 815) can lose track of the number of fragments by
+        * combining them as they are received.
+        */
+       unsigned long reasm_fails;
+       /** ipSystemStatsInDelivers
+        *
+        * The total number of datagrams successfully delivered to IP
+        * user-protocols (including ICMP).
+        */
+       unsigned long in_delivers;
+       /** ipSystemStatsOutRequests
+        *
+        * The total number of IP datagrams that local IP user-
+        * protocols (including ICMP) supplied to IP in requests for
+        * transmission.
+        */
+       unsigned long out_requests;
+       /** ipSystemStatsOutNoRoutes
+        *
+        * The number of locally generated IP datagrams discarded
+        * because no route could be found to transmit them to their
+        * destination.
+        */
+       unsigned long out_no_routes;
+       /** ipSystemStatsOutTransmits
+        *
+        * The total number of IP datagrams that this entity supplied
+        * to the lower layers for transmission.  This includes
+        * datagrams generated locally and those forwarded by this
+        * entity.
+        */
+       unsigned long out_transmits;
+       /** ipSystemStatsOutOctets
+        *
+        * The total number of octets in IP datagrams delivered to the
+        * lower layers for transmission.  Octets from datagrams
+        * counted in ipSystemStatsOutTransmits MUST be counted here.
+        */
+       unsigned long out_octets;
+       /** ipSystemStatsInMcastPkts
+        *
+        * The number of IP multicast datagrams received.
+        */
+       unsigned long in_mcast_pkts;
+       /** ipSystemStatsOutMcastPkts
+        *
+        * The number of IP multicast datagrams transmitted.
+        */
+       unsigned long out_mcast_pkts;
+       /** ipSystemStatsInBcastPkts
+        *
+        * The number of IP broadcast datagrams received.
+        */
+       unsigned long in_bcast_pkts;
+       /** ipSystemStatsOutBcastPkts
+        *
+        * The number of IP broadcast datagrams transmitted.
+        */
+       unsigned long out_bcast_pkts;
+};
+
+/** An IP system statistics family */
+struct ip_statistics_family {
+       /** IP version */
+       unsigned int version;
+       /** Statistics */
+       struct ip_statistics *stats;
+};
+
+/** IP system statistics family table */
+#define IP_STATISTICS_FAMILIES \
+       __table ( struct ip_statistics_family, "ip_statistics_families" )
+
+/** Declare an IP system statistics family */
+#define __ip_statistics_family( order ) \
+       __table_entry ( IP_STATISTICS_FAMILIES, order )
+
+#define IP_STATISTICS_IPV4 01
+#define IP_STATISTICS_IPV6 02
+
+#endif /* _IPXE_IPSTATS_H */
index fdfbae11bf7946f87bce229c4aa27f1d6b953d1b..f5ef4f0437333aad0dff2b7d45427df54f035b70 100644 (file)
@@ -17,6 +17,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 struct io_buffer;
 struct net_device;
+struct ip_statistics;
 
 /** Empty checksum value
  *
@@ -132,7 +133,8 @@ struct tcpip_net_protocol {
 
 extern int tcpip_rx ( struct io_buffer *iobuf, struct net_device *netdev,
                      uint8_t tcpip_proto, struct sockaddr_tcpip *st_src,
-                     struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum );
+                     struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum,
+                     struct ip_statistics *stats );
 extern int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip,
                      struct sockaddr_tcpip *st_src,
                      struct sockaddr_tcpip *st_dest,
index 3e1dfdf7f41b45ba764b707a9fc6ee2423b52ec4..410915b3bd96ee20bb6ceb4eeffc81622c10cc53 100644 (file)
@@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <string.h>
 #include <ipxe/retry.h>
 #include <ipxe/timer.h>
+#include <ipxe/ipstat.h>
 #include <ipxe/fragment.h>
 
 /** @file
@@ -45,6 +46,7 @@ static void fragment_expired ( struct retry_timer *timer, int fail __unused ) {
        DBGC ( fragment, "FRAG %p expired\n", fragment );
        free_iob ( fragment->iobuf );
        list_del ( &fragment->list );
+       fragment->fragments->stats->reasm_fails++;
        free ( fragment );
 }
 
@@ -89,6 +91,9 @@ struct io_buffer * fragment_reassemble ( struct fragment_reassembler *fragments,
        size_t expected_offset;
        int more_frags;
 
+       /* Update statistics */
+       fragments->stats->reasm_reqds++;
+
        /* Find matching fragment reassembly buffer, if any */
        fragment = fragment_find ( fragments, iobuf, *hdrlen );
 
@@ -115,6 +120,7 @@ struct io_buffer * fragment_reassemble ( struct fragment_reassembler *fragments,
                fragment->iobuf = iobuf;
                fragment->hdrlen = *hdrlen;
                timer_init ( &fragment->timer, fragment_expired, NULL );
+               fragment->fragments = fragments;
                DBGC ( fragment, "FRAG %p [0,%zd)\n", fragment,
                       ( iob_len ( iobuf ) - *hdrlen ) );
 
@@ -157,6 +163,7 @@ struct io_buffer * fragment_reassemble ( struct fragment_reassembler *fragments,
                        *hdrlen = fragment->hdrlen;
                        list_del ( &fragment->list );
                        free ( fragment );
+                       fragments->stats->reasm_oks++;
                        return iobuf;
                }
        }
@@ -167,6 +174,7 @@ struct io_buffer * fragment_reassemble ( struct fragment_reassembler *fragments,
        return NULL;
 
  drop:
+       fragments->stats->reasm_fails++;
        free_iob ( iobuf );
        return NULL;
 }
index b57b2f833fc20c5df8fc4154853249e34a5bdff8..d9a54adebbc9c10a37d7e5392103560e6f92daaa 100644 (file)
@@ -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;
 }
index 621b4ff111bdd9bbe38fb59844d90aa58f4d61d8..2802aef0545fff0799fc15add46a40ccecd80540 100644 (file)
@@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/if_ether.h>
 #include <ipxe/crc32.h>
 #include <ipxe/fragment.h>
+#include <ipxe/ipstat.h>
 #include <ipxe/ndp.h>
 #include <ipxe/ipv6.h>
 
@@ -57,6 +58,16 @@ FILE_LICENCE ( GPL2_OR_LATER );
 /** List of IPv6 miniroutes */
 struct list_head ipv6_miniroutes = LIST_HEAD_INIT ( ipv6_miniroutes );
 
+/** IPv6 statistics */
+static struct ip_statistics ipv6_stats;
+
+/** IPv6 statistics family */
+struct ip_statistics_family
+ipv6_statistics_family __ip_statistics_family ( IP_STATISTICS_IPV6 ) = {
+       .version = 6,
+       .stats = &ipv6_stats,
+};
+
 /**
  * Determine debugging colour for IPv6 debug messages
  *
@@ -398,6 +409,7 @@ static struct fragment_reassembler ipv6_reassembler = {
        .is_fragment = ipv6_is_fragment,
        .fragment_offset = ipv6_fragment_offset,
        .more_fragments = ipv6_more_fragments,
+       .stats = &ipv6_stats,
 };
 
 /**
@@ -455,6 +467,9 @@ static int ipv6_tx ( struct io_buffer *iobuf,
        size_t len;
        int rc;
 
+       /* Update statistics */
+       ipv6_stats.out_requests++;
+
        /* Fill up the IPv6 header, except source address */
        len = iob_len ( iobuf );
        iphdr = iob_push ( iobuf, sizeof ( *iphdr ) );
@@ -475,6 +490,7 @@ static int ipv6_tx ( struct io_buffer *iobuf,
        if ( ! netdev ) {
                DBGC ( ipv6col ( &iphdr->dest ), "IPv6 has no route to %s\n",
                       inet6_ntoa ( &iphdr->dest ) );
+               ipv6_stats.out_no_routes++;
                rc = -ENETUNREACH;
                goto err;
        }
@@ -498,6 +514,7 @@ static int ipv6_tx ( struct io_buffer *iobuf,
        /* Calculate link-layer destination address, if possible */
        if ( IN6_IS_ADDR_MULTICAST ( next_hop ) ) {
                /* Multicast address */
+               ipv6_stats.out_mcast_pkts++;
                if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET6, next_hop,
                                                           ll_dest_buf ) ) !=0){
                        DBGC ( ipv6col ( &iphdr->dest ), "IPv6 could not hash "
@@ -511,6 +528,10 @@ static int ipv6_tx ( struct io_buffer *iobuf,
                ll_dest = NULL;
        }
 
+       /* Update statistics */
+       ipv6_stats.out_transmits++;
+       ipv6_stats.out_octets += iob_len ( iobuf );
+
        /* Hand off to link layer (via NDP if applicable) */
        if ( ll_dest ) {
                if ( ( rc = net_tx ( iobuf, netdev, &ipv6_protocol, ll_dest,
@@ -568,20 +589,29 @@ static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
        int next_header;
        int rc;
 
+       /* Update statistics */
+       ipv6_stats.in_receives++;
+       ipv6_stats.in_octets += iob_len ( iobuf );
+       if ( flags & LL_BROADCAST ) {
+               ipv6_stats.in_bcast_pkts++;
+       } else if ( flags & LL_MULTICAST ) {
+               ipv6_stats.in_mcast_pkts++;
+       }
+
        /* Sanity check the IPv6 header */
        if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
                DBGC ( ipv6col ( &iphdr->src ), "IPv6 packet too short at %zd "
                       "bytes (min %zd bytes)\n", iob_len ( iobuf ),
                       sizeof ( *iphdr ) );
                rc = -EINVAL_LEN;
-               goto err;
+               goto err_header;
        }
        if ( ( iphdr->ver_tc_label & htonl ( IPV6_MASK_VER ) ) !=
             htonl ( IPV6_VER ) ) {
                DBGC ( ipv6col ( &iphdr->src ), "IPv6 version %#08x not "
                       "supported\n", ntohl ( iphdr->ver_tc_label ) );
                rc = -ENOTSUP_VER;
-               goto err;
+               goto err_header;
        }
 
        /* Truncate packet to specified length */
@@ -589,8 +619,9 @@ static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
        if ( len > iob_len ( iobuf ) ) {
                DBGC ( ipv6col ( &iphdr->src ), "IPv6 length too long at %zd "
                       "bytes (packet is %zd bytes)\n", len, iob_len ( iobuf ));
+               ipv6_stats.in_truncated_pkts++;
                rc = -EINVAL_LEN;
-               goto err;
+               goto err_other;
        }
        iob_unput ( iobuf, ( iob_len ( iobuf ) - len - sizeof ( *iphdr ) ) );
        hdrlen = sizeof ( *iphdr );
@@ -606,8 +637,9 @@ static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
             ( ! ipv6_has_addr ( netdev, &iphdr->dest ) ) ) {
                DBGC ( ipv6col ( &iphdr->src ), "IPv6 discarding non-local "
                       "unicast packet for %s\n", inet6_ntoa ( &iphdr->dest ) );
+               ipv6_stats.in_addr_errors++;
                rc = -EPIPE;
-               goto err;
+               goto err_other;
        }
 
        /* Process any extension headers */
@@ -624,7 +656,7 @@ static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
                               "%zd bytes)\n", this_header,
                               ( iob_len ( iobuf ) - hdrlen ), extlen );
                        rc = -EINVAL_LEN;
-                       goto err;
+                       goto err_header;
                }
 
                /* Determine size of extension header (if applicable) */
@@ -645,7 +677,7 @@ static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
                               "%zd bytes)\n", this_header,
                               ( iob_len ( iobuf ) - hdrlen ), extlen );
                        rc = -EINVAL_LEN;
-                       goto err;
+                       goto err_header;
                }
                hdrlen += extlen;
                next_header = ext->common.next_header;
@@ -662,7 +694,7 @@ static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
                        /* Check that all options can be ignored */
                        if ( ( rc = ipv6_check_options ( iphdr, &ext->options,
                                                         extlen ) ) != 0 )
-                               goto err;
+                               goto err_header;
 
                } else if ( this_header == IPV6_FRAGMENT ) {
 
@@ -692,7 +724,7 @@ static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
        pshdr_csum = ipv6_pshdr_chksum ( iphdr, iob_len ( iobuf ),
                                         next_header, TCPIP_EMPTY_CSUM );
        if ( ( rc = tcpip_rx ( iobuf, netdev, next_header, &src.st, &dest.st,
-                              pshdr_csum ) ) != 0 ) {
+                              pshdr_csum, &ipv6_stats ) ) != 0 ) {
                DBGC ( ipv6col ( &src.sin6.sin6_addr ), "IPv6 received packet "
                                "rejected by stack: %s\n", strerror ( rc ) );
                return rc;
@@ -700,7 +732,9 @@ static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
 
        return 0;
 
- err:
+ err_header:
+       ipv6_stats.in_hdr_errors++;
+ err_other:
        free_iob ( iobuf );
        return rc;
 }
index 0e4671444f7f2a9779c09eb4d9096eb7d9489b6f..0b2adfd96dac0792b3730ba3aede08b9e9514fcc 100644 (file)
@@ -5,6 +5,7 @@
 #include <byteswap.h>
 #include <ipxe/iobuf.h>
 #include <ipxe/tables.h>
+#include <ipxe/ipstat.h>
 #include <ipxe/tcpip.h>
 
 /** @file
@@ -25,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
  * @v st_src           Partially-filled source address
  * @v st_dest          Partially-filled destination address
  * @v pshdr_csum       Pseudo-header checksum
+ * @v stats            IP statistics
  * @ret rc             Return status code
  *
  * This function expects a transport-layer segment from the network
@@ -35,20 +37,22 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 int tcpip_rx ( struct io_buffer *iobuf, struct net_device *netdev,
               uint8_t tcpip_proto, struct sockaddr_tcpip *st_src,
-              struct sockaddr_tcpip *st_dest,
-              uint16_t pshdr_csum ) {
+              struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum,
+              struct ip_statistics *stats ) {
        struct tcpip_protocol *tcpip;
 
        /* Hand off packet to the appropriate transport-layer protocol */
        for_each_table_entry ( tcpip, TCPIP_PROTOCOLS ) {
                if ( tcpip->tcpip_proto == tcpip_proto ) {
                        DBG ( "TCP/IP received %s packet\n", tcpip->name );
+                       stats->in_delivers++;
                        return tcpip->rx ( iobuf, netdev, st_src, st_dest,
                                           pshdr_csum );
                }
        }
 
        DBG ( "Unrecognised TCP/IP protocol %d\n", tcpip_proto );
+       stats->in_unknown_protos++;
        free_iob ( iobuf );
        return -EPROTONOSUPPORT;
 }