net/ethernet: add timestamp for socket packet

add timestamp for socket packet

Signed-off-by: gaohedong <gaohedong@xiaomi.com>
This commit is contained in:
gaohedong
2025-02-16 17:35:04 +08:00
committed by Xiang Xiao
parent 3949a87d36
commit 81f42cb2cf
6 changed files with 151 additions and 60 deletions
+4 -1
View File
@@ -212,7 +212,7 @@
#define SO_TYPE 15 /* Reports the socket type (get only).
* return: int
*/
#define SO_TIMESTAMP 16 /* Generates a timestamp for each incoming packet
#define SO_TIMESTAMP 16 /* Generates a timestamp in us for each incoming packet
* arg: integer value
*/
#define SO_BINDTODEVICE 17 /* Bind this socket to a specific network device.
@@ -220,6 +220,9 @@
#define SO_PEERCRED 18 /* Return the credentials of the peer process
* connected to this socket.
*/
#define SO_TIMESTAMPNS 20 /* Generates a timestamp in ns for each incoming packet
* arg: integer value
*/
/* The options are unsupported but included for compatibility
* and portability
+27
View File
@@ -36,6 +36,7 @@
#include "devif/devif.h"
#include "pkt/pkt.h"
#include "socket/socket.h"
/****************************************************************************
* Private Functions
@@ -68,6 +69,22 @@ static uint16_t pkt_datahandler(FAR struct net_driver_s *dev,
return 0;
}
#ifdef CONFIG_NET_TIMESTAMP
if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) ||
_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS))
{
ret = iob_trycopyin(iob, (FAR const uint8_t *)&dev->d_rxtime,
sizeof(struct timespec), 0, true);
if (ret != sizeof(struct timespec))
{
nerr("ERROR: Failed to write timestamp: %d\n", ret);
goto errout;
}
iob_reserve(iob, sizeof(struct timespec));
}
#endif
/* Clone an I/O buffer chain of the L2 data, use throttled IOB to avoid
* overconsumption.
* TODO: Optimize IOB clone after we support shared IOB.
@@ -139,6 +156,16 @@ static int pkt_in(FAR struct net_driver_s *dev)
{
uint16_t flags;
#if defined(CONFIG_NET_TIMESTAMP) && !defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP)
/* Get system as timestamp if no hardware timestamp */
if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) ||
_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS))
{
clock_gettime(CLOCK_REALTIME, &dev->d_rxtime);
}
#endif /* CONFIG_NET_TIMESTAMP */
/* Setup for the application callback */
dev->d_appdata = dev->d_buf;
+101 -43
View File
@@ -30,6 +30,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
@@ -54,18 +55,54 @@
struct pkt_recvfrom_s
{
FAR struct devif_callback_s *pr_cb; /* Reference to callback instance */
sem_t pr_sem; /* Semaphore signals recv completion */
size_t pr_buflen; /* Length of receive buffer */
FAR uint8_t *pr_buffer; /* Pointer to receive buffer */
ssize_t pr_recvlen; /* The received length */
int pr_result; /* Success:OK, failure:negated errno */
FAR struct pkt_conn_s *pr_conn; /* Connection associated with the socket */
FAR struct devif_callback_s *pr_cb; /* Reference to callback instance */
FAR struct msghdr *pr_msg; /* Receive info and buffer */
sem_t pr_sem; /* Semaphore signals recv completion */
ssize_t pr_recvlen; /* The received length */
int pr_result; /* Success:OK, failure:negated errno */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: pkt_store_cmsg_timestamp
*
* Description:
* Store the timestamp in the cmsg
*
* Input Parameters:
* pstate Recicve state information
* timestamp Timestamp information
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_NET_TIMESTAMP
static void pkt_store_cmsg_timestamp(FAR struct pkt_recvfrom_s *pstate,
FAR struct timespec *timestamp)
{
FAR struct msghdr *msg = pstate->pr_msg;
struct timeval tv;
if (_SO_GETOPT(pstate->pr_conn->sconn.s_options, SO_TIMESTAMPNS))
{
cmsg_append(msg, SOL_SOCKET, SO_TIMESTAMPNS, timestamp,
sizeof(struct timespec));
}
else
{
TIMESPEC_TO_TIMEVAL(&tv, timestamp);
cmsg_append(msg, SOL_SOCKET, SO_TIMESTAMP, &tv,
sizeof(struct timeval));
}
}
#endif
/****************************************************************************
* Name: pkt_add_recvlen
*
@@ -92,8 +129,6 @@ static inline void pkt_add_recvlen(FAR struct pkt_recvfrom_s *pstate,
}
pstate->pr_recvlen += recvlen;
pstate->pr_buffer += recvlen;
pstate->pr_buflen -= recvlen;
}
/****************************************************************************
@@ -120,20 +155,24 @@ static void pkt_recvfrom_newdata(FAR struct net_driver_s *dev,
unsigned int offset;
size_t recvlen;
if (dev->d_len > pstate->pr_buflen)
#ifdef CONFIG_NET_TIMESTAMP
/* Unpack stored timestamp if SO_TIMESTAMP socket option is enabled */
if (_SO_GETOPT(pstate->pr_conn->sconn.s_options, SO_TIMESTAMP) ||
_SO_GETOPT(pstate->pr_conn->sconn.s_options, SO_TIMESTAMPNS))
{
recvlen = pstate->pr_buflen;
}
else
{
recvlen = dev->d_len;
pkt_store_cmsg_timestamp(pstate, &dev->d_rxtime);
}
#endif
recvlen = MIN(pstate->pr_msg->msg_iov->iov_len, dev->d_len);
/* Copy the new packet data into the user buffer */
offset = (dev->d_appdata - dev->d_iob->io_data) - dev->d_iob->io_offset;
recvlen = iob_copyout(pstate->pr_buffer, dev->d_iob, recvlen, offset);
recvlen = iob_copyout(pstate->pr_msg->msg_iov->iov_base,
dev->d_iob, recvlen, offset);
ninfo("Received %d bytes (of %d)\n", (int)recvlen, (int)dev->d_len);
@@ -228,9 +267,8 @@ static uint16_t pkt_recvfrom_eventhandler(FAR struct net_driver_s *dev,
* Initialize the state structure
*
* Input Parameters:
* psock Pointer to the socket structure for the socket
* buf Buffer to receive data
* len Length of buffer
* conn The PKT connection of interest
* msg Receive info and buffer for receive data
* pstate A pointer to the state structure to be initialized
*
* Returned Value:
@@ -240,9 +278,8 @@ static uint16_t pkt_recvfrom_eventhandler(FAR struct net_driver_s *dev,
*
****************************************************************************/
static void pkt_recvfrom_initialize(FAR struct socket *psock, FAR void *buf,
size_t len, FAR struct sockaddr *infrom,
FAR socklen_t *fromlen,
static void pkt_recvfrom_initialize(FAR struct pkt_conn_s *conn,
FAR struct msghdr *msg,
FAR struct pkt_recvfrom_s *pstate)
{
/* Initialize the state structure. */
@@ -250,8 +287,8 @@ static void pkt_recvfrom_initialize(FAR struct socket *psock, FAR void *buf,
memset(pstate, 0, sizeof(struct pkt_recvfrom_s));
nxsem_init(&pstate->pr_sem, 0, 0); /* Doesn't really fail */
pstate->pr_buflen = len;
pstate->pr_buffer = buf;
pstate->pr_conn = conn;
pstate->pr_msg = msg;
}
/* The only un-initialization that has to be performed is destroying the
@@ -313,35 +350,58 @@ static ssize_t pkt_recvfrom_result(int result,
* Copy the buffered read-ahead data to the user buffer.
*
* Input Parameters:
* conn - PKT socket connection structure containing the read-
* ahead data.
* buf target buffer.
* pstate The state structure of the recv operation
*
* Returned Value:
* Number of bytes copied to the user buffer
* None
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static inline ssize_t pkt_readahead(FAR struct pkt_conn_s *conn,
FAR void *buf, size_t buflen)
static inline void pkt_readahead(FAR struct pkt_recvfrom_s *pstate)
{
FAR struct pkt_conn_s *conn = pstate->pr_conn;
FAR struct iob_s *iob;
ssize_t ret = -ENODATA;
int recvlen;
/* Check there is any packets already buffered in a read-ahead buffer. */
pstate->pr_recvlen = -ENODATA;
if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
{
DEBUGASSERT(iob->io_pktlen > 0);
#ifdef CONFIG_NET_TIMESTAMP
/* Unpack stored timestamp if SO_TIMESTAMP/SO_TIMESTAMPNS socket option
* is enabled
*/
if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) ||
_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS))
{
struct timespec ts;
recvlen = iob_copyout((FAR uint8_t *)&ts, iob,
sizeof(struct timespec),
-sizeof(struct timespec));
DEBUGASSERT(recvlen == sizeof(struct timespec));
pkt_store_cmsg_timestamp(pstate, &ts);
}
#endif
/* Copy to user */
ret = iob_copyout(buf, iob, buflen, 0);
recvlen = iob_copyout(pstate->pr_msg->msg_iov->iov_base, iob,
pstate->pr_msg->msg_iov->iov_len, 0);
ninfo("Received %zd bytes (of %u)\n", ret, iob->io_pktlen);
/* Update the accumulated size of the data read */
pstate->pr_recvlen = recvlen;
ninfo("Received %d bytes (of %u)\n", recvlen, iob->io_pktlen);
/* Remove the I/O buffer chain from the head of the read-ahead
* buffer queue.
@@ -353,8 +413,6 @@ static inline ssize_t pkt_readahead(FAR struct pkt_conn_s *conn,
iob_free_chain(iob);
}
return ret;
}
/****************************************************************************
@@ -392,14 +450,12 @@ static inline ssize_t pkt_readahead(FAR struct pkt_conn_s *conn,
ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
int flags)
{
FAR void *buf = msg->msg_iov->iov_base;
size_t len = msg->msg_iov->iov_len;
FAR struct sockaddr *from = msg->msg_name;
FAR socklen_t *fromlen = &msg->msg_namelen;
FAR struct pkt_conn_s *conn = psock->s_conn;
FAR struct net_driver_s *dev;
struct pkt_recvfrom_s state;
ssize_t ret;
ssize_t ret = 0;
/* If a 'from' address has been provided, verify that it is large
* enough to hold this address family.
@@ -427,6 +483,8 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
* locked because we don't want anything to happen until we are ready.
*/
pkt_recvfrom_initialize(conn, msg, &state);
net_lock();
/* Check if there is buffered read-ahead data for this socket. We may have
@@ -435,7 +493,8 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
if (!IOB_QEMPTY(&conn->readahead))
{
ret = pkt_readahead(conn, buf, len);
pkt_readahead(&state);
ret = pkt_recvfrom_result(ret, &state);
}
else if (_SS_ISNONBLOCK(conn->sconn.s_flags) ||
(flags & MSG_DONTWAIT) != 0)
@@ -446,8 +505,6 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
}
else
{
pkt_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
/* Get the device driver that will service this transfer */
dev = pkt_find_device(conn);
@@ -496,12 +553,13 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
{
ret = -EBUSY;
}
errout_with_state:
pkt_recvfrom_uninitialize(&state);
}
net_unlock();
errout_with_state:
pkt_recvfrom_uninitialize(&state);
return ret;
}
+9 -8
View File
@@ -140,15 +140,16 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
* is outside of the scope of getsockopt.
*/
case SO_BROADCAST: /* Permits sending of broadcast messages */
case SO_DEBUG: /* Enables recording of debugging information */
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
case SO_OOBINLINE: /* Leaves received out-of-band data inline */
case SO_REUSEADDR: /* Allow reuse of local addresses */
case SO_BROADCAST: /* Permits sending of broadcast messages */
case SO_DEBUG: /* Enables recording of debugging information */
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
case SO_OOBINLINE: /* Leaves received out-of-band data inline */
case SO_REUSEADDR: /* Allow reuse of local addresses */
#ifdef CONFIG_NET_TIMESTAMP
case SO_TIMESTAMP: /* Generates a timestamp for each incoming packet */
case SO_TIMESTAMP: /* Generates a timestamp in us for each incoming packet */
case SO_TIMESTAMPNS: /* Generates a timestamp in ns for each incoming packet */
#endif
{
sockopt_t optionset;
+9 -8
View File
@@ -130,15 +130,16 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
return OK;
}
case SO_BROADCAST: /* Permits sending of broadcast messages */
case SO_DEBUG: /* Enables recording of debugging information */
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
case SO_OOBINLINE: /* Leaves received out-of-band data inline */
case SO_REUSEADDR: /* Allow reuse of local addresses */
case SO_BROADCAST: /* Permits sending of broadcast messages */
case SO_DEBUG: /* Enables recording of debugging information */
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
case SO_OOBINLINE: /* Leaves received out-of-band data inline */
case SO_REUSEADDR: /* Allow reuse of local addresses */
#ifdef CONFIG_NET_TIMESTAMP
case SO_TIMESTAMP: /* Generates a timestamp for each incoming packet */
case SO_TIMESTAMP: /* Generates a timestamp in us for each incoming packet */
case SO_TIMESTAMPNS: /* Generates a timestamp in ns for each incoming packet */
#endif
{
int setting;
+1
View File
@@ -65,6 +65,7 @@
#define _SO_SNDTIMEO _SO_BIT(SO_SNDTIMEO)
#define _SO_TYPE _SO_BIT(SO_TYPE)
#define _SO_TIMESTAMP _SO_BIT(SO_TIMESTAMP)
#define _SO_TIMESTAMPNS _SO_BIT(SO_TIMESTAMPNS)
#define _SO_BINDTODEVICE _SO_BIT(SO_BINDTODEVICE)
/* This is the largest option value. REVISIT: belongs in sys/socket.h */