Skip to content

Commit

Permalink
Do not send too old packets (ARMmbed#2632)
Browse files Browse the repository at this point in the history
* Do not send packets that are queued on adaptation layer over 30 seconds

* Do not allow new data request overtake existing one in MAC queue

* Revert "Do not allow new data request overtake existing one in MAC queue"

This reverts commit 5c660e0246139acd1dab99094fe3fdcf1138ad60.

* Do not send any old packets

* Return data request to adaptation layer after timeout

* Fixed missing PHY timestamp cb in unit tests

* Allow removing only normal priority buffers

* Unit tests for removing old buffers from MAC queue

* Cleaning

* Timeout value defined for all buffer priorities

* Updated unit tests

* Updated change log
  • Loading branch information
Jarkko Paso authored Jun 1, 2021
1 parent dbd83be commit 24168f8
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 44 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Filter RPL parents based on DEVICE_MIN_SENS configuration with Threshold and Hysteresis.
* Filter EAPOL parents based on DEVICE_MIN_SENS configuration with Threshold and Hysteresis to prevent EAPOL failures caused by bad signal levels
* Adaptation layer removes oldest packets first when stack needs to release memory or reduce traffic
* Use QoS specific timeout to drop old packets from TX queue to prioritize limited bandwidth.

### Changes
* Statistics for MAC data request latencies. Separated to adaptation layer and MAC queueing delays.
Expand Down
41 changes: 34 additions & 7 deletions source/6LoWPAN/adaptation_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ typedef struct {
#define LOWPAN_MEM_LIMIT_REMOVE_MAX 10000 // Remove when at memory limit
#define LOWPAN_MEM_LIMIT_REMOVE_EF_MODE 20000 // Remove when out of memory and we are in EF mode

#define LOWPAN_TX_BUFFER_AGE_LIMIT_LOW_PRIORITY 30 // Remove low priority packets older than limit (seconds)
#define LOWPAN_TX_BUFFER_AGE_LIMIT_HIGH_PRIORITY 60 // Remove high priority packets older than limit (seconds)
#define LOWPAN_TX_BUFFER_AGE_LIMIT_EF_PRIORITY 120 // Remove expedited forwarding packets older than limit (seconds)



static NS_LIST_DEFINE(fragmenter_interface_list, fragmenter_interface_t, link);
Expand Down Expand Up @@ -1294,6 +1298,23 @@ void lowpan_adaptation_interface_slow_timer(protocol_interface_info_entry_t *cur
}
}

static bool lowpan_adaptation_interface_check_buffer_timeout(buffer_t *buf)
{
// Convert from 100ms slots to seconds
uint32_t buffer_age_s = (protocol_core_monotonic_time - buf->adaptation_timestamp) / 10;

if ((buf->priority == QOS_NORMAL) && (buffer_age_s > LOWPAN_TX_BUFFER_AGE_LIMIT_LOW_PRIORITY)) {
return true;
} else if ((buf->priority == QOS_HIGH) && (buffer_age_s > LOWPAN_TX_BUFFER_AGE_LIMIT_HIGH_PRIORITY)) {
return true;
} else if ((buf->priority == QOS_NETWORK_CTRL) && (buffer_age_s > LOWPAN_TX_BUFFER_AGE_LIMIT_HIGH_PRIORITY)) {
return true;
} else if ((buf->priority == QOS_EXPEDITE_FORWARD) && (buffer_age_s > LOWPAN_TX_BUFFER_AGE_LIMIT_EF_PRIORITY)) {
return true;
}
return false;
}

int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buffer_t *buf)
{
bool is_room_for_new_message;
Expand All @@ -1309,13 +1330,7 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff
if (!interface_ptr) {
goto tx_error_handler;
}
// Set TX start timestamp
if (!buf->adaptation_timestamp) {
buf->adaptation_timestamp = protocol_core_monotonic_time;
if (!buf->adaptation_timestamp) {
buf->adaptation_timestamp--;
}
}

uint8_t traffic_class = buf->options.traffic_class >> IP_TCLASS_DSCP_SHIFT;

if (traffic_class == IP_DSCP_EF) {
Expand All @@ -1327,6 +1342,18 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff
buffer_priority_set(buf, QOS_HIGH);
}

if (!buf->adaptation_timestamp) {
// Set TX start timestamp
buf->adaptation_timestamp = protocol_core_monotonic_time;
if (!buf->adaptation_timestamp) {
buf->adaptation_timestamp--;
}
} else if (lowpan_adaptation_interface_check_buffer_timeout(buf)) {
// Remove old buffers
socket_tx_buffer_event_and_free(buf, SOCKET_TX_FAIL);
return -1;
}

//Update priority status
lowpan_adaptation_priority_status_update(cur, interface_ptr, buf->priority);

Expand Down
56 changes: 43 additions & 13 deletions source/MAC/IEEE802_15_4/mac_mcps_sap.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@

// Used to set TX time (us) with FHSS. Must be <= 65ms.
#define MAC_TX_PROCESSING_DELAY_INITIAL 2000
// Give up on data request after given timeout (seconds)
#define DATA_REQUEST_TIMEOUT_NORMAL_PRIORITY_S 30
#define DATA_REQUEST_TIMEOUT_EF_PRIORITY_S 120

typedef struct {
uint8_t address[8];
Expand Down Expand Up @@ -275,7 +278,7 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set
}
break;
case MAC_DATA_HIGH_PRIORITY:
buffer->priority = MAC_PD_DATA_HIGH_PRIOTITY;
buffer->priority = MAC_PD_DATA_HIGH_PRIORITY;
break;
case MAC_DATA_MEDIUM_PRIORITY:
buffer->priority = MAC_PD_DATA_MEDIUM_PRIORITY;
Expand Down Expand Up @@ -1102,6 +1105,18 @@ static void mac_mcps_asynch_finish(protocol_interface_rf_mac_setup_s *rf_mac_set
}
}

static bool mcps_sap_check_buffer_timeout(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer)
{
// Convert from 1us slots to seconds
uint32_t buffer_age_s = (mac_mcps_sap_get_phy_timestamp(rf_mac_setup) - buffer->request_start_time_us) / 1000000;
if ((buffer->priority == MAC_PD_DATA_NORMAL_PRIORITY) && (buffer_age_s > DATA_REQUEST_TIMEOUT_NORMAL_PRIORITY_S)) {
return true;
} else if ((buffer->priority == MAC_PD_DATA_EF_PRIORITY) && (buffer_age_s > DATA_REQUEST_TIMEOUT_EF_PRIORITY_S)) {
return true;
}
return false;
}

void mac_mcps_trig_buffer_from_queue(protocol_interface_rf_mac_setup_s *rf_mac_setup)
{
if (!rf_mac_setup) {
Expand All @@ -1121,22 +1136,31 @@ void mac_mcps_trig_buffer_from_queue(protocol_interface_rf_mac_setup_s *rf_mac_s
buffer = mcps_sap_pd_req_queue_read(rf_mac_setup, is_bc_queue, false);

if (buffer) {
//Here
if (buffer->ExtendedFrameExchange) {
//Update here state and store peer
memcpy(rf_mac_setup->mac_edfe_info->PeerAddr, buffer->DstAddr, 8);
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_CONNECTING;
}
rf_mac_setup->active_pd_data_request = buffer;
if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) {
if (mcps_sap_check_buffer_timeout(rf_mac_setup, buffer)) {
// Buffer is quite old. Return it to adaptation layer with timeout event.
rf_mac_setup->mac_tx_result = MAC_TX_TIMEOUT;
if (buffer->ExtendedFrameExchange) {
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
}
rf_mac_setup->active_pd_data_request = NULL;
mac_mcps_asynch_finish(rf_mac_setup, buffer);
mcps_data_confirm_handle(rf_mac_setup, buffer, NULL);
} else {
return;
if (buffer->ExtendedFrameExchange) {
//Update here state and store peer
memcpy(rf_mac_setup->mac_edfe_info->PeerAddr, buffer->DstAddr, 8);
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_CONNECTING;
}
rf_mac_setup->active_pd_data_request = buffer;
if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) {
if (buffer->ExtendedFrameExchange) {
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
}
rf_mac_setup->active_pd_data_request = NULL;
mac_mcps_asynch_finish(rf_mac_setup, buffer);
mcps_data_confirm_handle(rf_mac_setup, buffer, NULL);
} else {
return;
}
}
} else {
return;
Expand Down Expand Up @@ -2437,10 +2461,16 @@ static mac_pre_build_frame_t *mcps_sap_pd_req_queue_read(protocol_interface_rf_m

mac_pre_build_frame_t *buffer = queue;
mac_pre_build_frame_t *prev = NULL;
// With FHSS, check TX conditions
/* With FHSS, read buffer out from queue if:
* - Buffer has timed out, OR
* - Buffer is asynch request, OR
* - Queue is flushed, OR
* - Blacklisting AND FHSS allows buffer to be transmitted
*/
if (rf_mac_setup->fhss_api) {
while (buffer) {
if (buffer->asynch_request ||
if (mcps_sap_check_buffer_timeout(rf_mac_setup, buffer) ||
buffer->asynch_request ||
(flush == true) ||
((mcps_check_packet_blacklist(rf_mac_setup, buffer) == false) &&
(rf_mac_setup->fhss_api->check_tx_conditions(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer),
Expand Down
2 changes: 1 addition & 1 deletion source/MAC/IEEE802_15_4/mac_mcps_sap.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ typedef enum {

#define MAC_PD_DATA_NORMAL_PRIORITY 0 //Normal MCPS DATA REQ
#define MAC_PD_DATA_MEDIUM_PRIORITY 1 //Indirect Data which is polled
#define MAC_PD_DATA_HIGH_PRIOTITY 2 //Beacon request Beacon response
#define MAC_PD_DATA_HIGH_PRIORITY 2 //Beacon request Beacon response
#define MAC_PD_DATA_EF_PRIORITY 3 //Expedited forwarding
#define MAC_PD_DATA_TX_IMMEDIATELY 4 //Only for packets whose transmission was interrupted by wrong channel type. E.g. unicast on broadcast channel.

Expand Down
2 changes: 1 addition & 1 deletion source/MAC/IEEE802_15_4/mac_mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -1837,7 +1837,7 @@ int8_t mac_mlme_beacon_tx(protocol_interface_rf_mac_setup_s *rf_ptr)
ptr += BEACON_OPTION_JOIN_PRIORITY_LEN;
}*/
}
buf->priority = MAC_PD_DATA_HIGH_PRIOTITY;
buf->priority = MAC_PD_DATA_HIGH_PRIORITY;
mcps_sap_pd_req_queue_write(rf_ptr, buf);
sw_mac_stats_update(rf_ptr, STAT_MAC_BEA_TX_COUNT, 0);
return 0;
Expand Down
131 changes: 109 additions & 22 deletions test/nanostack/unittest/mac/mac_mcps_sap/test_mac_mcps_sap.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,27 @@ static arm_device_driver_list_s *rf_client_driver_allocate()
return driver;
}

uint32_t test_timestamp = 1000000;
static int8_t test_rf_extension(phy_extension_type_e extension, uint8_t *buf)
{
switch (extension) {
case PHY_EXTENSION_GET_TIMESTAMP:
buf[3] = test_timestamp >> 24;
buf[2] = test_timestamp >> 16;
buf[1] = test_timestamp >> 8;
buf[0] = test_timestamp;
test_timestamp += 100000;
break;
case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS:
*buf = 1;
break;
case PHY_EXTENSION_READ_RX_TIME:
common_write_32_bit(100, buf);
default:
break;
}
return 0;
}

static protocol_interface_rf_mac_setup_s *test_mac_rf_mac_class_allocate(void)
{
Expand All @@ -261,32 +282,11 @@ static protocol_interface_rf_mac_setup_s *test_mac_rf_mac_class_allocate(void)
dev_driver->phy_header_length = 0;
driver->phy_driver = dev_driver;
rf_mac_setup->dev_driver = driver;
rf_mac_setup->dev_driver->phy_driver->extension = test_rf_extension;

return rf_mac_setup;
}

uint32_t test_timestamp = 1000000;
static int8_t test_rf_extension(phy_extension_type_e extension, uint8_t *buf)
{
switch (extension) {
case PHY_EXTENSION_GET_TIMESTAMP:
buf[3] = test_timestamp >> 24;
buf[2] = test_timestamp >> 16;
buf[1] = test_timestamp >> 8;
buf[0] = test_timestamp;
test_timestamp += 100000;
break;
case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS:
*buf = 1;
break;
case PHY_EXTENSION_READ_RX_TIME:
common_write_32_bit(100, buf);
default:
break;
}
return 0;
}

static int8_t test_rf_tx(uint8_t *data, uint16_t length, uint8_t tx_handle, data_protocol_e protocol)
{
return 0;
Expand Down Expand Up @@ -3046,6 +3046,93 @@ bool test_mac_mcps_trig_buffer_from_queue()
return false;
}
mac_mcps_buffer_queue_free(rf_mac_setup);

// Test removing old buffers from queue
rf_mac_setup->fhss_api = ns_fhss_create(0, 0, 0);
// Add 4 buffers in queue, buf and buf2 are too old and should be removed
buf = tes_mac_mcps_temporary_buffer_get(0);
buf2 = tes_mac_mcps_temporary_buffer_get(0);
mac_pre_build_frame_t *buf3 = tes_mac_mcps_temporary_buffer_get(0);
mac_pre_build_frame_t *buf4 = tes_mac_mcps_temporary_buffer_get(0);
buf->request_start_time_us = test_timestamp - 32000000;
buf2->request_start_time_us = test_timestamp - 31000000;
buf3->request_start_time_us = test_timestamp - 25000000;
buf4->request_start_time_us = test_timestamp - 23000000;
rf_mac_setup->pd_data_request_queue_to_go = buf;
rf_mac_setup->pd_data_request_queue_to_go->next = buf2;
rf_mac_setup->pd_data_request_queue_to_go->next->next = buf3;
rf_mac_setup->pd_data_request_queue_to_go->next->next->next = buf4;
rf_mac_setup->unicast_queue_size = 4;
fhss_config_stub.bool_value = false;
fhss_tx_condition = true;
// Trig should remove first two buffers and take third as active data request
mac_mcps_trig_buffer_from_queue(rf_mac_setup);
if (rf_mac_setup->active_pd_data_request != buf3) {
test_mac_rf_mac_class_free(rf_mac_setup);
printf("Fail: Remove old buffers, wrong buffer activated\r\n");
return false;
}
mac_mcps_buffer_queue_free(rf_mac_setup);

// Test removing old buffers with low priority from queue
rf_mac_setup->fhss_api = ns_fhss_create(0, 0, 0);
// Add 4 buffers in queue, buf and buf2 are too old but only first one should be removed
buf = tes_mac_mcps_temporary_buffer_get(0);
buf2 = tes_mac_mcps_temporary_buffer_get(0);
buf3 = tes_mac_mcps_temporary_buffer_get(0);
buf4 = tes_mac_mcps_temporary_buffer_get(0);
buf->request_start_time_us = test_timestamp - 32000000;
buf2->request_start_time_us = test_timestamp - 31000000;
buf3->request_start_time_us = test_timestamp - 25000000;
buf4->request_start_time_us = test_timestamp - 23000000;
// Change buf2 priority to medium
buf2->priority = MAC_PD_DATA_MEDIUM_PRIORITY;
rf_mac_setup->pd_data_request_queue_to_go = buf;
rf_mac_setup->pd_data_request_queue_to_go->next = buf2;
rf_mac_setup->pd_data_request_queue_to_go->next->next = buf3;
rf_mac_setup->pd_data_request_queue_to_go->next->next->next = buf4;
rf_mac_setup->unicast_queue_size = 4;
fhss_config_stub.bool_value = false;
fhss_tx_condition = true;
// Trig should remove first buffer and take second as active data request
mac_mcps_trig_buffer_from_queue(rf_mac_setup);
if (rf_mac_setup->active_pd_data_request != buf2) {
test_mac_rf_mac_class_free(rf_mac_setup);
printf("Fail: Remove old buffers with priority, wrong buffer activated\r\n");
return false;
}
mac_mcps_buffer_queue_free(rf_mac_setup);

// Test removing old buffers with EF priority from queue
rf_mac_setup->fhss_api = ns_fhss_create(0, 0, 0);
// Add 4 buffers in queue, buf(normal priority) and buf2(EF priority) are too old and should be removed
buf = tes_mac_mcps_temporary_buffer_get(0);
buf2 = tes_mac_mcps_temporary_buffer_get(0);
buf3 = tes_mac_mcps_temporary_buffer_get(0);
buf4 = tes_mac_mcps_temporary_buffer_get(0);
buf->request_start_time_us = test_timestamp - 32000000;
buf2->request_start_time_us = test_timestamp - 121000000;
buf3->request_start_time_us = test_timestamp - 100000000;
buf4->request_start_time_us = test_timestamp - 23000000;
// Change buf2 and buf3 priority to expedited forwarding
buf2->priority = MAC_PD_DATA_EF_PRIORITY;
buf3->priority = MAC_PD_DATA_EF_PRIORITY;
rf_mac_setup->pd_data_request_queue_to_go = buf;
rf_mac_setup->pd_data_request_queue_to_go->next = buf2;
rf_mac_setup->pd_data_request_queue_to_go->next->next = buf3;
rf_mac_setup->pd_data_request_queue_to_go->next->next->next = buf4;
rf_mac_setup->unicast_queue_size = 4;
fhss_config_stub.bool_value = false;
fhss_tx_condition = true;
// Trig should remove first two buffers and take third as active data request
mac_mcps_trig_buffer_from_queue(rf_mac_setup);
if (rf_mac_setup->active_pd_data_request != buf3) {
test_mac_rf_mac_class_free(rf_mac_setup);
printf("Fail: Remove old buffers with EF priority, wrong buffer activated\r\n");
return false;
}
mac_mcps_buffer_queue_free(rf_mac_setup);

// Free test setup struct
test_mac_rf_mac_class_free(rf_mac_setup);
return true;
Expand Down

0 comments on commit 24168f8

Please sign in to comment.