[tcpip] Add IP statistics collection as per RFC 4293
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
c165e8d1fc
commit
11963c4f5f
@ -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 *
|
||||
|
187
src/include/ipxe/ipstat.h
Normal file
187
src/include/ipxe/ipstat.h
Normal file
@ -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 */
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user