Restore punt/inject after FIB2.0
[vpp.git] / vnet / vnet / unix / tuntap.c
index 967c0ac..4eab391 100644 (file)
  * limitations under the License.
  *------------------------------------------------------------------
  */
+/**
+ * @file
+ * @brief  TunTap Kernel stack (reverse) punt/inject path.
+ *
+ * This driver runs in one of two distinct modes:
+ * - "punt/inject" mode, where we send pkts not otherwise processed
+ * by the forwarding to the Linux kernel stack, and
+ *
+ * - "normal interface" mode, where we treat the Linux kernel stack
+ * as a peer.
+ *
+ * By default, we select punt/inject mode.
+ */
 
 #include <fcntl.h>             /* for open */
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
-#include <sys/types.h> 
+#include <sys/types.h>
 #include <sys/uio.h>           /* for iovec */
 #include <netinet/in.h>
 
@@ -34,6 +47,8 @@
 #include <vnet/ip/ip.h>
 
 #include <vnet/ethernet/ethernet.h>
+#include <vnet/devices/devices.h>
+#include <vnet/feature/feature.h>
 
 #if DPDK == 1
 #include <vnet/devices/dpdk/dpdk.h>
@@ -49,58 +64,52 @@ static void tuntap_nopunt_frame (vlib_main_t * vm,
                                  vlib_node_runtime_t * node,
                                  vlib_frame_t * frame);
 
-/* 
- * This driver runs in one of two distinct modes:
- * "punt/inject" mode, where we send pkts not otherwise processed
- * by the forwarding to the Linux kernel stack, and
- * "normal interface" mode, where we treat the Linux kernel stack
- * as a peer.
- *
- * By default, we select punt/inject mode.
- */
-
 typedef struct {
   u32 sw_if_index;
   u8 is_v6;
   u8 addr[16];
 } subif_address_t;
 
+/**
+ * @brief TUNTAP node main state
+ */
 typedef struct {
-  /* Vector of iovecs for readv/writev calls. */
+  /** Vector of iovecs for readv/writev calls. */
   struct iovec * iovecs;
 
-  /* Vector of VLIB rx buffers to use.  We allocate them in blocks
+  /** Vector of VLIB rx buffers to use.  We allocate them in blocks
      of VLIB_FRAME_SIZE (256). */
   u32 * rx_buffers;
 
-  /* File descriptors for /dev/net/tun and provisioning socket. */
+  /** File descriptors for /dev/net/tun and provisioning socket. */
   int dev_net_tun_fd, dev_tap_fd;
 
-  /* Create a "tap" [ethernet] encaps device */
+  /** Create a "tap" [ethernet] encaps device */
   int is_ether;
 
-  /* 1 if a "normal" routed intfc, 0 if a punt/inject interface */
+  /** 1 if a "normal" routed intfc, 0 if a punt/inject interface */
 
   int have_normal_interface;
 
-  /* tap device destination MAC address. Required, or Linux drops pkts */
+  /** tap device destination MAC address. Required, or Linux drops pkts */
   u8 ether_dst_mac[6];
 
-  /* Interface MTU in bytes and # of default sized buffers. */
+  /** Interface MTU in bytes and # of default sized buffers. */
   u32 mtu_bytes, mtu_buffers;
 
-  /* Linux interface name for tun device. */
+  /** Linux interface name for tun device. */
   char * tun_name;
 
-  /* Pool of subinterface addresses */
+  /** Pool of subinterface addresses */
   subif_address_t *subifs;
 
-  /* Hash for subif addresses */
+  /** Hash for subif addresses */
   mhash_t subif_mhash;
 
+  /** Unix file index */
   u32 unix_file_index;
 
-  /* For the "normal" interface, if configured */
+  /** For the "normal" interface, if configured */
   u32 hw_if_index, sw_if_index;
 
 } tuntap_main_t;
