net: tcp: Add TCP statistics support

We did not collect any TCP statistics before but this commit
changes that.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2017-05-16 15:27:27 +03:00
commit e253dcbd3b
9 changed files with 221 additions and 23 deletions

View file

@ -22,6 +22,11 @@ extern "C" {
typedef u32_t net_stats_t;
struct net_stats_bytes {
u32_t sent;
u32_t received;
};
struct net_stats_ip {
/** Number of received packets at the IP layer. */
net_stats_t recv;
@ -78,6 +83,12 @@ struct net_stats_icmp {
};
struct net_stats_tcp {
/** Amount of received and sent TCP application data. */
struct net_stats_bytes bytes;
/** Amount of retransmitted data. */
net_stats_t resent;
/** Number of recived TCP segments. */
net_stats_t recv;
@ -90,22 +101,25 @@ struct net_stats_tcp {
/** Number of TCP segments with a bad checksum. */
net_stats_t chkerr;
/** Number of TCP segments with a bad ACK number. */
/** Number of received TCP segments with a bad ACK number. */
net_stats_t ackerr;
/** Number of received bad TCP RST (reset) segments. */
net_stats_t rsterr;
/** Number of received TCP RST (reset) segments. */
net_stats_t rst;
/** Number of retransmitted TCP segments. */
net_stats_t rexmit;
/** Number of dropped SYNs because too few connections were
* available.
/** Number of dropped connection attempts because too few connections
* were available.
*/
net_stats_t syndrop;
net_stats_t conndrop;
/** Number of SYNs for closed ports, triggering a RST. */
net_stats_t synrst;
/** Number of connection attempts for closed ports, triggering a RST. */
net_stats_t connrst;
};
struct net_stats_udp {
@ -207,11 +221,6 @@ struct net_stats_ipv6_mld {
net_stats_t drop;
};
struct net_stats_bytes {
u32_t sent;
u32_t received;
};
struct net_stats {
net_stats_t processing_error;

View file

@ -69,7 +69,7 @@ config NET_STATISTICS_UDP
config NET_STATISTICS_TCP
bool "TCP statistics"
depends on NET_TCP
default n
default y
help
Keep track of TCP related statistics

View file

@ -843,9 +843,7 @@ enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt)
goto drop;
}
if (proto == IPPROTO_UDP) {
net_stats_update_udp_recv();
}
net_stats_update_per_proto_recv(proto);
return NET_OK;
}
@ -871,12 +869,14 @@ enum net_verdict net_conn_input(enum net_ip_protocol proto, struct net_pkt *pkt)
#endif
{
send_icmp_error(pkt);
if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) {
net_stats_update_tcp_seg_connrst();
}
}
drop:
if (proto == IPPROTO_UDP) {
net_stats_update_udp_drop();
}
net_stats_update_per_proto_drop(proto);
return NET_DROP;
}

View file

