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;
 }