1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #15560 from maribu/gnrc-aux-rx-timestamps

net/gnrc/sock: Implement sock_aux_timestamp for RX
This commit is contained in:
Martine Lenders 2020-12-10 19:20:16 +01:00 committed by GitHub
commit 08d86295d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 261 additions and 50 deletions

View File

@ -43,6 +43,7 @@ PSEUDOMODULES += gnrc_netapi_callbacks
PSEUDOMODULES += gnrc_netapi_mbox
PSEUDOMODULES += gnrc_netif_bus
PSEUDOMODULES += gnrc_netif_events
PSEUDOMODULES += gnrc_netif_timestamp
PSEUDOMODULES += gnrc_pktbuf_cmd
PSEUDOMODULES += gnrc_netif_6lo
PSEUDOMODULES += gnrc_netif_ipv6

View File

@ -185,6 +185,9 @@ endif
ifneq (,$(filter gnrc_sock_%,$(USEMODULE)))
USEMODULE += gnrc_sock
ifneq (,$(filter sock_aux_timestamp,$(USEMODULE)))
USEMODULE += gnrc_netif_timestamp
endif
endif
ifneq (,$(filter gnrc_sock_async,$(USEMODULE)))

View File

@ -88,6 +88,17 @@ extern "C" {
* @ref IEEE802154_FCF_FRAME_PEND
*/
#define GNRC_NETIF_HDR_FLAGS_MORE_DATA (0x10)
/**
* @brief Indicate presence of a valid timestamp
*
* @details If (and only if) module `gnrc_netif_timestamp` is used and the
* network device supplied the timestamp of reception of a frame, this
* timestamp is passed up the network stack through
* @ref gnrc_netif_hdr_t::timestamp and this flag is set. This flag
* can be used to check for presence of a valid timestamp.
*/
#define GNRC_NETIF_HDR_FLAGS_TIMESTAMP (0x08)
/**
* @}
*/
@ -105,6 +116,24 @@ typedef struct {
uint8_t flags; /**< flags as defined above */
uint8_t lqi; /**< lqi of received packet (optional) */
int16_t rssi; /**< rssi of received packet in dBm (optional) */
#if IS_USED(MODULE_GNRC_NETIF_TIMESTAMP) || defined(DOXYGEN)
/**
* @brief Timestamp of reception in nanoseconds since epoch
*
* @note Only when @ref GNRC_NETIF_HDR_FLAGS_TIMESTAMP is set, this
* field contains valid info.
*
* This field is only provided if module `gnrc_netif_timestamp` is used.
* Keep in mind that when the hardware does not provide timestamping, the
* network device driver could choose to provide this in software, which
* adds the delay and jitter of the ISR handling to the timestamp. Please
* keep also in mind that a hardware implementation might not be able to
* reliable timestamp every frame - e.g. a full-duplex wired interface might
* be unable to timestamp a received frame while timestamping an outgoing
* frame.
*/
uint64_t timestamp;
#endif /* MODULE_GNRC_NETIF_TIMESTAMP */
} gnrc_netif_hdr_t;
/**
@ -201,6 +230,50 @@ static inline void gnrc_netif_hdr_set_dst_addr(gnrc_netif_hdr_t *hdr,
memcpy(((uint8_t *)(hdr + 1)) + hdr->src_l2addr_len, addr, addr_len);
}
/**
* @brief Set the timestamp in the netif header
* @param[out] hdr Header to set the timestamp in
* @param[in] timestamp Timestamp to set (nanoseconds since epoch)
*
* @details If the module gnrc_netif_timestamp is not used, a call to this
* function become a non-op (and will be fully optimized out by the
* compiler)
*/
static inline void gnrc_netif_hdr_set_timestamp(gnrc_netif_hdr_t *hdr,
uint64_t timestamp)
{
(void)hdr;
(void)timestamp;
#if IS_USED(MODULE_GNRC_NETIF_TIMESTAMP)
hdr->timestamp = timestamp;
hdr->flags |= GNRC_NETIF_HDR_FLAGS_TIMESTAMP;
#endif
}
/**
* @brief Get the timestamp of the frame in nanoseconds since epoch
* @param[in] hdr Header to read the timestamp from
* @param[out] dest The timestamp will be stored here
* @retval 0 The timestamp was stored in @p dest
* @retval -1 No timestamp available, @p dest is unchanged
*
* @details If the module gnrc_netif_timestamp is not used, this will always
* return 0
*/
static inline int gnrc_netif_hdr_get_timestamp(const gnrc_netif_hdr_t *hdr,
uint64_t *dest)
{
(void)hdr;
(void)dest;
#if IS_USED(MODULE_GNRC_NETIF_TIMESTAMP)
if (hdr->flags & GNRC_NETIF_HDR_FLAGS_TIMESTAMP) {
*dest = hdr->timestamp;
return 0;
}
#endif
return -1;
}
#if defined(MODULE_GNRC_IPV6) || defined(DOXYGEN)
/**
* @brief Converts the source address of a given @ref net_gnrc_netif_hdr to

View File

@ -90,7 +90,7 @@ void gnrc_sock_create(gnrc_sock_reg_t *reg, gnrc_nettype_t type, uint32_t demux_
ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
uint32_t timeout, sock_ip_ep_t *remote,
gnrc_sock_recv_aux_t aux)
gnrc_sock_recv_aux_t *aux)
{
/* only used when some sock_aux_% module is used */
(void)aux;
@ -154,9 +154,9 @@ ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
memcpy(&remote->addr, &ipv6_hdr->src, sizeof(ipv6_addr_t));
remote->family = AF_INET6;
#if IS_USED(MODULE_SOCK_AUX_LOCAL)
if (aux.local != NULL) {
memcpy(&aux.local->addr, &ipv6_hdr->dst, sizeof(ipv6_addr_t));
aux.local->family = AF_INET6;
if (aux->local != NULL) {
memcpy(&aux->local->addr, &ipv6_hdr->dst, sizeof(ipv6_addr_t));
aux->local->family = AF_INET6;
}
#endif /* MODULE_SOCK_AUX_LOCAL */
netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);
@ -167,6 +167,13 @@ ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
gnrc_netif_hdr_t *netif_hdr = netif->data;
/* TODO: use API in #5511 */
remote->netif = (uint16_t)netif_hdr->if_pid;
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
if (aux->timestamp != NULL) {
if (gnrc_netif_hdr_get_timestamp(netif_hdr, aux->timestamp) == 0) {
aux->flags |= GNRC_SOCK_RECV_AUX_FLAG_TIMESTAMP;
}
}
#endif /* MODULE_SOCK_AUX_TIMESTAMP */
}
*pkt_out = pkt; /* set out parameter */

