net/udp: UDP write buffering is basically functional but needs a lot more verification.
This commit is contained in:
parent
289e4dde06
commit
f2017bded8
@ -52,7 +52,6 @@ config NET_UDP_WRITE_BUFFERS
|
|||||||
default n
|
default n
|
||||||
select NET_WRITE_BUFFERS
|
select NET_WRITE_BUFFERS
|
||||||
select MM_IOB
|
select MM_IOB
|
||||||
depends on EXPERIMENTAL
|
|
||||||
---help---
|
---help---
|
||||||
Write buffers allows buffering of ongoing UDP/IP packets, providing
|
Write buffers allows buffering of ongoing UDP/IP packets, providing
|
||||||
for higher performance, streamed output.
|
for higher performance, streamed output.
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <queue.h>
|
#include <queue.h>
|
||||||
|
|
||||||
#include <nuttx/clock.h>
|
#include <nuttx/clock.h>
|
||||||
@ -137,12 +138,12 @@ struct udp_conn_s
|
|||||||
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
#ifdef CONFIG_NET_UDP_WRITE_BUFFERS
|
||||||
struct udp_wrbuffer_s
|
struct udp_wrbuffer_s
|
||||||
{
|
{
|
||||||
sq_entry_t wb_node; /* Supports a singly linked list */
|
sq_entry_t wb_node; /* Supports a singly linked list */
|
||||||
union ip_addr_u wb_dest; /* Destination address */
|
struct sockaddr_storage wb_dest; /* Destination address */
|
||||||
#ifdef CONFIG_NET_SOCKOPTS
|
#ifdef CONFIG_NET_SOCKOPTS
|
||||||
systime_t wb_start; /* Start time for timeout calculation */
|
systime_t wb_start; /* Start time for timeout calculation */
|
||||||
#endif
|
#endif
|
||||||
struct iob_s *wb_iob; /* Head of the I/O buffer chain */
|
struct iob_s *wb_iob; /* Head of the I/O buffer chain */
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -124,8 +124,6 @@ static int sendto_next_transfer(FAR struct socket *psock,
|
|||||||
static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
|
static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
|
||||||
FAR void *pvconn, FAR void *pvpriv,
|
FAR void *pvconn, FAR void *pvpriv,
|
||||||
uint16_t flags);
|
uint16_t flags);
|
||||||
static inline void sendto_txnotify(FAR struct socket *psock,
|
|
||||||
FAR struct udp_conn_s *conn);
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
@ -378,9 +376,13 @@ static int sendto_next_transfer(FAR struct socket *psock,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q);
|
wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q);
|
||||||
DEBUGASSERT(wrb != NULL);
|
if (wrb == NULL)
|
||||||
|
{
|
||||||
|
ninfo("Write buffer queue is empty\n");
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
ret = udp_connect(conn, (FAR const struct sockaddr *)wrb->wb_iob->io_data);
|
ret = udp_connect(conn, (FAR const struct sockaddr *)&wrb->wb_dest);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
nerr("ERROR: udp_connect failed: %d\n", ret);
|
nerr("ERROR: udp_connect failed: %d\n", ret);
|
||||||
@ -443,6 +445,10 @@ static int sendto_next_transfer(FAR struct socket *psock,
|
|||||||
psock->s_sndcb->flags = (UDP_POLL | NETDEV_DOWN);
|
psock->s_sndcb->flags = (UDP_POLL | NETDEV_DOWN);
|
||||||
psock->s_sndcb->priv = (FAR void *)psock;
|
psock->s_sndcb->priv = (FAR void *)psock;
|
||||||
psock->s_sndcb->event = sendto_eventhandler;
|
psock->s_sndcb->event = sendto_eventhandler;
|
||||||
|
|
||||||
|
/* Notify the device driver of the availability of TX data */
|
||||||
|
|
||||||
|
netdev_txnotify_dev(dev);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,7 +505,7 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
* buffers to send.
|
* buffers to send.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (dev->d_sndlen <= 0 && (flags & UDP_NEWDATA) != 0 &&
|
if (dev->d_sndlen <= 0 && (flags & UDP_NEWDATA) == 0 &&
|
||||||
(flags & UDP_POLL) != 0 && !sq_empty(&conn->write_q))
|
(flags & UDP_POLL) != 0 && !sq_empty(&conn->write_q))
|
||||||
{
|
{
|
||||||
/* Check if the destination IP address is in the ARP or Neighbor
|
/* Check if the destination IP address is in the ARP or Neighbor
|
||||||
@ -576,53 +582,6 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: sendto_txnotify
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Notify the appropriate device driver that we are have data ready to
|
|
||||||
* be send (UDP)
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
* psock - Socket state structure
|
|
||||||
* conn - The UDP connection structure
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* None
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static inline void sendto_txnotify(FAR struct socket *psock,
|
|
||||||
FAR struct udp_conn_s *conn)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_NET_IPv4
|
|
||||||
#ifdef CONFIG_NET_IPv6
|
|
||||||
/* If both IPv4 and IPv6 support are enabled, then we will need to select
|
|
||||||
* the device driver using the appropriate IP domain.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (psock->s_domain == PF_INET)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
/* Notify the device driver that send data is available */
|
|
||||||
|
|
||||||
netdev_ipv4_txnotify(conn->u.ipv4.laddr, conn->u.ipv4.raddr);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_NET_IPv4 */
|
|
||||||
|
|
||||||
#ifdef CONFIG_NET_IPv6
|
|
||||||
#ifdef CONFIG_NET_IPv4
|
|
||||||
else /* if (psock->s_domain == PF_INET6) */
|
|
||||||
#endif /* CONFIG_NET_IPv4 */
|
|
||||||
{
|
|
||||||
/* Notify the device driver that send data is available */
|
|
||||||
|
|
||||||
DEBUGASSERT(psock->s_domain == PF_INET6);
|
|
||||||
netdev_ipv6_txnotify(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_NET_IPv6 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -750,7 +709,14 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||||||
UDP_WBDUMP("I/O buffer chain", wrb, wrb->wb_iob->io_pktlen, 0);
|
UDP_WBDUMP("I/O buffer chain", wrb, wrb->wb_iob->io_pktlen, 0);
|
||||||
|
|
||||||
/* sendto_eventhandler() will send data in FIFO order from the
|
/* sendto_eventhandler() will send data in FIFO order from the
|
||||||
* conn->write_q
|
* conn->write_q.
|
||||||
|
*
|
||||||
|
* REVISIT: Why FIFO order? Because it is easy. In a real world
|
||||||
|
* environment where there are multiple network devices this might
|
||||||
|
* be inefficient because we could be sending data to different
|
||||||
|
* device out-of-queued-order to optimize performance. Sending
|
||||||
|
* data to different networks from a single UDP socket is probably
|
||||||
|
* not a very common use case, however.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sq_addlast(&wrb->wb_node, &conn->write_q);
|
sq_addlast(&wrb->wb_node, &conn->write_q);
|
||||||
@ -770,9 +736,6 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||||||
goto errout_with_wrb;
|
goto errout_with_wrb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Notify the device driver of the availability of TX data */
|
|
||||||
|
|
||||||
sendto_txnotify(psock, conn);
|
|
||||||
net_unlock();
|
net_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user