Skip to content

Commit 97aaf5f

Browse files
author
Arto Kinnunen
authored
Add network property API to Nanostack (#2318)
Network property API allows application to read network characteristics that can be used to optimise the network operation. Application can give amount of data it wishes to send and the API returns approximated jitter value for the next transmission. The jitter is calculated based on estimated network size, available data rate and some other network properties. The API returns also estimated latency that can be used to adjust application waiting times. Other changes: - Rename socket specific error_t as socket_error_t to avoid naming clashes in tests. -Fix Wi-SUN network size constants
1 parent cfd1a4d commit 97aaf5f

File tree

16 files changed

+299
-43
lines changed

16 files changed

+299
-43
lines changed

nanostack/socket_api.h

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -694,27 +694,29 @@ static inline int8_t socket_read_session_address(int8_t socket, ns_address_t *ad
694694
*
695695
* IPv6 socket options summary
696696
*
697-
* | opt_name / cmsg_type | Data type | set/getsockopt | sendmsg | recvmsg |
698-
* | :--------------------------: | :--------------: | :-------------: | :-----: | :-------------------------------: |
699-
* | SOCKET_IPV6_TCLASS | int16_t | Yes | Yes | If enabled with RECVTCLASS |
700-
* | SOCKET_IPV6_UNICAST_HOPS | int16_t | Yes | No | No |
701-
* | SOCKET_IPV6_MULTICAST_HOPS | int16_t | Yes | No | No |
702-
* | SOCKET_IPV6_ADDR_PREFERENCES | int | Yes | No | No |
703-
* | SOCKET_IPV6_USE_MIN_MTU | int8_t | Yes | Yes | No |
704-
* | SOCKET_IPV6_DONTFRAG | int8_t | Yes | Yes | No |
705-
* | SOCKET_IPV6_FLOW_LABEL | int32_t | Yes | No | No |
706-
* | SOCKET_IPV6_HOPLIMIT | int16_t | No | Yes | If enabled with RECVHOPLIMIT |
707-
* | SOCKET_IPV6_PKTINFO | ns_in6_pktinfo_t | No | Yes | If enabled with RECVPKTINFO |
708-
* | SOCKET_IPV6_RECVPKTINFO | bool | Yes | No | No |
709-
* | SOCKET_IPV6_RECVHOPLIMIT | bool | Yes | No | No |
710-
* | SOCKET_IPV6_RECVTCLASS | bool | Yes | No | No |
711-
* | SOCKET_IPV6_MULTICAST_IF | int8_t | Yes | No | No |
712-
* | SOCKET_IPV6_MULTICAST_LOOP | bool | Yes | Yes | No |
713-
* | SOCKET_IPV6_JOIN_GROUP | ns_ipv6_mreq_t | Set only | No | No |
714-
* | SOCKET_IPV6_LEAVE_GROUP | ns_ipv6_mreq_t | Set only | No | No |
715-
* | SOCKET_BROADCAST_PAN | int8_t | Yes | No | No |
716-
* | SOCKET_LINK_LAYER_SECURITY | int8_t | Yes | No | No |
717-
* | SOCKET_INTERFACE_SELECT | int8_t | Yes | No | No |
697+
* | opt_name / cmsg_type | Data type | set/getsockopt | sendmsg | recvmsg |
698+
* | :--------------------------: | :---------- ----: | :-------------: | :-----: | :-------------------------------: |
699+
* | SOCKET_IPV6_TCLASS | int16_t | Yes | Yes | If enabled with RECVTCLASS |
700+
* | SOCKET_IPV6_UNICAST_HOPS | int16_t | Yes | No | No |
701+
* | SOCKET_IPV6_MULTICAST_HOPS | int16_t | Yes | No | No |
702+
* | SOCKET_IPV6_ADDR_PREFERENCES | int | Yes | No | No |
703+
* | SOCKET_IPV6_USE_MIN_MTU | int8_t | Yes | Yes | No |
704+
* | SOCKET_IPV6_DONTFRAG | int8_t | Yes | Yes | No |
705+
* | SOCKET_IPV6_FLOW_LABEL | int32_t | Yes | No | No |
706+
* | SOCKET_IPV6_HOPLIMIT | int16_t | No | Yes | If enabled with RECVHOPLIMIT |
707+
* | SOCKET_IPV6_PKTINFO | ns_in6_pktinfo_t | No | Yes | If enabled with RECVPKTINFO |
708+
* | SOCKET_IPV6_RECVPKTINFO | bool | Yes | No | No |
709+
* | SOCKET_IPV6_RECVHOPLIMIT | bool | Yes | No | No |
710+
* | SOCKET_IPV6_RECVTCLASS | bool | Yes | No | No |
711+
* | SOCKET_IPV6_MULTICAST_IF | int8_t | Yes | No | No |
712+
* | SOCKET_IPV6_MULTICAST_LOOP | bool | Yes | Yes | No |
713+
* | SOCKET_IPV6_JOIN_GROUP | ns_ipv6_mreq_t | Set only | No | No |
714+
* | SOCKET_IPV6_LEAVE_GROUP | ns_ipv6_mreq_t | Set only | No | No |
715+
* | SOCKET_BROADCAST_PAN | int8_t | Yes | No | No |
716+
* | SOCKET_LINK_LAYER_SECURITY | int8_t | Yes | No | No |
717+
* | SOCKET_INTERFACE_SELECT | int8_t | Yes | No | No |
718+
* | SOCKET_LATENCY | ns_ipv6_latency_t | Get only | No | No |
719+
* | SOCKET_STAGGER | ns_ipv6_stagger_t | Get only | No | No |
718720
*
719721
*/
720722

@@ -753,6 +755,10 @@ static inline int8_t socket_read_session_address(int8_t socket, ns_address_t *ad
753755
#define SOCKET_IPV6_JOIN_GROUP 15
754756
/** Leave a multicast group, using ns_ipv6_mreq_t */
755757
#define SOCKET_IPV6_LEAVE_GROUP 16
758+
/** Read estimated latency to reach destination */
759+
#define SOCKET_LATENCY 17
760+
/** Read estimated stagger value that can be used as initial delay after bootstrap or firmware update. */
761+
#define SOCKET_STAGGER 18
756762

757763
#define SOCKET_BROADCAST_PAN 0xfc /**< Internal use - transmit with IEEE 802.15.4 broadcast PAN ID */
758764
#define SOCKET_LINK_LAYER_SECURITY 0xfd /**< Not standard enable or disable socket security at link layer (For 802.15.4). */
@@ -765,6 +771,20 @@ typedef struct ns_ipv6_mreq {
765771
int8_t ipv6mr_interface; /**< interface id */
766772
} ns_ipv6_mreq_t;
767773

774+
/** Latency request used for getsockopt() */
775+
typedef struct {
776+
uint8_t dest_addr[16]; /**< [IN] IPv6 destination address */
777+
uint32_t latency; /**< [OUT] estimated latency value in milliseconds */
778+
} ns_ipv6_latency_t;
779+
780+
/** Stagger request used for getsockopt() */
781+
typedef struct {
782+
uint8_t dest_addr[16]; /**< [IN] IPv6 destination address */
783+
uint16_t data_amount; /**< [IN] Amount of data in kilobytes */
784+
uint16_t stagger_min; /**< [OUT] Minimum stagger value in seconds */
785+
uint16_t stagger_max; /**< [OUT] Maximum stagger value in seconds */
786+
uint16_t stagger_rand; /**< [OUT] Randomized stagger value in seconds */
787+
} ns_ipv6_stagger_t;
768788
/**
769789
* \brief Set an option for a socket
770790
*
@@ -804,6 +824,7 @@ int8_t socket_setsockopt(int8_t socket, uint8_t level, uint8_t opt_name, const v
804824
* \return 0 on success.
805825
* \return -1 invalid socket ID.
806826
* \return -2 invalid/unsupported option.
827+
* \return -3 data can't be retrieved.
807828
*/
808829
int8_t socket_getsockopt(int8_t socket, uint8_t level, uint8_t opt_name, void *opt_value, uint16_t *opt_len);
809830

nanostack/ws_management_api.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,11 @@ extern "C" {
7575
#define CHANNEL_SPACING_100 0x03 // 100 khz
7676
#define CHANNEL_SPACING_250 0x04 // 250 khz
7777

78-
#define NETWORK_SIZE_AUTOMATIC 0x00
79-
#define NETWORK_SIZE_SMALL 0x01
80-
#define NETWORK_SIZE_MEDIUM 0x08
81-
#define NETWORK_SIZE_LARGE 0x10
82-
#define NETWORK_SIZE_CERTIFICATE 0xFF
83-
78+
#define NETWORK_SIZE_CERTIFICATE 0x00
79+
#define NETWORK_SIZE_SMALL 0x01
80+
#define NETWORK_SIZE_MEDIUM 0x08
81+
#define NETWORK_SIZE_LARGE 0x10
82+
#define NETWORK_SIZE_AUTOMATIC 0xFF
8483

8584
/** Temporary API change flag. this will be removed when new version of API is implemented on applications
8685
*

source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
#include "6LoWPAN/Fragmentation/cipv6_fragmenter.h"
7575
#include "Service_Libs/etx/etx.h"
7676
#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
77+
#include "6LoWPAN/ws/ws_common.h"
7778
#include "6LoWPAN/ws/ws_bootstrap.h"
7879

7980

@@ -779,3 +780,83 @@ uint8_t protocol_6lowpan_beacon_compare_rx(int8_t interface_id, uint8_t join_pri
779780

780781
return conn_to_pref;
781782
}
783+
784+
bool protocol_6lowpan_latency_estimate_get(int8_t interface_id, uint32_t *latency)
785+
{
786+
protocol_interface_info_entry_t *cur_interface = protocol_stack_interface_info_get_by_id(interface_id);
787+
uint32_t latency_estimate = 0;
788+
789+
if (!cur_interface) {
790+
return false;
791+
}
792+
793+
if (cur_interface->eth_mac_api) {
794+
// either PPP or Ethernet interface.
795+
latency_estimate = 100;
796+
} else if (thread_info(cur_interface)) {
797+
// thread network
798+
latency_estimate = 1000;
799+
} else if (ws_info(cur_interface)) {
800+
latency_estimate = ws_common_latency_estimate_get(cur_interface);
801+
} else {
802+
// 6LoWPAN ND
803+
latency_estimate = 8000;
804+
}
805+
806+
if (latency_estimate != 0) {
807+
*latency = latency_estimate;
808+
return true;
809+
}
810+
811+
return false;
812+
}
813+
814+
bool protocol_6lowpan_stagger_estimate_get(int8_t interface_id, uint32_t data_amount, uint16_t *stagger_min, uint16_t *stagger_max, uint16_t *stagger_rand)
815+
{
816+
size_t network_size;
817+
uint32_t datarate;
818+
protocol_interface_info_entry_t *cur_interface = protocol_stack_interface_info_get_by_id(interface_id);
819+
820+
if (!cur_interface) {
821+
return false;
822+
}
823+
824+
*stagger_min = 1;
825+
826+
if (cur_interface->eth_mac_api) {
827+
// either PPP or Ethernet interface.
828+
network_size = 1;
829+
datarate = 1000000;
830+
} else if (thread_info(cur_interface)) {
831+
// thread network
832+
network_size = 23;
833+
datarate = 250000;
834+
} else if (ws_info(cur_interface)) {
835+
network_size = ws_common_network_size_estimate_get(cur_interface);
836+
datarate = ws_common_datarate_get(cur_interface);
837+
} else {
838+
// 6LoWPAN ND
839+
network_size = 1000;
840+
datarate = 250000;
841+
}
842+
843+
if (data_amount == 0) {
844+
// If no data amount given, use 1kB
845+
data_amount = 1;
846+
}
847+
/**Example:
848+
* Maximum stagger value to send 1kB on 50 devices network using datarate 50000 kb/:
849+
* (1 * 1024 * 8 * 50) / (50000/4)) = ~ 32s
850+
*
851+
* devices: 50, datarate: 250kbps => stagger ~ 6s
852+
* devices: 1000, datarate: 50kbps => stagger ~ 655s
853+
*/
854+
/* Do not occupy whole bandwidth, halve the theoretical datarate and reserve room for other channel usage */
855+
datarate = datarate / 4;
856+
*stagger_max = (uint16_t) * stagger_min + ((data_amount * 1024 * 8 * network_size) / datarate);
857+
858+
// Randomize stagger value
859+
*stagger_rand = randLIB_get_random_in_range(*stagger_min, *stagger_max);
860+
861+
return true;
862+
}

source/6LoWPAN/Bootstraps/protocol_6lowpan.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,7 @@ uint8_t protocol_6lowpan_beacon_join_priority_tx(int8_t interface_id);
7575
uint8_t protocol_6lowpan_beacon_compare_rx(int8_t interface_id, uint8_t join_priority, uint8_t link_quality);
7676
bool protocol_6lowpan_bootsrap_start(struct protocol_interface_info_entry *interface);
7777
bool protocol_6lowpan_bootsrap_link_set(struct protocol_interface_info_entry *interface, struct mlme_pan_descriptor_s *pan_descriptor, const uint8_t *beacon_payload, uint8_t beacon_length);
78+
bool protocol_6lowpan_latency_estimate_get(int8_t interface_id, uint32_t *latency);
79+
bool protocol_6lowpan_stagger_estimate_get(int8_t interface_id, uint32_t data_amount, uint16_t *stagger_min, uint16_t *stagger_max, uint16_t *stagger_rand);
7880

7981
#endif /* PROTOCOL_6LOWPAN_H_ */

source/6LoWPAN/ws/ws_common.c

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,57 @@ uint32_t ws_common_version_timeout_get(uint8_t config)
483483
return lifetime;
484484
}
485485

486+
uint32_t ws_common_latency_estimate_get(protocol_interface_info_entry_t *cur)
487+
{
488+
uint32_t latency = 0;
489+
490+
if (cur->ws_info->network_size_config <= NETWORK_SIZE_SMALL) {
491+
// handles also NETWORK_SIZE_CERTIFICATE
492+
latency = 8000;
493+
} else if (cur->ws_info->network_size_config <= NETWORK_SIZE_MEDIUM) {
494+
latency = 16000;
495+
} else if (cur->ws_info->network_size_config <= NETWORK_SIZE_LARGE) {
496+
latency = 32000;
497+
} else { /* <= NETWORK_SIZE_AUTOMATIC */
498+
// Make assumption based on current pan size
499+
if (cur->ws_info->pan_information.pan_size < 50) {
500+
latency = 8000;
501+
} else {
502+
latency = 32000;
503+
}
504+
}
486505

487-
#endif // HAVE_WS
506+
return latency;
507+
}
508+
509+
uint32_t ws_common_datarate_get(protocol_interface_info_entry_t *cur)
510+
{
511+
return ws_get_datarate_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode);
512+
}
488513

514+
uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cur)
515+
{
516+
uint32_t network_size_estimate = 0;
517+
518+
if (cur->ws_info->network_size_config <= NETWORK_SIZE_SMALL) {
519+
// tens of devices (now 30), handles also NETWORK_SIZE_CERTIFICATE
520+
network_size_estimate = 30;
521+
} else if (cur->ws_info->network_size_config <= NETWORK_SIZE_MEDIUM) {
522+
// hundreds of devices (now 300)
523+
network_size_estimate = 300;
524+
} else if (cur->ws_info->network_size_config <= NETWORK_SIZE_LARGE) {
525+
// huge amount of devices (now 1000)
526+
network_size_estimate = 1000;
527+
} else { /* <= NETWORK_SIZE_AUTOMATIC */
528+
// Make assumption based on current pan size
529+
if (cur->ws_info->pan_information.pan_size < 50) {
530+
network_size_estimate = 50;
531+
} else {
532+
network_size_estimate = 1000;
533+
}
534+
}
535+
536+
return network_size_estimate;
537+
}
538+
539+
#endif // HAVE_WS

