From a211cb6e31ae4c971d0f06d87135bc4f27263e76 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Wed, 15 Nov 2017 14:54:32 +0000 Subject: [PATCH] Allow to set a different number of MAC retransmissions for different classes of packets --- os/net/ipv6/sicslowpan.c | 11 +++++++ os/net/ipv6/uip.h | 19 ++++++++++++ os/net/ipv6/uip6.c | 28 ++++++++++++++++-- os/net/ipv6/uipopt.h | 29 +++++++++++++++++++ os/net/mac/csma/csma-output.c | 14 +++++++-- os/net/mac/tsch/tsch-queue.c | 6 ++-- os/net/mac/tsch/tsch-queue.h | 4 ++- os/net/mac/tsch/tsch.c | 15 ++++++++-- os/net/packetbuf.h | 3 ++ .../test-flush-nbr-queue.c | 6 ++-- 10 files changed, 121 insertions(+), 14 deletions(-) diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 2f239f77e..492dfe444 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -1504,6 +1504,17 @@ output(const linkaddr_t *localdest) set_packet_attrs(); } +#if UIP_WITH_VARIABLE_RETRANSMISSIONS + { + uint8_t traffic_class = (UIP_IP_BUF->vtc << 4) | (UIP_IP_BUF->tcflow >> 4); + if(traffic_class & UIP_TC_MAC_TRANSMISSION_COUNTER_BIT) { + uint8_t max_mac_transmissions = traffic_class & UIP_TC_MAC_TRANSMISSION_COUNTER_MASK; + /* propagate the MAC transmission limit to lower layers */ + packetbuf_set_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, max_mac_transmissions); + } + } +#endif /* UIP_WITH_VARIABLE_RETRANSMISSIONS */ + /* * The destination address will be tagged to each outbound * packet. If the argument localdest is NULL, we are sending a diff --git a/os/net/ipv6/uip.h b/os/net/ipv6/uip.h index 809f4b4bc..69888445e 100755 --- a/os/net/ipv6/uip.h +++ b/os/net/ipv6/uip.h @@ -820,6 +820,18 @@ CCIF void uip_send(const void *data, int len); */ #define uip_mss() (uip_conn->mss) +/** + * Set the maximal number of MAC transmissions. + * + * \hideinitializer + */ +#if UIP_WITH_VARIABLE_RETRANSMISSIONS +#define uip_set_max_mac_transmissions(conn, value) ((conn)->max_mac_transmissions = (value)) +#else +#define uip_set_max_mac_transmissions(conn, value) +#endif + + /** * Set up a new UDP connection. * @@ -883,6 +895,7 @@ struct uip_udp_conn *uip_udp_new(const uip_ipaddr_t *ripaddr, uint16_t rport); */ #define uip_udp_send(len) uip_send((char *)uip_appdata, len) + /** @} */ /* uIP convenience and converting functions. */ @@ -1352,6 +1365,9 @@ struct uip_conn { uint8_t timer; /**< The retransmission timer. */ uint8_t nrtx; /**< The number of retransmissions for the last segment sent. */ +#if UIP_WITH_VARIABLE_RETRANSMISSIONS + uint8_t max_mac_transmissions; /**< Number of max MAC-layer transmissions. */ +#endif uip_tcp_appstate_t appstate; /** The application state. */ }; @@ -1389,6 +1405,9 @@ struct uip_udp_conn { uint16_t lport; /**< The local port number in network byte order. */ uint16_t rport; /**< The remote port number in network byte order. */ uint8_t ttl; /**< Default time-to-live. */ +#if UIP_WITH_VARIABLE_RETRANSMISSIONS + uint8_t max_mac_transmissions; /**< Number of max MAC-layer transmissions. */ +#endif /** The application state. */ uip_udp_appstate_t appstate; diff --git a/os/net/ipv6/uip6.c b/os/net/ipv6/uip6.c index b0cab3ebd..d3df05b7f 100644 --- a/os/net/ipv6/uip6.c +++ b/os/net/ipv6/uip6.c @@ -508,6 +508,9 @@ uip_connect(const uip_ipaddr_t *ripaddr, uint16_t rport) conn->rto = UIP_RTO; conn->sa = 0; conn->sv = 16; /* Initial value of the RTT variance. */ +#if UIP_WITH_VARIABLE_RETRANSMISSIONS + conn->max_mac_transmissions = UIP_MAX_MAC_TRANSMISSIONS_UNDEFINED; +#endif conn->lport = uip_htons(lastport); conn->rport = rport; uip_ipaddr_copy(&conn->ripaddr, ripaddr); @@ -581,6 +584,9 @@ uip_udp_new(const uip_ipaddr_t *ripaddr, uint16_t rport) uip_ipaddr_copy(&conn->ripaddr, ripaddr); } conn->ttl = uip_ds6_if.cur_hop_limit; +#if UIP_WITH_VARIABLE_RETRANSMISSIONS + conn->max_mac_transmissions = UIP_MAX_MAC_TRANSMISSIONS_UNDEFINED; +#endif return conn; } @@ -1545,6 +1551,16 @@ uip_process(uint8_t flag) UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); + UIP_IP_BUF->vtc = 0x60; + UIP_IP_BUF->tcflow = 0x00; +#if UIP_WITH_VARIABLE_RETRANSMISSIONS + if(uip_udp_conn->max_mac_transmissions != UIP_MAX_MAC_TRANSMISSIONS_UNDEFINED) { + /* Encapsulate the MAC transmission limit in the Traffic Class field */ + UIP_IP_BUF->vtc = 0x60 | (UIP_TC_MAC_TRANSMISSION_COUNTER_BIT >> 4); + UIP_IP_BUF->tcflow = uip_udp_conn->max_mac_transmissions << 4; + } +#endif /* UIP_WITH_VARIABLE_RETRANSMISSIONS */ + UIP_IP_BUF->ttl = uip_udp_conn->ttl; UIP_IP_BUF->proto = UIP_PROTO_UDP; @@ -2249,6 +2265,16 @@ uip_process(uint8_t flag) UIP_TCP_BUF->srcport = uip_connr->lport; UIP_TCP_BUF->destport = uip_connr->rport; + UIP_IP_BUF->vtc = 0x60; + UIP_IP_BUF->tcflow = 0x00; +#if UIP_WITH_VARIABLE_RETRANSMISSIONS + if(uip_connr->max_mac_transmissions != UIP_MAX_MAC_TRANSMISSIONS_UNDEFINED) { + /* Encapsulate the MAC transmission limit in the Traffic Class field */ + UIP_IP_BUF->vtc = 0x60 | (UIP_TC_MAC_TRANSMISSION_COUNTER_BIT >> 4); + UIP_IP_BUF->tcflow = uip_connr->max_mac_transmissions << 4; + } +#endif /* UIP_WITH_VARIABLE_RETRANSMISSIONS */ + uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &uip_connr->ripaddr); uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); LOG_INFO("Sending TCP packet to "); @@ -2284,8 +2310,6 @@ uip_process(uint8_t flag) #if UIP_UDP ip_send_nolen: #endif - UIP_IP_BUF->vtc = 0x60; - UIP_IP_BUF->tcflow = 0x00; UIP_IP_BUF->flow = 0x00; send: LOG_INFO("Sending packet with length %d (%d)\n", uip_len, diff --git a/os/net/ipv6/uipopt.h b/os/net/ipv6/uipopt.h index 84b7fd023..d668133a8 100644 --- a/os/net/ipv6/uipopt.h +++ b/os/net/ipv6/uipopt.h @@ -518,6 +518,35 @@ void uip_log(char *msg); #define UIP_DEFAULT_PREFIX_LEN 64 +/** + * Enables selection of maximal MAC-layer transmission count at application layer + */ +#ifdef UIP_CONF_WITH_VARIABLE_RETRANSMISSIONS +#define UIP_WITH_VARIABLE_RETRANSMISSIONS UIP_CONF_WITH_VARIABLE_RETRANSMISSIONS +#else +#define UIP_WITH_VARIABLE_RETRANSMISSIONS 0 +#endif + +/** + * This is the default value of MAC-layer transmissons for uIPv6 + * + * It means that the limit is selected by the MAC protocol instead of uIPv6. + */ +#define UIP_MAX_MAC_TRANSMISSIONS_UNDEFINED 0 + +/** + * The MAC-layer transmissons limit is encapslated in "Traffic Class" field + * + * In Contiki, if the Traffic Class field in the IPv6 header has this bit set, + * the low-order bits are used as the MAC-layer transmissons limit. + */ +#define UIP_TC_MAC_TRANSMISSION_COUNTER_BIT 0x40 + +/** + * The bits in the "Traffic Class" field that describe the MAC transmission limit + */ +#define UIP_TC_MAC_TRANSMISSION_COUNTER_MASK 0x3F + /** @} */ /*------------------------------------------------------------------------------*/ diff --git a/os/net/mac/csma/csma-output.c b/os/net/mac/csma/csma-output.c index 167d4374c..532b4ae7a 100644 --- a/os/net/mac/csma/csma-output.c +++ b/os/net/mac/csma/csma-output.c @@ -85,9 +85,9 @@ /* macMaxFrameRetries: Maximum number of re-transmissions attampts. Range 0--7 */ #ifdef CSMA_CONF_MAX_FRAME_RETRIES -#define CSMA_MAX_MAX_FRAME_RETRIES CSMA_CONF_MAX_FRAME_RETRIES +#define CSMA_MAX_FRAME_RETRIES CSMA_MAX_FRAME_RETRIES #else -#define CSMA_MAX_MAX_FRAME_RETRIES 7 +#define CSMA_MAX_FRAME_RETRIES 7 #endif /* Packet metadata */ @@ -506,7 +506,15 @@ csma_output_packet(mac_callback_t sent, void *ptr) if(q->buf != NULL) { struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr; /* Neighbor and packet successfully allocated */ - metadata->max_transmissions = CSMA_MAX_MAX_FRAME_RETRIES + 1; +#if UIP_WITH_VARIABLE_RETRANSMISSIONS + metadata->max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS); + if(metadata->max_transmissions == 0) { + /* If not set by the application, use the default CSMA value */ + metadata->max_transmissions = CSMA_MAX_FRAME_RETRIES + 1; + } +#else + metadata->max_transmissions = CSMA_MAX_FRAME_RETRIES + 1; +#endif metadata->sent = sent; metadata->cptr = ptr; list_add(n->packet_queue, q); diff --git a/os/net/mac/tsch/tsch-queue.c b/os/net/mac/tsch/tsch-queue.c index 388953a60..7aee0d66a 100644 --- a/os/net/mac/tsch/tsch-queue.c +++ b/os/net/mac/tsch/tsch-queue.c @@ -230,7 +230,8 @@ tsch_queue_remove_nbr(struct tsch_neighbor *n) /*---------------------------------------------------------------------------*/ /* Add packet to neighbor queue. Use same lockfree implementation as ringbuf.c (put is atomic) */ struct tsch_packet * -tsch_queue_add_packet(const linkaddr_t *addr, mac_callback_t sent, void *ptr) +tsch_queue_add_packet(const linkaddr_t *addr, uint8_t max_transmissions, + mac_callback_t sent, void *ptr) { struct tsch_neighbor *n = NULL; int16_t put_index = -1; @@ -252,6 +253,7 @@ tsch_queue_add_packet(const linkaddr_t *addr, mac_callback_t sent, void *ptr) p->ptr = ptr; p->ret = MAC_TX_DEFERRED; p->transmissions = 0; + p->max_transmissions = max_transmissions; /* Add to ringbuf (actual add committed through atomic operation) */ n->tx_array[put_index] = p; ringbufindex_put(&n->tx_ringbuf); @@ -342,7 +344,7 @@ tsch_queue_packet_sent(struct tsch_neighbor *n, struct tsch_packet *p, } } else { /* Failed transmission */ - if(p->transmissions >= TSCH_MAC_MAX_FRAME_RETRIES + 1) { + if(p->transmissions >= p->max_transmissions) { /* Drop packet */ tsch_queue_remove_packet_from_queue(n); in_queue = 0; diff --git a/os/net/mac/tsch/tsch-queue.h b/os/net/mac/tsch/tsch-queue.h index 037461e7d..0d77a6105 100644 --- a/os/net/mac/tsch/tsch-queue.h +++ b/os/net/mac/tsch/tsch-queue.h @@ -135,6 +135,7 @@ struct tsch_packet { mac_callback_t sent; /* callback for this packet */ void *ptr; /* MAC callback parameter */ uint8_t transmissions; /* #transmissions performed for this packet */ + uint8_t max_transmissions; /* maximal number of Tx before dropping the packet */ uint8_t ret; /* status -- MAC return code */ uint8_t header_len; /* length of header and header IEs (needed for link-layer security) */ uint8_t tsch_sync_ie_offset; /* Offset within the frame used for quick update of EB ASN and join priority */ @@ -176,7 +177,8 @@ struct tsch_neighbor *tsch_queue_get_time_source(void); /* Update TSCH time source */ int tsch_queue_update_time_source(const linkaddr_t *new_addr); /* Add packet to neighbor queue. Use same lockfree implementation as ringbuf.c (put is atomic) */ -struct tsch_packet *tsch_queue_add_packet(const linkaddr_t *addr, mac_callback_t sent, void *ptr); +struct tsch_packet *tsch_queue_add_packet(const linkaddr_t *addr, uint8_t max_transmissions, + mac_callback_t sent, void *ptr); /* Returns the number of packets currently in any TSCH queue */ int tsch_queue_global_packet_count(void); /* Returns the number of packets currently a given neighbor queue */ diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index 017f6542c..bbaed827a 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -832,8 +832,8 @@ PROCESS_THREAD(tsch_send_eb_process, ev, data) /* Prepare the EB packet and schedule it to be sent */ if(tsch_packet_create_eb(&hdr_len, &tsch_sync_ie_offset) > 0) { struct tsch_packet *p; - /* Enqueue EB packet */ - if(!(p = tsch_queue_add_packet(&tsch_eb_address, NULL, NULL))) { + /* Enqueue EB packet, for a single transmission only */ + if(!(p = tsch_queue_add_packet(&tsch_eb_address, 1, NULL, NULL))) { LOG_ERR("! could not enqueue EB packet\n"); } else { LOG_INFO("TSCH: enqueue EB packet %u %u\n", @@ -958,6 +958,7 @@ send_packet(mac_callback_t sent, void *ptr) int ret = MAC_TX_DEFERRED; int hdr_len = 0; const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); + uint8_t max_transmissions = 0; if(!tsch_is_associated) { if(!tsch_is_initialized) { @@ -1006,13 +1007,21 @@ send_packet(mac_callback_t sent, void *ptr) packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); #endif +#if UIP_WITH_VARIABLE_RETRANSMISSIONS + max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS); +#endif + if(max_transmissions == 0) { + /* If not set by the application, use the default TSCH value */ + max_transmissions = TSCH_MAC_MAX_FRAME_RETRIES + 1; + } + if((hdr_len = NETSTACK_FRAMER.create()) < 0) { LOG_ERR("! can't send packet due to framer error\n"); ret = MAC_TX_ERR; } else { struct tsch_packet *p; /* Enqueue packet */ - p = tsch_queue_add_packet(addr, sent, ptr); + p = tsch_queue_add_packet(addr, max_transmissions, sent, ptr); if(p == NULL) { LOG_ERR("! can't send packet to "); LOG_ERR_LLADDR(addr); diff --git a/os/net/packetbuf.h b/os/net/packetbuf.h index c16a3f8f1..706fe51d6 100644 --- a/os/net/packetbuf.h +++ b/os/net/packetbuf.h @@ -217,6 +217,9 @@ enum { PACKETBUF_ATTR_LINK_QUALITY, PACKETBUF_ATTR_RSSI, PACKETBUF_ATTR_TIMESTAMP, +#if UIP_WITH_VARIABLE_RETRANSMISSIONS + PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS, +#endif /* UIP_WITH_VARIABLE_RETRANSMISSIONS */ PACKETBUF_ATTR_MAC_SEQNO, PACKETBUF_ATTR_MAC_ACK, PACKETBUF_ATTR_MAC_METADATA, diff --git a/tests/13-ieee802154/code-flush-nbr-queue/test-flush-nbr-queue.c b/tests/13-ieee802154/code-flush-nbr-queue/test-flush-nbr-queue.c index 9045f77e4..d8be606ac 100644 --- a/tests/13-ieee802154/code-flush-nbr-queue/test-flush-nbr-queue.c +++ b/tests/13-ieee802154/code-flush-nbr-queue/test-flush-nbr-queue.c @@ -58,7 +58,7 @@ UNIT_TEST(test) UNIT_TEST_BEGIN(); - packet = tsch_queue_add_packet(TEST_PEER_ADDR, NULL, NULL); + packet = tsch_queue_add_packet(TEST_PEER_ADDR, 1, NULL, NULL); UNIT_TEST_ASSERT(packet != NULL); nbr = tsch_queue_get_nbr(TEST_PEER_ADDR); @@ -68,14 +68,14 @@ UNIT_TEST(test) * QUEUEBUF_CONF_NUM is set with 1; so another addition should fail due to * lack of memory. */ - packet = tsch_queue_add_packet(TEST_PEER_ADDR, NULL, NULL); + packet = tsch_queue_add_packet(TEST_PEER_ADDR, 1, NULL, NULL); UNIT_TEST_ASSERT(packet == NULL); /* tsch_queue_flush_nbr_queue() is called inside of tsch_queue_reset(). */ tsch_queue_reset(); /* After flushing the nbr queue, we should be able to add a new packet */ - packet = tsch_queue_add_packet(TEST_PEER_ADDR, NULL, NULL); + packet = tsch_queue_add_packet(TEST_PEER_ADDR, 1, NULL, NULL); UNIT_TEST_ASSERT(packet != NULL); UNIT_TEST_END();