Skip to content
Permalink
Browse files

net: Add support for TXTIME socket option

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 Jun 27, 2019
1 parent 4a8154f commit 0435dce69798c1ba2c0c7b88e42d52a56203e048
@@ -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;

@@ -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,
};

/**
@@ -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;

@@ -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);
@@ -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.
@@ -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
@@ -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
@@ -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>
@@ -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.
*/
@@ -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,
@@ -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);
@@ -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)
@@ -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);
@@ -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);
@@ -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;
}
@@ -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;
}

0 comments on commit 0435dce

Please sign in to comment.
You can’t perform that action at this time.