@ -32,6 +32,7 @@
#include "ipv4.h"
#include "udp.h"
#include "tcp.h"
#include "net_stats.h"
#define NET_MAX_CONTEXT CONFIG_NET_MAX_CONTEXTS
@ -823,9 +824,12 @@ NET_CONN_CB(tcp_established)
if (tcp_flags & NET_TCP_RST) {
/* We only accept RST packet that has valid seq field. */
if (!net_tcp_validate_seq(context->tcp, pkt)) {
net_stats_update_tcp_seg_rsterr();
return NET_DROP;
}
net_stats_update_tcp_seg_rst();
net_tcp_print_recv_info("RST", pkt, NET_TCP_HDR(pkt)->src_port);
if (context->recv_cb) {
@ -917,9 +921,12 @@ NET_CONN_CB(tcp_synack_received)
if (NET_TCP_FLAGS(pkt) & NET_TCP_RST) {
/* We only accept RST packet that has valid seq field. */
if (!net_tcp_validate_seq(context->tcp, pkt)) {
net_stats_update_tcp_seg_rsterr();
return NET_DROP;
}
net_stats_update_tcp_seg_rst();
if (context->connect_cb) {
context->connect_cb(context, -ECONNREFUSED,
context->user_data);
@ -1350,9 +1357,12 @@ NET_CONN_CB(tcp_syn_rcvd)
/* We only accept RST packet that has valid seq field. */
if (!net_tcp_validate_seq(tcp, pkt)) {
net_stats_update_tcp_seg_rsterr();
return NET_DROP;
}
net_stats_update_tcp_seg_rst();
ack_timer_cancel(tcp);
net_tcp_print_recv_info("RST", pkt, NET_TCP_HDR(pkt)->src_port);
@ -1399,7 +1409,7 @@ NET_CONN_CB(tcp_syn_rcvd)
if (ret < 0) {
NET_DBG("Cannot get accepted context, "
"connection reset");
goto reset;
goto conndrop;
}
new_context->tcp->recv_max_ack = context->tcp->recv_max_ack;
@ -1460,7 +1470,7 @@ NET_CONN_CB(tcp_syn_rcvd)
NET_DBG("Cannot bind accepted context, "
"connection reset");
net_context_unref(new_context);
goto reset;
goto conndrop;
}
new_context->flags |= NET_CONTEXT_REMOTE_ADDR_SET;
@ -1479,7 +1489,7 @@ NET_CONN_CB(tcp_syn_rcvd)
NET_DBG("Cannot register accepted TCP handler (%d)",
ret);
net_context_unref(new_context);
goto reset;
goto conndrop;
}
/* Swap the newly-created TCP states with the one that
@ -1512,6 +1522,9 @@ NET_CONN_CB(tcp_syn_rcvd)
return NET_DROP;
conndrop:
net_stats_update_tcp_seg_conndrop();
reset:
{
struct sockaddr peer;
@ -1930,6 +1943,8 @@ static enum net_verdict packet_received(struct net_conn *conn,
net_pkt_appdata(pkt), net_pkt_appdatalen(pkt),
net_pkt_get_len(pkt));
net_stats_update_tcp_recv(net_pkt_appdatalen(pkt));
context->recv_cb(context, pkt, 0, user_data);
#if defined(CONFIG_NET_CONTEXT_SYNC_RECV)

View file

@ -70,8 +70,15 @@ static inline void net_context_send_cb(struct net_context *context,
#if defined(CONFIG_NET_UDP)
if (net_context_get_ip_proto(context) == IPPROTO_UDP) {
net_stats_update_udp_sent();
}
} else
#endif
#if defined(CONFIG_NET_TCP)
if (net_context_get_ip_proto(context) == IPPROTO_TCP) {
net_stats_update_tcp_seg_sent();
} else
#endif
{
}
}
static bool net_if_tx(struct net_if *iface)

View file

@ -373,6 +373,27 @@ static inline void net_shell_print_statistics(void)
GET_STAT(udp.chkerr));
#endif
#if defined(CONFIG_NET_STATISTICS_TCP)
printk("TCP bytes recv %u\tsent\t%d\n",
GET_STAT(tcp.bytes.received),
GET_STAT(tcp.bytes.sent));
printk("TCP seg recv %d\tsent\t%d\tdrop\t%d\n",
GET_STAT(tcp.recv),
GET_STAT(tcp.sent),
GET_STAT(tcp.drop));
printk("TCP seg resent %d\tchkerr\t%d\tackerr\t%d\n",
GET_STAT(tcp.resent),
GET_STAT(tcp.chkerr),
GET_STAT(tcp.ackerr));
printk("TCP seg rsterr %d\trst\t%d\tre-xmit\t%d\n",
GET_STAT(tcp.rsterr),
GET_STAT(tcp.rst),
GET_STAT(tcp.rexmit));
printk("TCP conn drop %d\tconnrst\t%d\n",
GET_STAT(tcp.conndrop),
GET_STAT(tcp.connrst));
#endif
#if defined(CONFIG_NET_STATISTICS_RPL)
printk("RPL DIS recv %d\tsent\t%d\tdrop\t%d\n",
GET_STAT(rpl.dis.recv),

View file

@ -23,7 +23,7 @@ struct net_stats net_stats;
#define PRINT_STATISTICS_INTERVAL (30 * MSEC_PER_SEC)
void net_print_statistics(void)
static inline void stats(void)
{
static s64_t next_print;
s64_t curr = k_uptime_get();
@ -80,6 +80,27 @@ void net_print_statistics(void)
GET_STAT(udp.chkerr));
#endif
#if defined(CONFIG_NET_STATISTICS_TCP)
NET_INFO("TCP bytes recv %u\tsent\t%d",
GET_STAT(tcp.bytes.received),
GET_STAT(tcp.bytes.sent));
NET_INFO("TCP seg recv %d\tsent\t%d\tdrop\t%d",
GET_STAT(tcp.recv),
GET_STAT(tcp.sent),
GET_STAT(tcp.drop));
NET_INFO("TCP seg resent %d\tchkerr\t%d\tackerr\t%d",
GET_STAT(tcp.resent),
GET_STAT(tcp.chkerr),
GET_STAT(tcp.ackerr));
NET_INFO("TCP seg rsterr %d\trst\t%d\tre-xmit\t%d",
GET_STAT(tcp.rsterr),
GET_STAT(tcp.rst),
GET_STAT(tcp.rexmit));
NET_INFO("TCP conn drop %d\tconnrst\t%d",
GET_STAT(tcp.conndrop),
GET_STAT(tcp.connrst));
#endif
#if defined(CONFIG_NET_STATISTICS_RPL)
NET_INFO("RPL DIS recv %d\tsent\t%d\tdrop\t%d",
GET_STAT(rpl.dis.recv),
@ -129,6 +150,14 @@ void net_print_statistics(void)
}
}
void net_print_statistics(void)
{
/* In order to make the info print lines shorter, use shorter
* function name.
*/
stats();
}
#endif /* CONFIG_NET_STATISTICS_PERIODIC_OUTPUT */
#if defined(CONFIG_NET_STATISTICS_USER_API)

View file

@ -9,6 +9,7 @@
#if defined(CONFIG_NET_STATISTICS)
#include <net/net_ip.h>
#include <net/net_stats.h>
extern struct net_stats net_stats;
@ -162,6 +163,106 @@ static inline void net_stats_update_udp_drop(void)
#define net_stats_update_udp_drop()
#endif /* CONFIG_NET_STATISTICS_UDP */
#if defined(CONFIG_NET_STATISTICS_TCP)
/* TCP stats */
static inline void net_stats_update_tcp_sent(u32_t bytes)
{
net_stats.tcp.bytes.sent += bytes;
}
static inline void net_stats_update_tcp_recv(u32_t bytes)
{
net_stats.tcp.bytes.received += bytes;
}
static inline void net_stats_update_tcp_resent(u32_t bytes)
{
net_stats.tcp.resent += bytes;
}
static inline void net_stats_update_tcp_seg_sent(void)
{
net_stats.tcp.sent++;
}
static inline void net_stats_update_tcp_seg_recv(void)
{
net_stats.tcp.recv++;
}
static inline void net_stats_update_tcp_seg_drop(void)
{
net_stats.tcp.drop++;
}
static inline void net_stats_update_tcp_seg_rst(void)
{
net_stats.tcp.rst++;
}
static inline void net_stats_update_tcp_seg_conndrop(void)
{
net_stats.tcp.conndrop++;
}
static inline void net_stats_update_tcp_seg_connrst(void)
{
net_stats.tcp.connrst++;
}
static inline void net_stats_update_tcp_seg_chkerr(void)
{
net_stats.tcp.chkerr++;
}
static inline void net_stats_update_tcp_seg_ackerr(void)
{
net_stats.tcp.ackerr++;
}
static inline void net_stats_update_tcp_seg_rsterr(void)
{
net_stats.tcp.rsterr++;
}
static inline void net_stats_update_tcp_seg_rexmit(void)
{
net_stats.tcp.rexmit++;
}
#else
#define net_stats_update_tcp_sent(...)
#define net_stats_update_tcp_resent(...)
#define net_stats_update_tcp_recv(...)
#define net_stats_update_tcp_seg_sent()
#define net_stats_update_tcp_seg_recv()
#define net_stats_update_tcp_seg_drop()
#define net_stats_update_tcp_seg_rst()
#define net_stats_update_tcp_seg_conndrop()
#define net_stats_update_tcp_seg_connrst()
#define net_stats_update_tcp_seg_chkerr()
#define net_stats_update_tcp_seg_ackerr()
#define net_stats_update_tcp_seg_rsterr()
#define net_stats_update_tcp_seg_rexmit()
#endif /* CONFIG_NET_STATISTICS_TCP */
static inline void net_stats_update_per_proto_recv(enum net_ip_protocol proto)
{
if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) {
net_stats_update_udp_recv();
} else if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) {
net_stats_update_tcp_seg_recv();
}
}
static inline void net_stats_update_per_proto_drop(enum net_ip_protocol proto)
{
if (IS_ENABLED(CONFIG_NET_UDP) && proto == IPPROTO_UDP) {
net_stats_update_udp_drop();
} else if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) {
net_stats_update_tcp_seg_drop();
}
}
#if defined(CONFIG_NET_STATISTICS_RPL)
/* RPL stats */
static inline void net_stats_update_rpl_resets(void)

