From 0e018308a389fd16f65f7ded4a6391c159ba4643 Mon Sep 17 00:00:00 2001 From: Zhe Weng Date: Tue, 7 Feb 2023 15:06:03 +0800 Subject: [PATCH] net/pkt: Add readahead queue for pkt, call input for tx on sim Signed-off-by: Zhe Weng --- arch/sim/src/sim/sim_netdriver.c | 6 ++ net/devif/devif_poll.c | 20 ++-- net/pkt/pkt.h | 12 ++- net/pkt/pkt_conn.c | 3 +- net/pkt/pkt_finddev.c | 6 +- net/pkt/pkt_input.c | 78 ++++++++++++++-- net/pkt/pkt_recvmsg.c | 152 +++++++++++++++++++++++-------- net/pkt/pkt_sockif.c | 6 +- 8 files changed, 223 insertions(+), 60 deletions(-) diff --git a/arch/sim/src/sim/sim_netdriver.c b/arch/sim/src/sim/sim_netdriver.c index 97d2a91fe6..6343203a8f 100644 --- a/arch/sim/src/sim/sim_netdriver.c +++ b/arch/sim/src/sim/sim_netdriver.c @@ -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); } diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c index 5cf78a6949..fd77dc3d96 100644 --- a/net/devif/devif_poll.c +++ b/net/devif/devif_poll.c @@ -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; diff --git a/net/pkt/pkt.h b/net/pkt/pkt.h index c2091837f4..e74f8fd95c 100644 --- a/net/pkt/pkt.h +++ b/net/pkt/pkt.h @@ -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. diff --git a/net/pkt/pkt_conn.c b/net/pkt/pkt_conn.c index 6693d61571..b74f4a54cb 100644 --- a/net/pkt/pkt_conn.c +++ b/net/pkt/pkt_conn.c @@ -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 */ diff --git a/net/pkt/pkt_finddev.c b/net/pkt/pkt_finddev.c index fb61de2d01..9ac3eeec24 100644 --- a/net/pkt/pkt_finddev.c +++ b/net/pkt/pkt_finddev.c @@ -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 */ diff --git a/net/pkt/pkt_input.c b/net/pkt/pkt_input.c index b9a5124aa3..4e8fed8162 100644 --- a/net/pkt/pkt_input.c +++ b/net/pkt/pkt_input.c @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -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 diff --git a/net/pkt/pkt_recvmsg.c b/net/pkt/pkt_recvmsg.c index 69edefd121..605d1cbfbd 100644 --- a/net/pkt/pkt_recvmsg.c +++ b/net/pkt/pkt_recvmsg.c @@ -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; } diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c index 3271669e08..47a073091a 100644 --- a/net/pkt/pkt_sockif.c +++ b/net/pkt/pkt_sockif.c @@ -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 */