View File

@ -70,18 +70,17 @@ typedef struct {
*/
sock_ip_ep_t *local;
#endif
#if !IS_USED(MODULE_SOCK_AUX_LOCAL) || DOXYGEN
/**
* @brief Workaround in case no `sock_aux_%` module is used
*
* Empty structures are only allowed with a GNU extension. For portability,
* this member is present if and only if this structure would be otherwise
* empty.
*/
uint8_t this_struct_is_not_empty;
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP) || DOXYGEN
uint64_t *timestamp; /**< timestamp PDU was received at in nanoseconds */
#endif
/**
* @brief Flags
*/
uint8_t flags;
} gnrc_sock_recv_aux_t;
#define GNRC_SOCK_RECV_AUX_FLAG_TIMESTAMP 0x01 /**< Timestamp valid */
/**
* @brief Internal helper functions for GNRC
* @internal
@ -143,7 +142,7 @@ void gnrc_sock_create(gnrc_sock_reg_t *reg, gnrc_nettype_t type, uint32_t demux_
* @internal
*/
ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt, uint32_t timeout,
sock_ip_ep_t *remote, gnrc_sock_recv_aux_t aux);
sock_ip_ep_t *remote, gnrc_sock_recv_aux_t *aux);
/**
* @brief Send a packet internally

View File

@ -135,7 +135,12 @@ ssize_t sock_ip_recv_buf_aux(sock_ip_t *sock, void **data, void **buf_ctx,
_aux.local = &aux->local;
}
#endif
res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp, _aux);
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
if ((aux != NULL) && (aux->flags & SOCK_AUX_GET_TIMESTAMP)) {
_aux.timestamp = &aux->timestamp;
}
#endif
res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp, &_aux);
if (res < 0) {
return res;
}
@ -156,6 +161,16 @@ ssize_t sock_ip_recv_buf_aux(sock_ip_t *sock, void **data, void **buf_ctx,
if ((aux != NULL) && (aux->flags & SOCK_AUX_GET_LOCAL)) {
aux->flags &= ~(SOCK_AUX_GET_LOCAL);
}
#endif
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
if ((aux != NULL) && (aux->flags & SOCK_AUX_GET_TIMESTAMP)) {
/* check if network interface did provide a timestamp; this depends on
* hardware support. A timestamp of zero is used to indicate a missing
* timestamp */
if (aux->timestamp > 0) {
aux->flags &= ~SOCK_AUX_GET_TIMESTAMP;
}
}
#endif
*data = pkt->data;
*buf_ctx = pkt;

