Skip to content

Commit

Permalink
net: Add support for TXTIME socket option
Browse files Browse the repository at this point in the history
The SO_TXTIME socket option can be used by the application to
tell the network device driver the exact moment when the
network packet should be sent.

This feature is also implemented in Linux.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
  • Loading branch information
jukkar committed Jul 24, 2019
1 parent 4a8154f commit 0435dce
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 3 deletions.
4 changes: 4 additions & 0 deletions include/net/net_context.h
Expand Up @@ -286,6 +286,9 @@ struct net_context {
#endif
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP)
bool timestamp;
#endif
#if defined(CONFIG_NET_CONTEXT_TXTIME)
bool txtime;
#endif
} options;

Expand Down Expand Up @@ -947,6 +950,7 @@ int net_context_update_recv_wnd(struct net_context *context,
enum net_context_option {
NET_OPT_PRIORITY = 1,
NET_OPT_TIMESTAMP = 2,
NET_OPT_TXTIME = 3,
};

/**
Expand Down
40 changes: 37 additions & 3 deletions include/net/net_pkt.h
Expand Up @@ -95,10 +95,19 @@ struct net_pkt {
struct net_if *orig_iface; /* Original network interface */
#endif

#if defined(CONFIG_NET_PKT_TIMESTAMP) || defined(CONFIG_NET_PKT_TXTIME)
union {
#if defined(CONFIG_NET_PKT_TIMESTAMP)
/** Timestamp if available. */
struct net_ptp_time timestamp;
#endif
/** Timestamp if available. */
struct net_ptp_time timestamp;
#endif /* CONFIG_NET_PKT_TIMESTAMP */
#if defined(CONFIG_NET_PKT_TXTIME)
/** Network packet TX time in the future (in nanoseconds) */
u64_t txtime;
#endif /* CONFIG_NET_PKT_TXTIME */
};
#endif /* CONFIG_NET_PKT_TIMESTAMP || CONFIG_NET_PKT_TXTIME */

/** Reference counter */
atomic_t atomic_ref;

Expand Down Expand Up @@ -699,6 +708,31 @@ static inline void net_pkt_set_timestamp(struct net_pkt *pkt,
}
#endif /* CONFIG_NET_PKT_TIMESTAMP */

#if defined(CONFIG_NET_PKT_TXTIME)
static inline u64_t net_pkt_txtime(struct net_pkt *pkt)
{
return pkt->txtime;
}

static inline void net_pkt_set_txtime(struct net_pkt *pkt, u64_t txtime)
{
pkt->txtime = txtime;
}
#else
static inline u64_t net_pkt_txtime(struct net_pkt *pkt)
{
ARG_UNUSED(pkt);

return 0;
}

static inline void net_pkt_set_txtime(struct net_pkt *pkt, u64_t txtime)
{
ARG_UNUSED(pkt);
ARG_UNUSED(txtime);
}
#endif /* CONFIG_NET_PKT_TXTIME */

static inline size_t net_pkt_get_len(struct net_pkt *pkt)
{
return net_buf_frags_len(pkt->frags);
Expand Down
4 changes: 4 additions & 0 deletions include/net/socket.h
Expand Up @@ -767,6 +767,10 @@ static inline char *inet_ntop(sa_family_t family, const void *src, char *dst,
/** sockopt: Socket priority */
#define SO_PRIORITY 12

/** sockopt: Socket TX time (when the data should be sent) */
#define SO_TXTIME 61
#define SCM_TXTIME SO_TXTIME

/** @cond INTERNAL_HIDDEN */
/**
* @brief Registration information for a given BSD socket family.
Expand Down
15 changes: 15 additions & 0 deletions subsys/net/ip/Kconfig
Expand Up @@ -376,6 +376,14 @@ config NET_CONTEXT_TIMESTAMP
It is possible to timestamp outgoing packets and get information
about these timestamps.

config NET_CONTEXT_TXTIME
bool "Add TXTIME support to net_context"
select NET_PKT_TXTIME
help
It is possible to add information when the outgoing network packet
should be sent. The TX time information should be placed into
ancillary data field in sendmsg call.

config NET_TEST
bool "Network Testing"
help
Expand Down Expand Up @@ -565,6 +573,13 @@ config NET_PKT_TIMESTAMP_STACK_SIZE
thread waits for timestamped TX frames and calls registered
callbacks.

config NET_PKT_TXTIME
bool "Enable network packet TX time support"
help
Enable network packet TX time support. This is needed for
when the application wants to set the exact time when the network
packet should be sent.

config NET_PROMISCUOUS_MODE
bool "Enable promiscuous mode support [EXPERIMENTAL]"
select NET_MGMT
Expand Down
69 changes: 69 additions & 0 deletions subsys/net/ip/net_context.c
Expand Up @@ -20,6 +20,7 @@ LOG_MODULE_REGISTER(net_ctx, CONFIG_NET_CONTEXT_LOG_LEVEL);

#include <net/net_pkt.h>
#include <net/net_ip.h>
#include <net/socket.h>
#include <net/net_context.h>
#include <net/net_offload.h>
#include <net/ethernet.h>
Expand Down Expand Up @@ -1131,6 +1132,22 @@ int net_context_get_timestamp(struct net_context *context,
}
#endif /* CONFIG_NET_CONTEXT_TIMESTAMP */

static int get_context_txtime(struct net_context *context,
void *value, size_t *len)
{
#if defined(CONFIG_NET_CONTEXT_TXTIME)
*((bool *)value) = context->options.txtime;

if (len) {
*len = sizeof(bool);
}

return 0;
#else
return -ENOTSUP;
#endif
}

/* If buf is not NULL, then use it. Otherwise read the data to be written
* to net_pkt from msghdr.
*/
Expand Down Expand Up @@ -1265,6 +1282,22 @@ static struct net_pkt *context_alloc_pkt(struct net_context *context,
return pkt;
}

static void set_pkt_txtime(struct net_pkt *pkt, const struct msghdr *msghdr)
{
struct cmsghdr *cmsg;

for (cmsg = CMSG_FIRSTHDR(msghdr); cmsg != NULL;
cmsg = CMSG_NXTHDR(msghdr, cmsg)) {
if (cmsg->cmsg_len == CMSG_LEN(sizeof(u64_t)) &&
cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_TXTIME) {
u64_t txtime = *(u64_t *)CMSG_DATA(cmsg);

net_pkt_set_txtime(pkt, txtime);
break;
}
}
}

static int context_sendto(struct net_context *context,
const void *buf,
Expand Down Expand Up @@ -1457,6 +1490,20 @@ static int context_sendto(struct net_context *context,
}
}

/* If there is ancillary data in msghdr, then we need to add that
* to net_pkt as there is no other way to store it.
*/
if (msghdr && msghdr->msg_control && msghdr->msg_controllen) {
if (IS_ENABLED(CONFIG_NET_CONTEXT_TXTIME)) {
bool is_txtime;

get_context_txtime(context, &is_txtime, NULL);
if (is_txtime) {
set_pkt_txtime(pkt, msghdr);
}
}
}

if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
net_if_is_ip_offloaded(net_context_get_iface(context))) {
ret = context_write_data(pkt, buf, len, msghdr);
Expand Down Expand Up @@ -1927,6 +1974,22 @@ static int set_context_timestamp(struct net_context *context,
#endif
}

static int set_context_txtime(struct net_context *context,
const void *value, size_t len)
{
#if defined(CONFIG_NET_CONTEXT_TXTIME)
if (len > sizeof(bool)) {
return -EINVAL;
}

context->options.txtime = *((bool *)value);

return 0;
#else
return -ENOTSUP;
#endif
}

int net_context_set_option(struct net_context *context,
enum net_context_option option,
const void *value, size_t len)
Expand All @@ -1948,6 +2011,9 @@ int net_context_set_option(struct net_context *context,
case NET_OPT_TIMESTAMP:
ret = set_context_timestamp(context, value, len);
break;
case NET_OPT_TXTIME:
ret = set_context_txtime(context, value, len);
break;
}

k_mutex_unlock(&context->lock);
Expand Down Expand Up @@ -1976,6 +2042,9 @@ int net_context_get_option(struct net_context *context,
case NET_OPT_TIMESTAMP:
ret = get_context_timepstamp(context, value, len);
break;
case NET_OPT_TXTIME:
ret = get_context_txtime(context, value, len);
break;
}

k_mutex_unlock(&context->lock);
Expand Down
37 changes: 37 additions & 0 deletions subsys/net/lib/sockets/sockets.c
Expand Up @@ -1130,6 +1130,28 @@ Z_SYSCALL_HANDLER(zsock_inet_pton, family, src, dst)
int zsock_getsockopt_ctx(struct net_context *ctx, int level, int optname,
void *optval, socklen_t *optlen)
{
int ret;

switch (level) {
case SOL_SOCKET:
switch (optname) {
case SO_TXTIME:
if (IS_ENABLED(CONFIG_NET_CONTEXT_TXTIME)) {
ret = net_context_get_option(ctx,
NET_OPT_TXTIME,
optval, optlen);
if (ret < 0) {
errno = -ret;
return -1;
}

return 0;
}
}

break;
}

errno = ENOPROTOOPT;
return -1;
}
Expand Down Expand Up @@ -1212,6 +1234,21 @@ int zsock_setsockopt_ctx(struct net_context *ctx, int level, int optname,
return 0;
}

break;

case SO_TXTIME:
if (IS_ENABLED(CONFIG_NET_CONTEXT_TXTIME)) {
ret = net_context_set_option(ctx,
NET_OPT_TXTIME,
optval, optlen);
if (ret < 0) {
errno = -ret;
return -1;
}

return 0;
}

break;
}

Expand Down

0 comments on commit 0435dce

Please sign in to comment.