source/6LoWPAN/ws/ws_common.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, con
148148

149149
uint32_t ws_common_version_timeout_get(uint8_t config);
150150

151+
uint32_t ws_common_latency_estimate_get(protocol_interface_info_entry_t *cur);
152+
153+
uint32_t ws_common_datarate_get(protocol_interface_info_entry_t *cur);
154+
155+
uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cur);
156+
151157
#define ws_info(cur) ((cur)->ws_info)
152158
#else
153159
#define ws_info(cur) ((ws_info_t *) NULL)
@@ -158,6 +164,9 @@ uint32_t ws_common_version_timeout_get(uint8_t config);
158164
#define ws_common_fast_timer(cur, ticks) ((void) 0)
159165
#define ws_common_allow_child_registration(cur, eui64) (2)
160166
#define ws_common_negative_aro_mark(interface, eui64)(false)
167+
#define ws_common_latency_estimate_get(cur) 0
168+
#define ws_common_datarate_get(cur) 0
169+
#define ws_common_network_size_estimate_get(cur) 0
161170

162171
#endif //HAVE_WS
163172
#endif //WS_COMMON_H_

source/Core/include/ns_error_types.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@
2222
* \enum error_t
2323
* \brief System generic error.
2424
*/
25-
typedef enum error_t {
25+
typedef enum {
2626
eOK = 0, /*!< no error */
2727
eFALSE = 1, /*!< no result */
2828
eBUSY = 2, /*!< resource busy */
2929
eSYSTEM /*!< error code readable in sys_error */
30-
} error_t;
30+
} socket_error_t;
3131

