mirror of
https://github.com/apache/nuttx.git
synced 2026-10-03 04:07:55 +00:00
arch/sim: support SO_TIMESTAMPING TX in sim netdriver
Add TX timestamp loopback support to the simulator network driver. When a packet tagged with io_conn (SO_TIMESTAMPING TX) is sent, the driver clones the packet, generates a software timestamp, and queues it for loopback through the RX path. The protocol layer (UDP/PKT) then delivers the timestamp via MSG_ERRQUEUE. - Add tstampq IOB queue to sim_netdev_s for loopback packets. - In netdriver_send(), clone timestamped packets with realtime clock and notify RX ready. - In netdriver_recv(), return loopback packets before reading from the tap device. Signed-off-by: wenquan1 <wenquan1@xiaomi.com>
This commit is contained in:
parent
935f830e16
commit
95f8c54836
1 changed files with 69 additions and 3 deletions
|
|
@ -63,6 +63,7 @@
|
|||
|
||||
#include <nuttx/debug.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <nuttx/compiler.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
|
|
@ -109,6 +110,9 @@ struct sim_netdev_s
|
|||
#endif
|
||||
uint8_t buf[SIM_NETDEV_BUFSIZE]; /* Used when packet buffer is fragmented */
|
||||
struct work_s work;
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
netpkt_queue_t tstampq; /* TX timestamp loopback queue */
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -163,6 +167,25 @@ static int netdriver_send(struct netdev_lowerhalf_s *dev, netpkt_t *pkt)
|
|||
sim_netdev_send(DEVIDX(dev), netpkt_getdata(dev, pkt), len);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
/* If the packet is tagged for TX timestamping, generate a
|
||||
* software timestamp and loop it back through the RX path
|
||||
* so the protocol layer can deliver it via MSG_ERRQUEUE.
|
||||
* Reuse the original pkt directly to avoid clone overhead.
|
||||
*/
|
||||
|
||||
if (pkt->io_conn != NULL)
|
||||
{
|
||||
FAR struct sim_netdev_s *priv = (FAR struct sim_netdev_s *)dev;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &pkt->io_time);
|
||||
iob_add_queue(pkt, &priv->tstampq);
|
||||
atomic_add(&dev->quota_ptr[NETPKT_TX], 1);
|
||||
netdev_lower_rxready(dev);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
netpkt_free(dev, pkt, NETPKT_TX);
|
||||
return OK;
|
||||
}
|
||||
|
|
@ -172,6 +195,26 @@ static netpkt_t *netdriver_recv(struct netdev_lowerhalf_s *dev)
|
|||
netpkt_t *pkt = NULL;
|
||||
unsigned int len;
|
||||
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
/* Return any TX timestamp loopback packets first.
|
||||
* Fast-path: skip locking when the queue is empty.
|
||||
*/
|
||||
|
||||
FAR struct sim_netdev_s *priv = (FAR struct sim_netdev_s *)dev;
|
||||
|
||||
if (!IOB_QEMPTY(&priv->tstampq))
|
||||
{
|
||||
netdev_lock(&dev->netdev);
|
||||
pkt = iob_remove_queue(&priv->tstampq);
|
||||
netdev_unlock(&dev->netdev);
|
||||
if (pkt != NULL)
|
||||
{
|
||||
atomic_sub(&dev->quota_ptr[NETPKT_RX], 1);
|
||||
return pkt;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sim_netdev_avail(DEVIDX(dev)))
|
||||
{
|
||||
pkt = netpkt_alloc(dev, NETPKT_RX);
|
||||
|
|
@ -237,8 +280,23 @@ static int netdriver_ifup(struct netdev_lowerhalf_s *dev)
|
|||
|
||||
static int netdriver_ifdown(struct netdev_lowerhalf_s *dev)
|
||||
{
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
/* Drain any pending TX timestamp loopback packets.
|
||||
* Detach the entire queue under lock, then free outside.
|
||||
*/
|
||||
|
||||
FAR struct sim_netdev_s *priv = (FAR struct sim_netdev_s *)dev;
|
||||
FAR netpkt_t *pkt;
|
||||
|
||||
while ((pkt = iob_remove_queue(&priv->tstampq)) != NULL)
|
||||
{
|
||||
netpkt_free(dev, pkt, NETPKT_TX);
|
||||
}
|
||||
#endif
|
||||
|
||||
netdev_lower_carrier_off(dev);
|
||||
sim_netdev_ifdown(DEVIDX(dev));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -273,7 +331,11 @@ static void sim_netdev_work(void *arg)
|
|||
struct sim_netdev_s *priv = (struct sim_netdev_s *)arg;
|
||||
struct netdev_lowerhalf_s *dev = (struct netdev_lowerhalf_s *)&priv->dev;
|
||||
|
||||
if (sim_netdev_avail(DEVIDX(dev)))
|
||||
if (sim_netdev_avail(DEVIDX(dev))
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
|| !IOB_QEMPTY(&priv->tstampq)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
netdev_lower_rxready(dev);
|
||||
}
|
||||
|
|
@ -347,7 +409,7 @@ void sim_netdriver_setmacaddr(int devidx, unsigned char *macaddr)
|
|||
void sim_netdriver_setmtu(int devidx, int mtu)
|
||||
{
|
||||
IDXDEV(devidx)->netdev.d_pktsize = MIN(SIM_NETDEV_BUFSIZE,
|
||||
mtu + ETH_HDRLEN);
|
||||
mtu + ETH_HDRLEN);
|
||||
}
|
||||
|
||||
void sim_netdriver_loop(void)
|
||||
|
|
@ -355,7 +417,11 @@ void sim_netdriver_loop(void)
|
|||
int devidx;
|
||||
for (devidx = 0; devidx < CONFIG_SIM_NETDEV_NUMBER; devidx++)
|
||||
{
|
||||
if (sim_netdev_avail(devidx))
|
||||
if (sim_netdev_avail(devidx)
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
|| !IOB_QEMPTY(&g_sim_dev[devidx].tstampq)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
netdev_lower_rxready(IDXDEV(devidx));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue