net/pkt: Add readahead queue for pkt, call input for tx on sim

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2023-02-07 15:06:03 +08:00 committed by Petro Karashchenko
parent cd1decf4a5
commit 0e018308a3
8 changed files with 223 additions and 60 deletions

View File

@ -110,6 +110,12 @@ static void netdriver_send(struct net_driver_s *dev)
UNUSED(devidx);
#ifdef CONFIG_NET_PKT
/* When packet sockets are enabled, feed the tx frame into it */
pkt_input(dev);
#endif
sim_netdev_send(devidx, buf, dev->d_len);
}

View File

@ -208,17 +208,25 @@ static int devif_poll_pkt_connections(FAR struct net_driver_s *dev,
while (!bstop && (pkt_conn = pkt_nextconn(pkt_conn)))
{
/* Perform the packet TX poll */
/* Skip packet connections that are bound to other polling devices */
pkt_poll(dev, pkt_conn);
if (dev->d_ifindex == pkt_conn->ifindex)
{
/* Perform the packet TX poll */
/* Perform any necessary conversions on outgoing packets */
pkt_poll(dev, pkt_conn);
devif_packet_conversion(dev, DEVIF_PKT);
/* Perform any necessary conversions on outgoing packets */
/* Call back into the driver */
devif_packet_conversion(dev, DEVIF_PKT);
bstop = callback(dev);
/* Call back into the driver */
if (dev->d_len > 0)
{
bstop = callback(dev);
}
}
}
return bstop;

View File

@ -64,6 +64,16 @@ struct pkt_conn_s
uint8_t ifindex;
uint16_t proto;
uint8_t crefs; /* Reference counts on this instance */
/* Read-ahead buffering.
*
* readahead - A singly linked list of type struct iob_qentry_s
* where the PKT read-ahead data is retained.
*
* TODO: Maybe support PACKET_MMAP for further optimize.
*/
struct iob_queue_s readahead; /* Read-ahead buffering */
};
/****************************************************************************
@ -231,7 +241,7 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
* Select the network driver to use with the PKT transaction.
*
* Input Parameters:
* conn - PKT connection structure (not currently used).
* conn - PKT connection structure.
*
* Returned Value:
* A pointer to the network driver to use.

View File

@ -210,7 +210,8 @@ FAR struct pkt_conn_s *pkt_active(FAR struct eth_hdr_s *buf)
{
/* FIXME lmac in conn should have been set by pkt_bind() */
if (eth_addr_cmp(buf->dest, conn->lmac))
if (eth_addr_cmp(buf->dest, conn->lmac) ||
eth_addr_cmp(buf->src, conn->lmac))
{
/* Matching connection found.. return a reference to it */

View File

@ -41,7 +41,7 @@
* Select the network driver to use with the PKT transaction.
*
* Input Parameters:
* conn - PKT connection structure (not currently used).
* conn - PKT connection structure.
*
* Returned Value:
* A pointer to the network driver to use.
@ -50,9 +50,7 @@
FAR struct net_driver_s *pkt_find_device(FAR struct pkt_conn_s *conn)
{
/* REVISIT: This is bogus. A better network device lookup is needed. */
return netdev_findbyname("eth0");
return netdev_findbyindex(conn->ifindex);
}
#endif /* CONFIG_NET && CONFIG_NET_PKT */

View File

@ -29,6 +29,7 @@
#include <errno.h>
#include <debug.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/pkt.h>
@ -39,6 +40,66 @@
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: pkt_datahandler
*
* Description:
* Handle packet that are not accepted by the application.
*
* Input Parameters:
* dev - Device instance only the input packet in d_buf, length = d_len;
* conn - A pointer to the PKT connection structure
*
* Returned Value:
* The number of bytes actually buffered is returned. This will be either
* zero or equal to buflen; partial packets are not buffered.
*
****************************************************************************/
static uint16_t pkt_datahandler(FAR struct net_driver_s *dev,
FAR struct pkt_conn_s *conn)
{
FAR struct iob_s *iob = iob_tryalloc(true);
int ret;
if (iob == NULL)
{
return 0;
}
/* 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.
*/
ret = iob_clone_partial(dev->d_iob, dev->d_len, -NET_LL_HDRLEN(dev),
iob, 0, true, false);
if (ret < 0)
{
nerr("ERROR: Failed to clone the I/O buffer chain: %d\n", ret);
goto errout;
}
/* Add the new I/O buffer chain to the tail of the read-ahead queue (again
* without waiting).
*/
if ((ret = iob_tryadd_queue(iob, &conn->readahead)) < 0)
{
nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
goto errout;
}
else
{
ninfo("Buffered %d bytes\n", dev->d_len);
return dev->d_len;
}
errout:
iob_free_chain(iob);
return 0;
}
/****************************************************************************
* Name: pkt_in
*
@ -93,14 +154,17 @@ static int pkt_in(FAR struct net_driver_s *dev)
if ((flags & PKT_NEWDATA) != 0)
{
/* No.. the packet was not processed now. Return -EAGAIN so
* that the driver may retry again later. We still need to
* set d_len to zero so that the driver is aware that there
* is nothing to be sent.
*/
/* Add the PKT to the socket read-ahead buffer. */
nwarn("WARNING: Packet not processed\n");
ret = -EAGAIN;
if (pkt_datahandler(dev, conn) == 0)
{
/* No.. the packet was not processed now. Return -EAGAIN so
* that the driver may retry again later.
*/
nwarn("WARNING: Packet not processed\n");
ret = -EAGAIN;
}
}
}
else