3232
#endif /* NS_ERROR_TYPES_H_ */

source/Core/include/ns_socket.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ extern void socket_init(void);
190190
extern int8_t socket_event_handler_id_get(void);
191191
extern bool socket_data_queued_event_push(socket_t *socket);
192192
extern void socket_event_push(uint8_t sock_event, socket_t *socket, int8_t interface_id, void *session_ptr, uint16_t length);
193-
extern error_t socket_create(socket_family_t family, socket_type_t type, uint8_t protocol, int8_t *sid, uint16_t port, void (*passed_fptr)(void *), bool buffer_type);
193+
extern socket_error_t socket_create(socket_family_t family, socket_type_t type, uint8_t protocol, int8_t *sid, uint16_t port, void (*passed_fptr)(void *), bool buffer_type);
194194
extern socket_t *socket_new_incoming_connection(socket_t *listen_socket);
195195
void socket_connection_abandoned(socket_t *socket, int8_t interface_id, uint8_t reason);
196196
void socket_connection_complete(socket_t *socket, int8_t interface_id);
@@ -201,8 +201,8 @@ extern void socket_id_detach(int8_t sid);
201201
extern buffer_t *socket_buffer_read(socket_t *socket);
202202
extern socket_t *socket_lookup(socket_family_t family, uint8_t protocol, const sockaddr_t *local_addr, const sockaddr_t *remote_addr);
203203
extern socket_t *socket_lookup_ipv6(uint8_t protocol, const sockaddr_t *local_addr, const sockaddr_t *remote_addr, bool allow_wildcards);
204-
extern error_t socket_port_validate(uint16_t port, uint8_t protocol);
205-
extern error_t socket_up(buffer_t *buf);
204+
extern socket_error_t socket_port_validate(uint16_t port, uint8_t protocol);
205+
extern socket_error_t socket_up(buffer_t *buf);
206206
extern bool socket_message_validate_iov(const struct ns_msghdr *msg, uint16_t *length_out);
207207
extern int16_t socket_buffer_sendmsg(int8_t sid, buffer_t *buf, const struct ns_msghdr *msg, int flags);
208208
extern socket_t *socket_pointer_get(int8_t socket);

