From e980405cbce777ef7ff3832f4ed725891915d955 Mon Sep 17 00:00:00 2001 From: "Martine S. Lenders" Date: Tue, 3 Dec 2019 15:56:32 +0100 Subject: [PATCH] gnrc_sixlowpan_frag_sfr: provide statistics sub-module --- makefiles/pseudomodules.inc.mk | 1 + sys/Makefile.dep | 4 ++ sys/include/net/gnrc/sixlowpan/frag/sfr.h | 31 +++++++++ .../frag/sfr/gnrc_sixlowpan_frag_sfr.c | 63 +++++++++++++++++-- sys/shell/commands/sc_gnrc_6lo_frag_stats.c | 21 +++++++ 5 files changed, 116 insertions(+), 4 deletions(-) diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index ee617d9644..1ef1e6804a 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -56,6 +56,7 @@ PSEUDOMODULES += gnrc_sixloenc PSEUDOMODULES += gnrc_sixlowpan_border_router_default PSEUDOMODULES += gnrc_sixlowpan_default PSEUDOMODULES += gnrc_sixlowpan_frag_hint +PSEUDOMODULES += gnrc_sixlowpan_frag_sfr_stats PSEUDOMODULES += gnrc_sixlowpan_iphc_nhc PSEUDOMODULES += gnrc_sixlowpan_nd_border_router PSEUDOMODULES += gnrc_sixlowpan_router_default diff --git a/sys/Makefile.dep b/sys/Makefile.dep index 989e4b618f..66ca09d648 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -333,6 +333,10 @@ ifneq (,$(filter gnrc_sixlowpan_frag_sfr,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter gnrc_sixlowpan_frag_sfr_stats,$(USEMODULE))) + USEMODULE += gnrc_sixlowpan_frag_sfr +endif + ifneq (,$(filter gnrc_sixlowpan_frag_vrb,$(USEMODULE))) USEMODULE += xtimer USEMODULE += gnrc_sixlowpan_frag_fb diff --git a/sys/include/net/gnrc/sixlowpan/frag/sfr.h b/sys/include/net/gnrc/sixlowpan/frag/sfr.h index 3d5b9a5fcf..3a3a32e260 100644 --- a/sys/include/net/gnrc/sixlowpan/frag/sfr.h +++ b/sys/include/net/gnrc/sixlowpan/frag/sfr.h @@ -56,6 +56,28 @@ extern "C" { */ #define GNRC_SIXLOWPAN_FRAG_SFR_INTER_FRAG_GAP_MSG (0x0228) +/** + * @brief Stats on selective fragment recovery + */ +typedef struct { + uint32_t datagram_resends; /**< datagrams resent */ + struct { + uint32_t usual; /**< non-abort fragments sent */ + uint32_t aborts; /**< abort pseudo-fragments sent */ + uint32_t forwarded; /**< forwarded fragments */ + } fragments_sent; /**< RFRAG packets sent */ + struct { + uint32_t by_nack; /**< fragments resent due to a 0 in ACK's bitmap */ + uint32_t by_timeout; /**< fragments resent due to an ARQ timeout */ + } fragment_resends; /**< fragments resent */ + struct { + uint32_t full; /**< full RFRAGs ACKs sent */ + uint32_t partly; /**< partly ACKing RFRAGs sent */ + uint32_t aborts; /**< abort RFRAG ACKs sent */ + uint32_t forwarded; /**< forwarded ACKs */ + } acks; /**< ACKs stats */ +} gnrc_sixlowpan_frag_sfr_stats_t; + /** * @brief Initialize selective fragment recovery */ @@ -163,6 +185,15 @@ void gnrc_sixlowpan_frag_sfr_arq_timeout(gnrc_sixlowpan_frag_fb_t *fbuf); */ void gnrc_sixlowpan_frag_sfr_inter_frame_gap(void); +#if IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS) +/** + * @brief Fetch current stats for selective fragment recovery + * + * @param[out] stats The current stats. Must not be NULL. + */ +void gnrc_sixlowpan_frag_sfr_stats_get(gnrc_sixlowpan_frag_sfr_stats_t *stats); +#endif /* IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS) */ + #ifdef __cplusplus } #endif diff --git a/sys/net/gnrc/network_layer/sixlowpan/frag/sfr/gnrc_sixlowpan_frag_sfr.c b/sys/net/gnrc/network_layer/sixlowpan/frag/sfr/gnrc_sixlowpan_frag_sfr.c index 9b2119c8c4..8058a5b545 100644 --- a/sys/net/gnrc/network_layer/sixlowpan/frag/sfr/gnrc_sixlowpan_frag_sfr.c +++ b/sys/net/gnrc/network_layer/sixlowpan/frag/sfr/gnrc_sixlowpan_frag_sfr.c @@ -96,6 +96,8 @@ static clist_node_t _frame_queue; static const gnrc_sixlowpan_frag_sfr_bitmap_t _full_bitmap = { .u32 = UINT32_MAX }; static const gnrc_sixlowpan_frag_sfr_bitmap_t _null_bitmap = { .u32 = 0U }; +static gnrc_sixlowpan_frag_sfr_stats_t _stats; + /** * @brief Converts a @ref sys_bitmap based bitmap to a * gnrc_sixlowpan_frag_sfr_bitmap_t @@ -495,6 +497,11 @@ void gnrc_sixlowpan_frag_sfr_arq_timeout(gnrc_sixlowpan_frag_fb_t *fbuf) error_no = ENOMEM; goto error; } + else if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + /* fragment was resent successfully, note this done in + * the statistics */ + _stats.fragment_resends.by_timeout++; + } /* fragment was resent successfully, schedule next ACK * timeout */ reschedule_arq_timeout = true; @@ -559,6 +566,13 @@ void gnrc_sixlowpan_frag_sfr_inter_frame_gap(void) } } +void gnrc_sixlowpan_frag_sfr_stats_get(gnrc_sixlowpan_frag_sfr_stats_t *stats) +{ + if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + *stats = _stats; + } +} + /* ====== INTERNAL FUNCTION DEFINITIONS ====== */ static inline uint16_t _min(uint16_t a, size_t b) { @@ -770,6 +784,9 @@ static bool _send_fragment(gnrc_pktsnip_t *frag, gnrc_sixlowpan_frag_fb_t *fbuf, frag_desc->retries = 0; clist_rpush(&fbuf->sfr.window, &frag_desc->super); if ((res = _send_frame(frag, NULL, page))) { + if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + _stats.fragments_sent.usual++; + } frag_desc->last_sent = _last_frame_sent; fbuf->sfr.cur_seq++; fbuf->sfr.frags_sent++; @@ -866,6 +883,9 @@ static void _try_reassembly(gnrc_netif_hdr_t *netif_hdr, "fragment\n"); /* send abort */ bitmap = &_null_bitmap; + if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + _stats.acks.aborts++; + } } else if (vrbe != NULL) { DEBUG("6lo sfr: packet was forwarded\n"); @@ -886,11 +906,17 @@ static void _try_reassembly(gnrc_netif_hdr_t *netif_hdr, _clean_up_rb_entry(entry); /* send abort */ bitmap = &_null_bitmap; + if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + _stats.acks.aborts++; + } } else { if (res) { DEBUG("6lo sfr: dispatched datagram to upper layer\n"); bitmap = &_full_bitmap; + if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + _stats.acks.full++; + } } else if (ack_req) { DEBUG("6lo sfr: ACKing received fragments %02X%02X%02X%02X " @@ -902,6 +928,9 @@ static void _try_reassembly(gnrc_netif_hdr_t *netif_hdr, entry->entry.base->current_size, entry->entry.base->datagram_size); bitmap = _to_bitmap(entry->entry.rb->received); + if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + _stats.acks.partly++; + } } else { /* no ACK was requested and no error was causing an abort ACK*/ @@ -1087,6 +1116,17 @@ static void _handle_nth_rfrag(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, } } +static int _resend_failed_frag(clist_node_t *node, void *fbuf_ptr) +{ + int res; + + if (((res = _resend_frag(node, fbuf_ptr)) == 0) && + IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + _stats.fragment_resends.by_nack++; + } + return res; +} + static void _check_failed_frags(sixlowpan_sfr_ack_t *ack, gnrc_sixlowpan_frag_fb_t *fbuf) { @@ -1140,10 +1180,10 @@ static void _check_failed_frags(sixlowpan_sfr_ack_t *ack, else { fbuf->sfr.window = not_received; assert(fbuf->sfr.frags_sent == clist_count(&fbuf->sfr.window)); - /* use _resend_frag here instead of loop above, so _resend_frag - * can know if the fragment is the last in the window by using - * clist_rpeek() on fbuf->sfr.window */ - if (clist_foreach(&fbuf->sfr.window, _resend_frag, fbuf) != NULL) { + /* use _resend_failed_frag here instead of loop above, so + * _resend_frag can know if the fragment is the last in the window by + * using clist_rpeek() on fbuf->sfr.window */ + if (clist_foreach(&fbuf->sfr.window, _resend_failed_frag, fbuf) != NULL) { /* XXX: it is unlikely that allocating an abort RFRAG will be * successful since the resources missing to cause the abort are * still in use, but we should at least try */ @@ -1310,6 +1350,9 @@ static bool _send_abort_frag(gnrc_pktsnip_t *pkt, uint8_t tag, bool req_ack, if (frag != NULL) { sixlowpan_sfr_rfrag_set_offset(frag->next->data, 0); _send_frame(frag, NULL, page); + if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + _stats.fragments_sent.aborts++; + } return true; } return false; @@ -1378,6 +1421,9 @@ static void _retry_datagram(gnrc_sixlowpan_frag_fb_t *fbuf) } else { DEBUG("6lo sfr: Retrying to send datagram %u completely\n", fbuf->tag); + if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + _stats.datagram_resends++; + } fbuf->sfr.retrans--; /* return fragmentation buffer to its original state to resend the whole * datagram again */ @@ -1396,6 +1442,9 @@ static void _abort_rb(gnrc_pktsnip_t *pkt, _generic_rb_entry_t *entry, netif_hdr->src_l2addr_len, addr_str), hdr->base.tag); if (send_ack) { + if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + _stats.acks.aborts++; + } _send_ack(gnrc_netif_hdr_get_netif(netif_hdr), gnrc_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len, @@ -1513,6 +1562,9 @@ static void _handle_ack(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, addr_str), vrbe->super.tag); _send_ack(vrbe->in_netif, vrbe->super.src, vrbe->super.src_len, &mock_base, hdr->bitmap); + if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + _stats.acks.forwarded++; + } if ((unaligned_get_u32(hdr->bitmap) == _full_bitmap.u32) || (unaligned_get_u32(hdr->bitmap) == _null_bitmap.u32)) { if (CONFIG_GNRC_SIXLOWPAN_FRAG_RBUF_DEL_TIMER > 0) { @@ -1598,6 +1650,9 @@ static int _forward_rfrag(gnrc_pktsnip_t *pkt, _generic_rb_entry_t *entry, gnrc_netif_hdr_set_netif(new->data, entry->entry.vrb->out_netif); new->next = pkt; _send_frame(new, NULL, page); + if (IS_USED(MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS)) { + _stats.fragments_sent.forwarded++; + } return 0; } diff --git a/sys/shell/commands/sc_gnrc_6lo_frag_stats.c b/sys/shell/commands/sc_gnrc_6lo_frag_stats.c index 53beec1384..6e256fc7cf 100644 --- a/sys/shell/commands/sc_gnrc_6lo_frag_stats.c +++ b/sys/shell/commands/sc_gnrc_6lo_frag_stats.c @@ -16,6 +16,9 @@ #include #include "net/gnrc/sixlowpan/frag/stats.h" +#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS +#include "net/gnrc/sixlowpan/frag/sfr.h" +#endif int _gnrc_6lo_frag_stats(int argc, char **argv) { @@ -28,6 +31,24 @@ int _gnrc_6lo_frag_stats(int argc, char **argv) #ifdef MODULE_GNRC_SIXLOWPAN_FRAG_VRB printf("VRB full: %u\n", stats->vrb_full); #endif +#ifdef MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS + gnrc_sixlowpan_frag_sfr_stats_t sfr; + + gnrc_sixlowpan_frag_sfr_stats_get(&sfr); + printf("DG resends: %lu\n", (long unsigned)sfr.datagram_resends); + printf("frags sent: usual: %lu, aborts: %lu, forwarded: %lu\n", + (long unsigned)sfr.fragments_sent.usual, + (long unsigned)sfr.fragments_sent.aborts, + (long unsigned)sfr.fragments_sent.forwarded); + printf("frag resends: NACK: %lu, timeout: %lu\n", + (long unsigned)sfr.fragment_resends.by_nack, + (long unsigned)sfr.fragment_resends.by_timeout); + printf("ACKs: full: %lu, partly: %lu, aborts: %lu, forwarded: %lu\n", + (long unsigned)sfr.acks.full, + (long unsigned)sfr.acks.partly, + (long unsigned)sfr.acks.aborts, + (long unsigned)sfr.acks.forwarded); +#endif /* MODULE_GNRC_SIXLOWPAN_FRAG_SFR_STATS */ printf("frags complete: %u\n", stats->fragments); printf("dgs complete: %u\n", stats->datagrams); return 0;