View File

@ -224,7 +224,12 @@ ssize_t sock_udp_recv_buf_aux(sock_udp_t *sock, void **data, void **buf_ctx,
_aux.local = (sock_ip_ep_t *)&aux->local;
}
#endif
res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp, _aux);
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
if ((aux != NULL) && (aux->flags & SOCK_AUX_GET_TIMESTAMP)) {
_aux.timestamp = &aux->timestamp;
}
#endif
res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp, &_aux);
if (res < 0) {
return res;
}
@ -251,6 +256,16 @@ ssize_t sock_udp_recv_buf_aux(sock_udp_t *sock, void **data, void **buf_ctx,
aux->flags &= ~SOCK_AUX_GET_LOCAL;
aux->local.port = sock->local.port;
}
#endif
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
if ((aux != NULL) && (aux->flags & SOCK_AUX_GET_TIMESTAMP)) {
/* check if network interface did provide a timestamp; this depends on
* hardware support. A timestamp of zero is used to indicate a missing
* timestamp */
if (_aux.flags & GNRC_SOCK_RECV_AUX_FLAG_TIMESTAMP) {
aux->flags &= ~SOCK_AUX_GET_TIMESTAMP;
}
}
#endif
*data = pkt->data;
*buf_ctx = pkt;

View File

@ -1,11 +1,16 @@
include ../Makefile.tests_common
AUX_LOCAL ?= 1
AUX_TIMESTAMP ?= 1
ifeq (1, $(AUX_LOCAL))
USEMODULE += sock_aux_local
endif
ifeq (1, $(AUX_LOCAL))
USEMODULE += sock_aux_timestamp
endif
USEMODULE += sock_ip
USEMODULE += gnrc_ipv6
USEMODULE += ps

View File

@ -349,13 +349,16 @@ static void test_sock_ip_recv__aux(void)
static const ipv6_addr_t src_addr = { .u8 = _TEST_ADDR_REMOTE };
static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
static const sock_ip_ep_t local = { .family = AF_INET6 };
static const inject_aux_t inject_aux = { .timestamp = 42 };
sock_ip_ep_t result;
sock_ip_aux_rx_t aux = { .flags = SOCK_AUX_GET_LOCAL };
sock_ip_aux_rx_t aux = {
.flags = SOCK_AUX_GET_LOCAL | SOCK_AUX_GET_TIMESTAMP
};
expect(0 == sock_ip_create(&_sock, &local, NULL, _TEST_PROTO,
SOCK_FLAGS_REUSE_EP));
expect(_inject_packet(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
sizeof("ABCD"), _TEST_NETIF));
expect(_inject_packet_aux(&src_addr, &dst_addr, _TEST_PROTO, "ABCD",
sizeof("ABCD"), _TEST_NETIF, &inject_aux));
expect(sizeof("ABCD") == sock_ip_recv_aux(&_sock, _test_buffer,
sizeof(_test_buffer), 0, &result,
&aux));
@ -367,6 +370,12 @@ static void test_sock_ip_recv__aux(void)
expect(memcmp(&aux.local.addr, &dst_addr, sizeof(dst_addr)) == 0);
#else
expect(aux.flags & SOCK_AUX_GET_LOCAL);
#endif
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
expect(!(aux.flags & SOCK_AUX_GET_TIMESTAMP));
expect(aux.timestamp == inject_aux.timestamp);
#else
expect(aux.flags & SOCK_AUX_GET_TIMESTAMP);
#endif
expect(_check_net());
}

View File