source/Core/ns_socket.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ static void socket_free(socket_t *socket)
342342
ns_dyn_mem_free(socket);
343343
}
344344

345-
error_t socket_port_validate(uint16_t port, uint8_t protocol)
345+
socket_error_t socket_port_validate(uint16_t port, uint8_t protocol)
346346
{
347347
ns_list_foreach(socket_t, socket, &socket_list) {
348348
if (!socket_is_ipv6(socket)) {
@@ -497,7 +497,7 @@ socket_t *socket_dereference(socket_t *socket_ptr)
497497
* \return eFALSE no free sockets
498498
* \return eBUSY port reserved
499499
*/
500-
error_t socket_create(socket_family_t family, socket_type_t type, uint8_t protocol, int8_t *sid, uint16_t port, void (*passed_fptr)(void *), bool buffer_type)
500+
socket_error_t socket_create(socket_family_t family, socket_type_t type, uint8_t protocol, int8_t *sid, uint16_t port, void (*passed_fptr)(void *), bool buffer_type)
501501
{
502502
if (sid) {
503503
*sid = -1;
@@ -850,7 +850,7 @@ socket_t *socket_lookup(socket_family_t family, uint8_t protocol, const sockaddr
850850
* \return eFALSE no socket found
851851
* \return eBUSY socket full
852852
*/
853-
error_t socket_up(buffer_t *buf)
853+
socket_error_t socket_up(buffer_t *buf)
854854
{
855855
socket_t *socket = buf->socket;
856856

0 commit comments

Comments
 (0)