@@ -108,15 +117,23 @@ typedef struct {
 static tuntap_main_t tuntap_main = {
   .tun_name = "vnet",
 
-  /* Suitable defaults for an Ethernet-like tun/tap device */
+  /** Suitable defaults for an Ethernet-like tun/tap device */
   .mtu_bytes = 4096 + 256,
 };
 
-/*
- * tuntap_tx
- * Output node, writes the buffers comprising the incoming frame 
+/**
+ * @brief tuntap_tx
+ * @node tuntap-tx
+ *
+ * Output node, writes the buffers comprising the incoming frame
  * to the tun/tap device, aka hands them to the Linux kernel stack.
- * 
+ *
+ * @param *vm - vlib_main_t
+ * @param *node - vlib_node_runtime_t
+ * @param *frame - vlib_frame_t
+ *
+ * @return rc - uword
+ *
  */
 static uword
 tuntap_tx (vlib_main_t * vm,
@@ -126,6 +143,9 @@ tuntap_tx (vlib_main_t * vm,
   u32 * buffers = vlib_frame_args (frame);
   uword n_packets = frame->n_vectors;
   tuntap_main_t * tm = &tuntap_main;
+  vnet_main_t *vnm = vnet_get_main ();
+  vnet_interface_main_t *im = &vnm->interface_main;
+  u32 n_bytes = 0;
   int i;
 
   for (i = 0; i < n_packets; i++)
@@ -146,7 +166,7 @@ tuntap_tx (vlib_main_t * vm,
       if (tm->iovecs)
        _vec_len (tm->iovecs) = 0;
 
-      /* VLIB buffer chain -> Unix iovec(s). */
+      /** VLIB buffer chain -> Unix iovec(s). */
       vec_add2 (tm->iovecs, iov, 1);
       iov->iov_base = b->data + b->current_data;
       iov->iov_len = l = b->current_length;
@@ -166,14 +186,23 @@ tuntap_tx (vlib_main_t * vm,
 
       if (writev (tm->dev_net_tun_fd, tm->iovecs, vec_len (tm->iovecs)) < l)
        clib_unix_warning ("writev");
+
+      n_bytes += l;
     }
-    
-  /* The normal interface path flattens the buffer chain */
+
+  /* Update tuntap interface output stats. */
+  vlib_increment_combined_counter (im->combined_sw_if_counters
+                                  + VNET_INTERFACE_COUNTER_TX,
+                                  vm->cpu_index,
+                                  tm->sw_if_index, n_packets, n_bytes);
+
+
+  /** The normal interface path flattens the buffer chain */
   if (tm->have_normal_interface)
     vlib_buffer_free_no_next (vm, buffers, n_packets);
   else
     vlib_buffer_free (vm, buffers, n_packets);
-    
+
   return n_packets;
 }
 
@@ -184,14 +213,17 @@ VLIB_REGISTER_NODE (tuntap_tx_node,static) = {
   .vector_size = 4,
 };
 
-enum {
-  TUNTAP_RX_NEXT_IP4_INPUT, 
-  TUNTAP_RX_NEXT_IP6_INPUT, 
-  TUNTAP_RX_NEXT_ETHERNET_INPUT,
-  TUNTAP_RX_NEXT_DROP,
-  TUNTAP_RX_N_NEXT,
-};
-
+/**
+ * @brief TUNTAP receive node
+ * @node tuntap-rx
+ *
+ * @param *vm - vlib_main_t
+ * @param *node - vlib_node_runtime_t
+ * @param *frame - vlib_frame_t
+ *
+ * @return rc - uword
+ *
+ */
 static uword
 tuntap_rx (vlib_main_t * vm,
           vlib_node_runtime_t * node,
@@ -206,9 +238,10 @@ tuntap_rx (vlib_main_t * vm,
 #else
   dpdk_main_t * dm = &dpdk_main;
   u32 free_list_index = dm->vlib_buffer_free_list_index;
+  struct rte_mbuf *first_mb = NULL, *prev_mb = NULL;
 #endif
 
-  /* Make sure we have some RX buffers. */
+  /** Make sure we have some RX buffers. */
   {
     uword n_left = vec_len (tm->rx_buffers);
     uword n_alloc;
@@ -225,14 +258,14 @@ tuntap_rx (vlib_main_t * vm,
       }
   }
 
-  /* Allocate RX buffers from end of rx_buffers.
+  /** Allocate RX buffers from end of rx_buffers.
      Turn them into iovecs to pass to readv. */
   {
     uword i_rx = vec_len (tm->rx_buffers) - 1;
     vlib_buffer_t * b;
     word i, n_bytes_left, n_bytes_in_packet;
 
-    /* We should have enough buffers left for an MTU sized packet. */
+    /** We should have enough buffers left for an MTU sized packet. */
     ASSERT (vec_len (tm->rx_buffers) >= tm->mtu_buffers);
 
     vec_validate (tm->iovecs, tm->mtu_buffers - 1);
@@ -262,6 +295,15 @@ tuntap_rx (vlib_main_t * vm,
        b = vlib_get_buffer (vm, tm->rx_buffers[i_rx]);
 #if DPDK == 1
        mb = rte_mbuf_from_vlib_buffer(b);
+
+        if (first_mb == NULL)
+            first_mb = mb;
+
+        if (prev_mb != NULL)
+          {
+            prev_mb->next = mb;
+            first_mb->nb_segs++;
+          }
 #endif
        b->flags = 0;
        b->current_data = 0;
@@ -270,12 +312,13 @@ tuntap_rx (vlib_main_t * vm,
        n_bytes_left -= buffer_size;
 #if DPDK == 1
         rte_pktmbuf_data_len (mb) = b->current_length;
+        mb->data_off = RTE_PKTMBUF_HEADROOM + b->current_data;
 #endif
 
        if (n_bytes_left <= 0)
           {
 #if DPDK == 1
-            rte_pktmbuf_pkt_len (mb) = n_bytes_in_packet;
+            rte_pktmbuf_pkt_len (first_mb) = n_bytes_in_packet;
 #endif
             break;
           }
@@ -284,20 +327,18 @@ tuntap_rx (vlib_main_t * vm,
        b->flags |= VLIB_BUFFER_NEXT_PRESENT;
        b->next_buffer = tm->rx_buffers[i_rx];
 #if DPDK == 1
-        ASSERT(0);
-        // ((struct rte_pktmbuf *)(b->mb))->next = 
-        // vlib_get_buffer (vm, tm->rx_buffers[i_rx])->mb;
+        prev_mb = mb;
 #endif
       }
 
-    /* Interface counters for tuntap interface. */
-    vlib_increment_combined_counter 
+    /** Interface counters for tuntap interface. */
+    vlib_increment_combined_counter
         (vnet_main.interface_main.combined_sw_if_counters
          + VNET_INTERFACE_COUNTER_RX,
          os_get_cpu_number(),
          tm->sw_if_index,
          1, n_bytes_in_packet);
-    
+
     _vec_len (tm->rx_buffers) = i_rx;
   }
 
@@ -322,19 +363,19 @@ tuntap_rx (vlib_main_t * vm,
 
     if (tm->is_ether)
       {
-       next_index = TUNTAP_RX_NEXT_ETHERNET_INPUT;
+       next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
       }
     else
       switch (b->data[0] & 0xf0)
         {
         case 0x40:
-          next_index = TUNTAP_RX_NEXT_IP4_INPUT;
+          next_index = VNET_DEVICE_INPUT_NEXT_IP4_INPUT;
           break;
         case 0x60:
-          next_index = TUNTAP_RX_NEXT_IP6_INPUT;
+          next_index = VNET_DEVICE_INPUT_NEXT_IP6_INPUT;
           break;
         default:
-          next_index = TUNTAP_RX_NEXT_DROP;
+          next_index = VNET_DEVICE_INPUT_NEXT_DROP;
           break;
         }
 
@@ -345,9 +386,11 @@ tuntap_rx (vlib_main_t * vm,
         vnet_sw_interface_t * si;
         si = vnet_get_sw_interface (vnm, tm->sw_if_index);
         if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
-          next_index = TUNTAP_RX_NEXT_DROP;
+          next_index = VNET_DEVICE_INPUT_NEXT_DROP;
       }
 
+    vnet_feature_start_device_input_x1 (tm->sw_if_index, &next_index, b, 0);
+
     vlib_set_next_frame_buffer (vm, node, next_index, bi);
 
     if (n_trace > 0)
@@ -361,6 +404,9 @@ tuntap_rx (vlib_main_t * vm,
   return 1;
 }
 
+/**
+ * @brief TUNTAP_RX error strings
+ */
 static char * tuntap_rx_error_strings[] = {
   "unknown packet type",
 };
@@ -374,16 +420,17 @@ VLIB_REGISTER_NODE (tuntap_rx_node,static) = {
   .n_errors = 1,
   .error_strings = tuntap_rx_error_strings,
 
-  .n_next_nodes = TUNTAP_RX_N_NEXT,
-  .next_nodes = {
-    [TUNTAP_RX_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
-    [TUNTAP_RX_NEXT_IP6_INPUT] = "ip6-input",
-    [TUNTAP_RX_NEXT_DROP] = "error-drop",
-    [TUNTAP_RX_NEXT_ETHERNET_INPUT] = "ethernet-input",
-  },
+  .n_next_nodes = VNET_DEVICE_INPUT_N_NEXT_NODES,
+  .next_nodes = VNET_DEVICE_INPUT_NEXT_NODES,
 };
 
-/* Gets called when file descriptor is ready from epoll. */
+/**
+ * @brief Gets called when file descriptor is ready from epoll.
+ *
+ * @param *uf - unix_file_t
+ *
+ * @return error - clib_error_t
+ */
 static clib_error_t * tuntap_read_ready (unix_file_t * uf)
 {
   vlib_main_t * vm = vlib_get_main();
@@ -391,11 +438,14 @@ static clib_error_t * tuntap_read_ready (unix_file_t * uf)
   return 0;
 }
 
-/*
- * tuntap_exit
- * Clean up the tun/tap device
+/**
+ * @brief Clean up the tun/tap device
+ *
+ * @param *vm - vlib_main_t
+ *
+ * @return error - clib_error_t
+ *
  */
-
 static clib_error_t *
 tuntap_exit (vlib_main_t * vm)
 {
@@ -437,6 +487,15 @@ tuntap_exit (vlib_main_t * vm)
 
 VLIB_MAIN_LOOP_EXIT_FUNCTION (tuntap_exit);
 
+/**
+ * @brief CLI function for tun/tap config
+ *
+ * @param *vm - vlib_main_t
+ * @param *input - unformat_input_t
+ *
+ * @return error - clib_error_t
+ *
+ */
 static clib_error_t *
 tuntap_config (vlib_main_t * vm, unformat_input_t * input)
 {
@@ -645,6 +704,16 @@ tuntap_config (vlib_main_t * vm, unformat_input_t * input)
 
 VLIB_CONFIG_FUNCTION (tuntap_config, "tuntap");
 
+/**
+ * @brief Add or Del IP4 address to tun/tap interface
+ *
+ * @param *im - ip4_main_t
+ * @param opaque - uword
+ * @param sw_if_index - u32
+ * @param *address - ip4_address_t
+ * @param is_delete - u32
+ *
+ */
 void
 tuntap_ip4_add_del_interface_address (ip4_main_t * im,
                                      uword opaque,
@@ -659,15 +728,15 @@ tuntap_ip4_add_del_interface_address (ip4_main_t * im,
   subif_address_t subif_addr, * ap;
   uword * p;
 
-  /* Tuntap disabled, or using a "normal" interface. */
+  /** Tuntap disabled, or using a "normal" interface. */
   if (tm->have_normal_interface ||  tm->dev_tap_fd < 0)
     return;
 
-  /* See if we already know about this subif */
+  /** See if we already know about this subif */
   memset (&subif_addr, 0, sizeof (subif_addr));
   subif_addr.sw_if_index = sw_if_index;
   clib_memcpy (&subif_addr.addr, address, sizeof (*address));
-  
+
   p = mhash_get (&tm->subif_mhash, &subif_addr);
 
   if (p)
@@ -684,6 +753,12 @@ tuntap_ip4_add_del_interface_address (ip4_main_t * im,
   snprintf (ifr.ifr_name, sizeof(ifr.ifr_name), 
             "%s:%d", tm->tun_name, (int)(ap - tm->subifs));
 
+  /* the tuntap punt/inject is enabled for IPv4 RX so long as
+   * any vpp interface has an IPv4 address.
+   * this is also ref counted.
+   */
+  ip4_sw_interface_enable_disable (tm->sw_if_index, !is_delete);
+
   if (! is_delete)
     {
       struct sockaddr_in * sin;
@@ -719,21 +794,31 @@ tuntap_ip4_add_del_interface_address (ip4_main_t * im,
     clib_unix_warning ("ioctl SIOCSIFFLAGS");
 }
 
-/*
- * $$$$ gross workaround for a known #include bug 
- * #include <linux/ipv6.h> causes multiple definitions if
- * netinet/in.h is also included.
+/**
+ * @brief workaround for a known include file bug.
+ * including @c <linux/ipv6.h> causes multiple definitions if
+ * @c <netinet/in.h is also included.
  */
 struct in6_ifreq {
        struct in6_addr ifr6_addr;
         u32            ifr6_prefixlen;
-       int             ifr6_ifindex; 
+        int            ifr6_ifindex;
 };
 
-/* 
+/**
+ * @brief Add or Del tun/tap interface address.
+ *
  * Both the v6 interface address API and the way ifconfig
  * displays subinterfaces differ from their v4 couterparts.
  * The code given here seems to work but YMMV.
+ *
+ * @param *im - ip6_main_t
+ * @param opaque - uword
+ * @param sw_if_index - u32
+ * @param *address - ip6_address_t
+ * @param address_length - u32
+ * @param if_address_index - u32
+ * @param is_delete - u32
  */
 void
 tuntap_ip6_add_del_interface_address (ip6_main_t * im,
@@ -759,7 +844,7 @@ tuntap_ip6_add_del_interface_address (ip6_main_t * im,
   subif_addr.sw_if_index = sw_if_index;
   subif_addr.is_v6 = 1;
   clib_memcpy (&subif_addr.addr, address, sizeof (*address));
-  
+
   p = mhash_get (&tm->subif_mhash, &subif_addr);
 
   if (p)
@@ -777,6 +862,12 @@ tuntap_ip6_add_del_interface_address (ip6_main_t * im,
   snprintf (ifr.ifr_name, sizeof(ifr.ifr_name), 
             "%s:%d", tm->tun_name, (int)(ap - tm->subifs));
 
+  /* the tuntap punt/inject is enabled for IPv6 RX so long as
+   * any vpp interface has an IPv6 address.
+   * this is also ref counted.
+   */
+  ip6_sw_interface_enable_disable (tm->sw_if_index, !is_delete);
+
   if (! is_delete)
     {
       int sockfd = socket (AF_INET6, SOCK_STREAM, 0);
@@ -820,6 +911,14 @@ tuntap_ip6_add_del_interface_address (ip6_main_t * im,
     }
 }
 
+/**
+ * @brief TX the tun/tap frame
+ *
+ * @param *vm - vlib_main_t
+ * @param *node - vlib_node_runtime_t
+ * @param *frame - vlib_frame_t
+ *
+ */
 static void
 tuntap_punt_frame (vlib_main_t * vm,
                    vlib_node_runtime_t * node,
@@ -829,6 +928,14 @@ tuntap_punt_frame (vlib_main_t * vm,
   vlib_frame_free (vm, node, frame);
 }
 
+/**
+ * @brief Free the tun/tap frame
+ *
+ * @param *vm - vlib_main_t
+ * @param *node - vlib_node_runtime_t
+ * @param *frame - vlib_frame_t
+ *
+ */
 static void
 tuntap_nopunt_frame (vlib_main_t * vm,
                    vlib_node_runtime_t * node,
@@ -842,8 +949,18 @@ tuntap_nopunt_frame (vlib_main_t * vm,
 
 VNET_HW_INTERFACE_CLASS (tuntap_interface_class,static) = {
   .name = "tuntap",
+  .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
 };
 
+/**
+ * @brief Format tun/tap interface name
+ *
+ * @param *s - u8 - formatter string
+ * @param *args - va_list
+ *
+ * @return *s - u8 - formatted string
+ *
+ */
 static u8 * format_tuntap_interface_name (u8 * s, va_list * args)
 {
   u32 i = va_arg (*args, u32);
@@ -852,6 +969,16 @@ static u8 * format_tuntap_interface_name (u8 * s, va_list * args)
   return s;
 }
 
+/**
+ * @brief TX packet out tun/tap
+ *
+ * @param *vm - vlib_main_t
+ * @param *node - vlib_node_runtime_t
+ * @param *frame - vlib_frame_t
+ *
+ * @return n_buffers - uword - Packets transmitted
+ *
+ */
 static uword
 tuntap_intfc_tx (vlib_main_t * vm,
                 vlib_node_runtime_t * node,
@@ -875,6 +1002,14 @@ VNET_DEVICE_CLASS (tuntap_dev_class,static) = {
   .format_device_name = format_tuntap_interface_name,
 };
 
+/**
+ * @brief tun/tap node init
+ *
+ * @param *vm - vlib_main_t
+ *
+ * @return error - clib_error_t
+ *
+ */
 static clib_error_t *
 tuntap_init (vlib_main_t * vm)
 {