@ -41,9 +41,10 @@ void _prepare_send_checks(void)
static gnrc_pktsnip_t *_build_ipv6_packet(const ipv6_addr_t *src,
const ipv6_addr_t *dst, uint8_t nh,
void *data, size_t data_len,
uint16_t netif)
uint16_t netif,
const inject_aux_t *aux)
{
gnrc_pktsnip_t *netif_hdr, *ipv6, *payload;
gnrc_pktsnip_t *netif_hdr_snip, *ipv6, *payload;
ipv6_hdr_t *ipv6_hdr;
if ((netif > INT16_MAX) || (data_len > UINT16_MAX)) {
@ -63,21 +64,25 @@ static gnrc_pktsnip_t *_build_ipv6_packet(const ipv6_addr_t *src,
ipv6_hdr->nh = nh;
ipv6_hdr->hl = 64;
payload = gnrc_pkt_append(payload, ipv6);
netif_hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
if (netif_hdr == NULL) {
netif_hdr_snip = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
if (netif_hdr_snip == NULL) {
return NULL;
}
((gnrc_netif_hdr_t *)netif_hdr->data)->if_pid = (kernel_pid_t)netif;
return gnrc_pkt_append(payload, netif_hdr);
gnrc_netif_hdr_t *netif_hdr = netif_hdr_snip->data;
netif_hdr->if_pid = (kernel_pid_t)netif;
if (aux) {
gnrc_netif_hdr_set_timestamp(netif_hdr, aux->timestamp);
}
return gnrc_pkt_append(payload, netif_hdr_snip);
}
bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
uint8_t proto, void *data, size_t data_len,
uint16_t netif)
bool _inject_packet_aux(const ipv6_addr_t *src, const ipv6_addr_t *dst,
uint8_t proto, void *data, size_t data_len,
uint16_t netif, const inject_aux_t *aux)
{
gnrc_pktsnip_t *pkt = _build_ipv6_packet(src, dst, proto, data, data_len,
netif);
netif, aux);
if (pkt == NULL) {
return false;

View File

@ -39,6 +39,31 @@ void _net_init(void);
*/
void _prepare_send_checks(void);
/**
* @brief Structure containing auxiliary data to inject
*/
typedef struct {
uint64_t timestamp; /**< Timestamp of reception */
} inject_aux_t;
/**
* @brief Injects a received IPv6 packet into the stack
*
* @param[in] src The source address of the IPv6 packet
* @param[in] dst The destination address of the IPv6 packet
* @param[in] proto The next header field of the IPv6 packet
* @param[in] data The payload of the IPv6 packet
* @param[in] data_len The payload length of the IPv6 packet
* @param[in] netif The interface the packet came over
* @param[in] aux Auxiliary data to inject
*
* @return true, if packet was successfully injected
* @return false, if an error occurred during injection
*/
bool _inject_packet_aux(const ipv6_addr_t *src, const ipv6_addr_t *dst,
uint8_t proto, void *data, size_t data_len,
uint16_t netif, const inject_aux_t *aux);
/**
* @brief Injects a received IPv6 packet into the stack
*
@ -52,9 +77,13 @@ void _prepare_send_checks(void);
* @return true, if packet was successfully injected
* @return false, if an error occurred during injection
*/
bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
uint8_t proto, void *data, size_t data_len,
uint16_t netif);
static inline bool _inject_packet(const ipv6_addr_t *src,
const ipv6_addr_t *dst,
uint8_t proto, void *data, size_t data_len,
uint16_t netif)
{
return _inject_packet_aux(src, dst, proto, data, data_len, netif, NULL);
}
/**
* @brief Checks networking state (e.g. packet buffer state)

View File

@ -1,11 +1,16 @@
include ../Makefile.tests_common
AUX_LOCAL ?= 1
AUX_TIMESTAMP ?= 1
ifeq (1, $(AUX_LOCAL))
USEMODULE += sock_aux_local
endif
ifeq (1, $(AUX_LOCAL))
USEMODULE += sock_aux_timestamp
endif
USEMODULE += gnrc_sock_check_reuse
USEMODULE += sock_udp
USEMODULE += gnrc_ipv6

View File

@ -429,13 +429,16 @@ static void test_sock_udp_recv__aux(void)
static const ipv6_addr_t dst_addr = { .u8 = _TEST_ADDR_LOCAL };
static const sock_udp_ep_t local = { .family = AF_INET6,
.port = _TEST_PORT_LOCAL };
static const inject_aux_t inject_aux = { .timestamp = 1337 };
sock_udp_ep_t result;
sock_udp_aux_rx_t aux = { .flags = SOCK_AUX_GET_LOCAL };
sock_udp_aux_rx_t aux = {
.flags = SOCK_AUX_GET_LOCAL | SOCK_AUX_GET_TIMESTAMP
};
expect(0 == sock_udp_create(&_sock, &local, NULL, SOCK_FLAGS_REUSE_EP));
expect(_inject_packet(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
_TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
_TEST_NETIF));
expect(_inject_packet_aux(&src_addr, &dst_addr, _TEST_PORT_REMOTE,
_TEST_PORT_LOCAL, "ABCD", sizeof("ABCD"),
_TEST_NETIF, &inject_aux));
expect(sizeof("ABCD") == sock_udp_recv_aux(&_sock, _test_buffer,
sizeof(_test_buffer), 0,
&result, &aux));
@ -449,6 +452,12 @@ static void test_sock_udp_recv__aux(void)
expect(_TEST_PORT_LOCAL == aux.local.port);
#else
expect(aux.flags & SOCK_AUX_GET_LOCAL);
#endif
#if IS_USED(MODULE_SOCK_AUX_TIMESTAMP)
expect(!(aux.flags & SOCK_AUX_GET_TIMESTAMP));
expect(inject_aux.timestamp == aux.timestamp);
#else
expect(aux.flags & SOCK_AUX_GET_TIMESTAMP);
#endif
expect(_check_net());
}

View File

@ -47,9 +47,10 @@ static gnrc_pktsnip_t *_build_udp_packet(const ipv6_addr_t *src,
const ipv6_addr_t *dst,
uint16_t src_port, uint16_t dst_port,
void *data, size_t data_len,
uint16_t netif)
uint16_t netif,
const inject_aux_t *aux)
{
gnrc_pktsnip_t *netif_hdr, *ipv6, *udp;
gnrc_pktsnip_t *netif_hdr_snip, *ipv6, *udp;
udp_hdr_t *udp_hdr;
ipv6_hdr_t *ipv6_hdr;
uint16_t csum = 0;
@ -86,21 +87,25 @@ static gnrc_pktsnip_t *_build_udp_packet(const ipv6_addr_t *src,
udp_hdr->checksum = byteorder_htons(~csum);
}
udp = gnrc_pkt_append(udp, ipv6);
netif_hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
if (netif_hdr == NULL) {
netif_hdr_snip = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
if (netif_hdr_snip == NULL) {
return NULL;
}
((gnrc_netif_hdr_t *)netif_hdr->data)->if_pid = (kernel_pid_t)netif;
return gnrc_pkt_append(udp, netif_hdr);
gnrc_netif_hdr_t *netif_hdr = netif_hdr_snip->data;
netif_hdr->if_pid = (kernel_pid_t)netif;
if (aux) {
gnrc_netif_hdr_set_timestamp(netif_hdr, aux->timestamp);
}
return gnrc_pkt_append(udp, netif_hdr_snip);
}
bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
uint16_t src_port, uint16_t dst_port,
void *data, size_t data_len, uint16_t netif)
bool _inject_packet_aux(const ipv6_addr_t *src, const ipv6_addr_t *dst,
uint16_t src_port, uint16_t dst_port,
void *data, size_t data_len, uint16_t netif,
const inject_aux_t *aux)
{
gnrc_pktsnip_t *pkt = _build_udp_packet(src, dst, src_port, dst_port,
data, data_len, netif);
data, data_len, netif, aux);
if (pkt == NULL) {
return false;

View File

@ -39,6 +39,13 @@ void _net_init(void);
*/
void _prepare_send_checks(void);
/**
* @brief Auxiliary data to inject
*/
typedef struct {
uint64_t timestamp; /**< Timestamp of reception */
} inject_aux_t;
/**
* @brief Injects a received UDP packet into the stack
*
@ -53,9 +60,33 @@ void _prepare_send_checks(void);
* @return true, if packet was successfully injected
* @return false, if an error occurred during injection
*/
bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst,
uint16_t src_port, uint16_t dst_port,
void *data, size_t data_len, uint16_t netif);
bool _inject_packet_aux(const ipv6_addr_t *src, const ipv6_addr_t *dst,
uint16_t src_port, uint16_t dst_port,
void *data, size_t data_len, uint16_t netif,
const inject_aux_t *aux);
/**
* @brief Injects a received UDP packet into the stack
*
* @param[in] src The source address of the UDP packet
* @param[in] dst The destination address of the UDP packet
* @param[in] src_port The source port of the UDP packet
* @param[in] dst_port The destination port of the UDP packet
* @param[in] data The payload of the UDP packet
* @param[in] data_len The payload length of the UDP packet
* @param[in] netif The interface the packet came over
*
* @return true, if packet was successfully injected
* @return false, if an error occurred during injection
*/
static inline bool _inject_packet(const ipv6_addr_t *src,
const ipv6_addr_t *dst,
uint16_t src_port, uint16_t dst_port,
void *data, size_t data_len, uint16_t netif)
{
return _inject_packet_aux(src, dst, src_port, dst_port, data, data_len,
netif, NULL);
}
/**
* @brief Checks networking state (e.g. packet buffer state)