View file

@ -34,6 +34,7 @@
#include "ipv6.h"
#include "ipv4.h"
#include "tcp.h"
#include "net_stats.h"
/*
* Each TCP connection needs to be tracked by net_context, so
@ -158,6 +159,11 @@ static void tcp_retry_expired(struct k_timer *timer)
do_ref_if_needed(pkt);
if (net_tcp_send_pkt(pkt) < 0 && !is_6lo_technology(pkt)) {
net_pkt_unref(pkt);
} else {
if (IS_ENABLED(CONFIG_NET_STATISTICS_TCP) &&
!is_6lo_technology(pkt)) {
net_stats_update_tcp_seg_rexmit();
}
}
} else if (IS_ENABLED(CONFIG_NET_TCP_TIME_WAIT)) {
if (tcp->fin_sent && tcp->fin_rcvd) {
@ -635,6 +641,8 @@ int net_tcp_queue_data(struct net_context *context, struct net_pkt *pkt)
context->tcp->send_seq += data_len;
net_stats_update_tcp_sent(data_len);
sys_slist_append(&context->tcp->sent_list, &pkt->sent_list);
/* We need to restart retry_timer if it is stopped. */
@ -715,6 +723,8 @@ int net_tcp_send_pkt(struct net_pkt *pkt)
ret = net_send_data(new_pkt);
if (ret < 0) {
net_pkt_unref(new_pkt);
} else {
net_stats_update_tcp_seg_rexmit();
}
return ret;
@ -773,6 +783,11 @@ void net_tcp_ack_received(struct net_context *ctx, u32_t ack)
u32_t seq;
bool valid_ack = false;
if (IS_ENABLED(CONFIG_NET_STATISTICS_TCP) &&
sys_slist_is_empty(list)) {
net_stats_update_tcp_seg_ackerr();
}
while (!sys_slist_is_empty(list)) {
head = sys_slist_peek_head(list);
pkt = CONTAINER_OF(head, struct net_pkt, sent_list);
@ -781,6 +796,7 @@ void net_tcp_ack_received(struct net_context *ctx, u32_t ack)
seq = sys_get_be32(tcphdr->seq) + net_pkt_appdatalen(pkt) - 1;
if (!net_tcp_seq_greater(ack, seq)) {
net_stats_update_tcp_seg_ackerr();
break;
}