diff --git a/include/net/net_stats.h b/include/net/net_stats.h index 89b0d05f1f1..8b524d7f24e 100644 --- a/include/net/net_stats.h +++ b/include/net/net_stats.h @@ -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; diff --git a/subsys/net/ip/Kconfig.stats b/subsys/net/ip/Kconfig.stats index 40ee3a89ce0..0bada1c7e72 100644 --- a/subsys/net/ip/Kconfig.stats +++ b/subsys/net/ip/Kconfig.stats @@ -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 diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index 35db99e7307..4d8968db7dd 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -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; } diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index 2f8a2952db0..f95230b1b2f 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -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) diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index 07c5ab8624e..6d06b1b5455 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -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) diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c index ecf38aa3036..014f35be532 100644 --- a/subsys/net/ip/net_shell.c +++ b/subsys/net/ip/net_shell.c @@ -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), diff --git a/subsys/net/ip/net_stats.c b/subsys/net/ip/net_stats.c index 7b4f700a192..0a3aeacd45f 100644 --- a/subsys/net/ip/net_stats.c +++ b/subsys/net/ip/net_stats.c @@ -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) diff --git a/subsys/net/ip/net_stats.h b/subsys/net/ip/net_stats.h index a9d6cd07631..93b9669d620 100644 --- a/subsys/net/ip/net_stats.h +++ b/subsys/net/ip/net_stats.h @@ -9,6 +9,7 @@ #if defined(CONFIG_NET_STATISTICS) +#include #include 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) diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c index 60cef5ae471..bff89bf5427 100644 --- a/subsys/net/ip/tcp.c +++ b/subsys/net/ip/tcp.c @@ -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; }