You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/02/02 13:58:01 UTC
[incubator-nuttx] branch pr198 updated: Improve tun (#198)
This is an automated email from the ASF dual-hosted git repository.
gnutt pushed a commit to branch pr198
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/pr198 by this push:
new 8264638 Improve tun (#198)
8264638 is described below
commit 8264638ebb674ae16ed1c04e8cae4fa30d69752a
Author: Xiang Xiao <xi...@xiaomi.com>
AuthorDate: Sun Feb 2 05:57:52 2020 -0800
Improve tun (#198)
* Remove the code duplication in tun_net_receive_tap and remove the unused filep field
* Shouldn't return -EBUSY in tun_write. Let the caller wait until the write buffer free
* Handle that write buffer is ready first correctly in tun_read
* Remove the unused tun_ipv6multicast
---
drivers/net/tun.c | 268 ++++++++++++++++++++++++------------------------------
1 file changed, 117 insertions(+), 151 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 44f67be..40f99bf 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -134,12 +134,13 @@ struct tun_device_s
{
bool bifup; /* true:ifup false:ifdown */
bool read_wait;
+ bool write_wait;
WDOG_ID txpoll; /* TX poll timer */
struct work_s work; /* For deferring poll work to the work queue */
- FAR struct file *filep;
FAR struct pollfd *poll_fds;
sem_t waitsem;
sem_t read_wait_sem;
+ sem_t write_wait_sem;
size_t read_d_len;
size_t write_d_len;
@@ -170,7 +171,7 @@ static void tun_unlock(FAR struct tun_device_s *priv);
/* Common TX logic */
-static int tun_fd_transmit(FAR struct tun_device_s *priv);
+static void tun_fd_transmit(FAR struct tun_device_s *priv);
static int tun_txpoll(FAR struct net_driver_s *dev);
#ifdef CONFIG_NET_ETHERNET
static int tun_txpoll_tap(FAR struct net_driver_s *dev);
@@ -201,13 +202,10 @@ static int tun_txavail(FAR struct net_driver_s *dev);
static int tun_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
static int tun_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
#endif
-#ifdef CONFIG_NET_ICMPv6
-static void tun_ipv6multicast(FAR struct tun_device_s *priv);
-#endif
static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
FAR const char *devfmt, bool tun);
-static int tun_dev_uninit(FAR struct tun_device_s *priv);
+static void tun_dev_uninit(FAR struct tun_device_s *priv);
/* File interface */
@@ -291,6 +289,18 @@ static void tun_pollnotify(FAR struct tun_device_s *priv,
{
FAR struct pollfd *fds = priv->poll_fds;
+ if (priv->read_wait && (eventset & POLLIN))
+ {
+ priv->read_wait = false;
+ nxsem_post(&priv->read_wait_sem);
+ }
+
+ if (priv->write_wait && (eventset & POLLOUT))
+ {
+ priv->write_wait = false;
+ nxsem_post(&priv->write_wait_sem);
+ }
+
if (fds == NULL)
{
return;
@@ -316,7 +326,7 @@ static void tun_pollnotify(FAR struct tun_device_s *priv,
* priv - Reference to the driver state structure
*
* Returned Value:
- * OK on success; a negated errno on failure
+ * None
*
* Assumptions:
* May or may not be called from an interrupt handler. In either case,
@@ -325,23 +335,10 @@ static void tun_pollnotify(FAR struct tun_device_s *priv,
*
****************************************************************************/
-static int tun_fd_transmit(FAR struct tun_device_s *priv)
+static void tun_fd_transmit(FAR struct tun_device_s *priv)
{
NETDEV_TXPACKETS(&priv->dev);
-
- /* Verify that the hardware is ready to send another packet. If we get
- * here, then we are committed to sending a packet; Higher level logic
- * must have assured that there is no transmission in progress.
- */
-
- if (priv->read_wait)
- {
- priv->read_wait = false;
- nxsem_post(&priv->read_wait_sem);
- }
-
tun_pollnotify(priv, POLLIN);
- return OK;
}
/****************************************************************************
@@ -589,33 +586,6 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
arp_ipin(&priv->dev);
ipv4_input(&priv->dev);
-
- /* If the above function invocation resulted in data that should be
- * sent out on the network, the field d_len will set to a value > 0.
- */
-
- if (priv->dev.d_len > 0)
- {
- /* Update the Ethernet header with the correct MAC address */
-
-#ifdef CONFIG_NET_IPv6
- if (IFF_IS_IPv4(priv->dev.d_flags))
-#endif
- {
- arp_out(&priv->dev);
- }
-#ifdef CONFIG_NET_IPv6
- else
- {
- neighbor_out(&priv->dev);
- }
-#endif
-
- /* And send the packet */
-
- priv->write_d_len = priv->dev.d_len;
- tun_fd_transmit(priv);
- }
}
else
#endif
@@ -628,31 +598,6 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
/* Give the IPv6 packet to the network layer. */
ipv6_input(&priv->dev);
-
- /* If the above function invocation resulted in data that should be
- * sent out on the network, the field d_len will set to a value > 0.
- */
-
- if (priv->dev.d_len > 0)
- {
- /* Update the Ethernet header with the correct MAC address */
-
-#ifdef CONFIG_NET_IPv4
- if (IFF_IS_IPv4(priv->dev.d_flags))
- {
- arp_out(&priv->dev);
- }
- else
-#endif
-#ifdef CONFIG_NET_IPv6
- {
- neighbor_out(&priv->dev);
- }
-#endif
-
- priv->write_d_len = priv->dev.d_len;
- tun_fd_transmit(priv);
- }
}
else
#endif
@@ -670,12 +615,41 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
{
priv->write_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
+ priv->dev.d_len = 0;
}
}
else
#endif
{
NETDEV_RXDROPPED(&priv->dev);
+ priv->dev.d_len = 0;
+ }
+
+ /* If the above function invocation resulted in data that should be
+ * sent out on the network, the field d_len will set to a value > 0.
+ */
+
+ if (priv->dev.d_len > 0)
+ {
+ /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+ if (IFF_IS_IPv4(priv->dev.d_flags))
+#endif
+ {
+ arp_out(&priv->dev);
+ }
+#ifdef CONFIG_NET_IPv6
+ else
+ {
+ neighbor_out(&priv->dev);
+ }
+#endif
+
+ /* And send the packet */
+
+ priv->write_d_len = priv->dev.d_len;
+ tun_fd_transmit(priv);
}
}
#endif
@@ -889,16 +863,6 @@ static int tun_ifup(FAR struct net_driver_s *dev)
dev->d_ipv6addr[6], dev->d_ipv6addr[7]);
#endif
- /* Initialize PHYs, the Ethernet interface, and setup up Ethernet interrupts */
-
- /* Instantiate the MAC address from priv->dev.d_mac.ether.ether_addr_octet */
-
-#ifdef CONFIG_NET_ICMPv6
- /* Set up IPv6 multicast address filtering */
-
- tun_ipv6multicast(priv);
-#endif
-
/* Set and activate a timer process */
wd_start(priv->txpoll, TUN_WDDELAY, tun_poll_expiry,
@@ -1134,16 +1098,18 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
nxsem_init(&priv->waitsem, 0, 1);
nxsem_init(&priv->read_wait_sem, 0, 0);
+ nxsem_init(&priv->write_wait_sem, 0, 0);
/* The wait semaphore is used for signaling and, hence, should not have
* priority inheritance enabled.
*/
nxsem_setprotocol(&priv->read_wait_sem, SEM_PRIO_NONE);
+ nxsem_setprotocol(&priv->write_wait_sem, SEM_PRIO_NONE);
/* Create a watchdog for timing polling for and timing of transmissions */
- priv->txpoll = wd_create(); /* Create periodic poll timer */
+ priv->txpoll = wd_create(); /* Create periodic poll timer */
/* Assign d_ifname if specified. */
@@ -1159,12 +1125,11 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
{
nxsem_destroy(&priv->waitsem);
nxsem_destroy(&priv->read_wait_sem);
+ nxsem_destroy(&priv->write_wait_sem);
return ret;
}
- priv->filep = filep; /* Set link to file */
- filep->f_priv = priv; /* Set link to TUN device */
-
+ filep->f_priv = priv; /* Set link to TUN device */
return ret;
}
@@ -1172,7 +1137,7 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
* Name: tun_dev_uninit
****************************************************************************/
-static int tun_dev_uninit(FAR struct tun_device_s *priv)
+static void tun_dev_uninit(FAR struct tun_device_s *priv)
{
/* Put the interface in the down state */
@@ -1184,8 +1149,7 @@ static int tun_dev_uninit(FAR struct tun_device_s *priv)
nxsem_destroy(&priv->waitsem);
nxsem_destroy(&priv->read_wait_sem);
-
- return OK;
+ nxsem_destroy(&priv->write_wait_sem);
}
/****************************************************************************
@@ -1195,7 +1159,6 @@ static int tun_dev_uninit(FAR struct tun_device_s *priv)
static int tun_open(FAR struct file *filep)
{
filep->f_priv = 0;
-
return OK;
}
@@ -1222,7 +1185,6 @@ static int tun_close(FAR struct file *filep)
tun_dev_uninit(priv);
tundev_unlock(tun);
-
return OK;
}
@@ -1236,40 +1198,47 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
FAR struct tun_device_s *priv = filep->f_priv;
ssize_t ret;
- if (priv == NULL)
+ if (priv == NULL || buflen > CONFIG_NET_TUN_PKTSIZE)
{
return -EINVAL;
}
tun_lock(priv);
- if (priv->write_d_len > 0)
+ for (; ; )
{
- tun_unlock(priv);
- return -EBUSY;
- }
+ /* Check if there are free space to write */
- net_lock();
+ if (priv->write_d_len == 0)
+ {
+ memcpy(priv->write_buf, buffer, buflen);
- if (buflen > CONFIG_NET_TUN_PKTSIZE)
- {
- ret = -EINVAL;
- }
- else
- {
- memcpy(priv->write_buf, buffer, buflen);
+ net_lock();
+ priv->dev.d_buf = priv->write_buf;
+ priv->dev.d_len = buflen;
+
+ tun_net_receive(priv);
+ net_unlock();
- priv->dev.d_buf = priv->write_buf;
- priv->dev.d_len = buflen;
+ ret = buflen;
+ break;
+ }
- tun_net_receive(priv);
+ /* Wait if there are no free space to write */
- ret = (ssize_t)buflen;
+ if ((filep->f_oflags & O_NONBLOCK) != 0)
+ {
+ ret = -EAGAIN;
+ break;
+ }
+
+ priv->write_wait = true;
+ tun_unlock(priv);
+ nxsem_wait(&priv->write_wait_sem);
+ tun_lock(priv);
}
- net_unlock();
tun_unlock(priv);
-
return ret;
}
@@ -1282,8 +1251,6 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
{
FAR struct tun_device_s *priv = filep->f_priv;
ssize_t ret;
- size_t write_d_len;
- size_t read_d_len;
if (priv == NULL)
{
@@ -1292,33 +1259,53 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
tun_lock(priv);
- /* Check if there are data to read in write buffer */
-
- write_d_len = priv->write_d_len;
- if (write_d_len > 0)
+ for (; ; )
{
- if (buflen < write_d_len)
+ /* Check if there are data to read in write buffer */
+
+ if (priv->write_d_len > 0)
{
- ret = -EINVAL;
- goto out;
+ if (buflen < priv->write_d_len)
+ {
+ ret = -EINVAL;
+ break;
+ }
+
+ memcpy(buffer, priv->write_buf, priv->write_d_len);
+ ret = priv->write_d_len;
+ priv->write_d_len = 0;
+
+ NETDEV_TXDONE(&priv->dev);
+ tun_pollnotify(priv, POLLOUT);
+ break;
}
- memcpy(buffer, priv->write_buf, write_d_len);
- ret = (ssize_t)write_d_len;
+ /* Check if there are data to read in read buffer */
- priv->write_d_len = 0;
- NETDEV_TXDONE(&priv->dev);
- tun_pollnotify(priv, POLLOUT);
+ if (priv->read_d_len > 0)
+ {
+ if (buflen < priv->read_d_len)
+ {
+ ret = -EINVAL;
+ break;
+ }
- goto out;
- }
+ memcpy(buffer, priv->read_buf, priv->read_d_len);
+ ret = priv->read_d_len;
+ priv->read_d_len = 0;
+
+ net_lock();
+ tun_txdone(priv);
+ net_unlock();
+ break;
+ }
+
+ /* Wait if there are no data to read */
- if (priv->read_d_len == 0)
- {
if ((filep->f_oflags & O_NONBLOCK) != 0)
{
ret = -EAGAIN;
- goto out;
+ break;
}
priv->read_wait = true;
@@ -1327,27 +1314,7 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
tun_lock(priv);
}
- net_lock();
-
- read_d_len = priv->read_d_len;
- if (buflen < read_d_len)
- {
- ret = -EINVAL;
- }
- else
- {
- memcpy(buffer, priv->read_buf, read_d_len);
- ret = (ssize_t)read_d_len;
- }
-
- priv->read_d_len = 0;
- tun_txdone(priv);
-
- net_unlock();
-
-out:
tun_unlock(priv);
-
return ret;
}
@@ -1410,7 +1377,6 @@ int tun_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
errout:
tun_unlock(priv);
-
return ret;
}