View File

@ -304,6 +304,57 @@ static ssize_t pkt_recvfrom_result(int result,
return pstate->pr_recvlen;
}
/****************************************************************************
* Name: pkt_readahead
*
* Description:
* 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.
*
* Returned Value:
* Number of bytes copied to the user buffer
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static inline ssize_t pkt_readahead(FAR struct pkt_conn_s *conn,
FAR void *buf, size_t buflen)
{
FAR struct iob_s *iob;
ssize_t ret = -ENODATA;
/* Check there is any packets already buffered in a read-ahead buffer. */
if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
{
DEBUGASSERT(iob->io_pktlen > 0);
/* Copy to user */
ret = iob_copyout(buf, iob, buflen, 0);
ninfo("Received %zd bytes (of %u)\n", ret, iob->io_pktlen);
/* Remove the I/O buffer chain from the head of the read-ahead
* buffer queue.
*/
iob_remove_queue(&conn->readahead);
/* And free the I/O buffer chain */
iob_free_chain(iob);
}
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -370,59 +421,80 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
*/
net_lock();
pkt_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
/* Get the device driver that will service this transfer */
dev = pkt_find_device(conn);
if (dev == NULL)
{
ret = -ENODEV;
goto errout_with_state;
}
/* TODO pkt_recvfrom_initialize() expects from to be of type sockaddr_in,
* but in our case is sockaddr_ll
/* Check if there is buffered read-ahead data for this socket. We may have
* already received the response to previous command.
*/
#if 0
ret = pkt_connect(conn, NULL);
if (ret < 0)
if (!IOB_QEMPTY(&conn->readahead))
{
goto errout_with_state;
ret = pkt_readahead(conn, buf, len);
}
#endif
/* Set up the callback in the connection */
state.pr_cb = pkt_callback_alloc(dev, conn);
if (state.pr_cb)
else if (_SS_ISNONBLOCK(conn->sconn.s_flags) ||
(flags & MSG_DONTWAIT) != 0)
{
state.pr_cb->flags = (PKT_NEWDATA | PKT_POLL);
state.pr_cb->priv = (FAR void *)&state;
state.pr_cb->event = pkt_recvfrom_eventhandler;
/* Handle non-blocking PKT sockets */
/* Wait for either the receive to complete or for an error/timeout to
* occur. NOTES: (1) net_sem_wait will also terminate if a signal
* is received, (2) the network is locked! It will be un-locked while
* the task sleeps and automatically re-locked when the task restarts.
*/
ret = net_sem_wait(&state.pr_sem);
/* Make sure that no further events are processed */
pkt_callback_free(dev, conn, state.pr_cb);
ret = pkt_recvfrom_result(ret, &state);
ret = -EAGAIN;
}
else
{
ret = -EBUSY;
}
pkt_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
/* Get the device driver that will service this transfer */
dev = pkt_find_device(conn);
if (dev == NULL)
{
ret = -ENODEV;
goto errout_with_state;
}
/* TODO pkt_recvfrom_initialize() expects from to be of type
* sockaddr_in, but in our case is sockaddr_ll
*/
#if 0
ret = pkt_connect(conn, NULL);
if (ret < 0)
{
goto errout_with_state;
}
#endif
/* Set up the callback in the connection */
state.pr_cb = pkt_callback_alloc(dev, conn);
if (state.pr_cb)
{
state.pr_cb->flags = (PKT_NEWDATA | PKT_POLL);
state.pr_cb->priv = (FAR void *)&state;
state.pr_cb->event = pkt_recvfrom_eventhandler;
/* Wait for either the receive to complete or for an error/timeout
* to occur. NOTES: (1) net_sem_wait will also terminate if a
* signal is received, (2) the network is locked! It will be
* un-locked while the task sleeps and automatically re-locked when
* the task restarts.
*/
ret = net_sem_wait(&state.pr_sem);
/* Make sure that no further events are processed */
pkt_callback_free(dev, conn, state.pr_cb);
ret = pkt_recvfrom_result(ret, &state);
}
else
{
ret = -EBUSY;
}
errout_with_state:
pkt_recvfrom_uninitialize(&state);
}
net_unlock();
pkt_recvfrom_uninitialize(&state);
return ret;
}

View File

@ -305,7 +305,11 @@ static int pkt_close(FAR struct socket *psock)
if (conn->crefs <= 1)
{
/* Yes... free the connection structure */
/* Yes... free any read-ahead data */
iob_free_queue(&conn->readahead);
/* Then free the connection structure */
conn->crefs = 0; /* No more references on the connection */
pkt_free(psock->s_conn); /* Free network resources */