udp: fix csum computation when offload disabled
[vpp.git] / src / vnet / interface_api.c
index a765c0b..c727e51 100644 (file)
  *------------------------------------------------------------------
  */
 
+#define _GNU_SOURCE
+#include <string.h>
+
 #include <vnet/vnet.h>
 #include <vlibmemory/api.h>
 
 #include <vnet/interface.h>
 #include <vnet/interface/rx_queue_funcs.h>
+#include <vnet/interface/tx_queue_funcs.h>
 #include <vnet/api_errno.h>
 #include <vnet/ethernet/ethernet.h>
 #include <vnet/ip/ip.h>
@@ -56,7 +60,9 @@ vpe_api_main_t vpe_api_main;
   _ (SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address)              \
   _ (SW_INTERFACE_SET_RX_MODE, sw_interface_set_rx_mode)                      \
   _ (SW_INTERFACE_RX_PLACEMENT_DUMP, sw_interface_rx_placement_dump)          \
+  _ (SW_INTERFACE_TX_PLACEMENT_GET, sw_interface_tx_placement_get)            \
   _ (SW_INTERFACE_SET_RX_PLACEMENT, sw_interface_set_rx_placement)            \
+  _ (SW_INTERFACE_SET_TX_PLACEMENT, sw_interface_set_tx_placement)            \
   _ (SW_INTERFACE_SET_TABLE, sw_interface_set_table)                          \
   _ (SW_INTERFACE_GET_TABLE, sw_interface_get_table)                          \
   _ (SW_INTERFACE_SET_UNNUMBERED, sw_interface_set_unnumbered)                \
@@ -143,6 +149,7 @@ vl_api_hw_interface_set_mtu_t_handler (vl_api_hw_interface_set_mtu_t * mp)
   u32 sw_if_index = ntohl (mp->sw_if_index);
   u16 mtu = ntohs (mp->mtu);
   ethernet_main_t *em = &ethernet_main;
+  clib_error_t *err;
   int rv = 0;
 
   VALIDATE_SW_IF_INDEX (mp);
@@ -154,7 +161,6 @@ vl_api_hw_interface_set_mtu_t_handler (vl_api_hw_interface_set_mtu_t * mp)
       goto bad_sw_if_index;
     }
 
-  vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, si->hw_if_index);
   ethernet_interface_t *eif = ethernet_get_interface (em, si->hw_if_index);
 
   if (!eif)
@@ -163,20 +169,13 @@ vl_api_hw_interface_set_mtu_t_handler (vl_api_hw_interface_set_mtu_t * mp)
       goto bad_sw_if_index;
     }
 
-  if (mtu < hi->min_supported_packet_bytes)
-    {
-      rv = VNET_API_ERROR_INVALID_VALUE;
-      goto bad_sw_if_index;
-    }
-
-  if (mtu > hi->max_supported_packet_bytes)
+  if ((err = vnet_hw_interface_set_mtu (vnm, si->hw_if_index, mtu)))
     {
-      rv = VNET_API_ERROR_INVALID_VALUE;
+      rv = vnet_api_error (err);
+      clib_error_free (err);
       goto bad_sw_if_index;
     }
 
-  vnet_hw_interface_set_mtu (vnm, si->hw_if_index, mtu);
-
   BAD_SW_IF_INDEX_LABEL;
   REPLY_MACRO (VL_API_HW_INTERFACE_SET_MTU_REPLY);
 }
@@ -262,7 +261,7 @@ send_sw_interface_details (vpe_api_main_t * am,
   mp->link_duplex = ntohl (((hi->flags & VNET_HW_INTERFACE_FLAG_DUPLEX_MASK) >>
                            VNET_HW_INTERFACE_FLAG_DUPLEX_SHIFT));
   mp->link_speed = ntohl (hi->link_speed);
-  mp->link_mtu = ntohs (hi->max_packet_bytes);
+  mp->link_mtu = ntohs (hi->max_frame_size - hi->frame_overhead);
   mp->mtu[VNET_MTU_L3] = ntohl (swif->mtu[VNET_MTU_L3]);
   mp->mtu[VNET_MTU_IP4] = ntohl (swif->mtu[VNET_MTU_IP4]);
   mp->mtu[VNET_MTU_IP6] = ntohl (swif->mtu[VNET_MTU_IP6]);
@@ -388,8 +387,6 @@ vl_api_sw_interface_dump_t_handler (vl_api_sw_interface_dump_t * mp)
       vec_add1 (filter, 0);    /* Ensure it's a C string for strcasecmp() */
     }
 
-  char *strcasestr (char *, char *);   /* lnx hdr file botch */
-  /* *INDENT-OFF* */
   pool_foreach (swif, im->sw_interfaces)
    {
     if (!vnet_swif_is_api_visible (swif))
@@ -403,7 +400,6 @@ vl_api_sw_interface_dump_t_handler (vl_api_sw_interface_dump_t * mp)
 
     send_sw_interface_details (am, rp, swif, name, mp->context);
   }
-  /* *INDENT-ON* */
 
   vec_free (name);
   vec_free (filter);
@@ -812,14 +808,12 @@ link_state_process (vlib_main_t * vm,
          if (event_by_sw_if_index[i] == 0)
            continue;
 
-          /* *INDENT-OFF* */
           pool_foreach (reg, vam->interface_events_registrations)
            {
             vl_reg = vl_api_client_index_to_registration (reg->client_index);
             if (vl_reg)
              send_sw_interface_event (vam, reg, vl_reg, i, event_by_sw_if_index[i]);
           }
-          /* *INDENT-ON* */
        }
       vec_reset_length (event_by_sw_if_index);
     }
@@ -835,13 +829,11 @@ static clib_error_t *sw_interface_add_del_function (vnet_main_t * vm,
                                                    u32 sw_if_index,
                                                    u32 flags);
 
-/* *INDENT-OFF* */
 VLIB_REGISTER_NODE (link_state_process_node,static) = {
   .function = link_state_process,
   .type = VLIB_NODE_TYPE_PROCESS,
   .name = "vpe-link-state-process",
 };
-/* *INDENT-ON* */
 
 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (admin_up_down_function);
 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (link_up_down_function);
@@ -1028,21 +1020,19 @@ vl_api_sw_interface_set_interface_name_t_handler (
 {
   vl_api_sw_interface_set_interface_name_reply_t *rmp;
   vnet_main_t *vnm = vnet_get_main ();
-  u32 sw_if_index = ntohl (mp->sw_if_index);
-  vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
   clib_error_t *error;
   int rv = 0;
 
+  VALIDATE_SW_IF_INDEX (mp);
+
+  u32 sw_if_index = ntohl (mp->sw_if_index);
+  vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
+
   if (mp->name[0] == 0)
     {
       rv = VNET_API_ERROR_INVALID_VALUE;
       goto out;
     }
-  if (si == 0)
-    {
-      rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
-      goto out;
-    }
 
   error = vnet_rename_interface (vnm, si->hw_if_index, (char *) mp->name);
   if (error)
@@ -1052,6 +1042,7 @@ vl_api_sw_interface_set_interface_name_t_handler (
     }
 
 out:
+  BAD_SW_IF_INDEX_LABEL;
   REPLY_MACRO (VL_API_SW_INTERFACE_SET_INTERFACE_NAME_REPLY);
 }
 
@@ -1215,6 +1206,164 @@ out:
   REPLY_MACRO (VL_API_SW_INTERFACE_SET_RX_PLACEMENT_REPLY);
 }
 
+static void
+send_interface_tx_placement_details (vnet_hw_if_tx_queue_t **all_queues,
+                                    u32 index, vl_api_registration_t *rp,
+                                    u32 context)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  vl_api_sw_interface_tx_placement_details_t *rmp;
+  u32 n_bits = 0, v = ~0;
+  vnet_hw_if_tx_queue_t **q = vec_elt_at_index (all_queues, index);
+  uword *bitmap = q[0]->threads;
+  u32 hw_if_index = q[0]->hw_if_index;
+  vnet_hw_interface_t *hw_if = vnet_get_hw_interface (vnm, hw_if_index);
+
+  n_bits = clib_bitmap_count_set_bits (bitmap);
+  u32 n = n_bits * sizeof (u32);
+
+  REPLY_MACRO_DETAILS5_END (VL_API_SW_INTERFACE_TX_PLACEMENT_DETAILS, n, rp,
+                           context, ({
+                             rmp->sw_if_index = hw_if->sw_if_index;
+                             rmp->queue_id = q[0]->queue_id;
+                             rmp->shared = q[0]->shared_queue;
+                             rmp->array_size = n_bits;
+
+                             v = clib_bitmap_first_set (bitmap);
+                             for (u32 i = 0; i < n_bits; i++)
+                               {
+                                 rmp->threads[i] = v;
+                                 v = clib_bitmap_next_set (bitmap, v + 1);
+                               }
+                           }));
+}
+
+static void
+vl_api_sw_interface_tx_placement_get_t_handler (
+  vl_api_sw_interface_tx_placement_get_t *mp)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  vl_api_sw_interface_tx_placement_get_reply_t *rmp = 0;
+  vnet_hw_if_tx_queue_t **all_queues = 0;
+  vnet_hw_if_tx_queue_t *q;
+  u32 sw_if_index = mp->sw_if_index;
+  i32 rv = 0;
+
+  if (pool_elts (vnm->interface_main.hw_if_tx_queues) == 0)
+    {
+      rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+      goto err;
+    }
+
+  if (sw_if_index == ~0)
+    {
+      pool_foreach (q, vnm->interface_main.hw_if_tx_queues)
+       vec_add1 (all_queues, q);
+      vec_sort_with_function (all_queues, vnet_hw_if_txq_cmp_cli_api);
+    }
+  else
+    {
+      u32 qi = ~0;
+      vnet_sw_interface_t *si;
+
+      if (!vnet_sw_if_index_is_api_valid (sw_if_index))
+       {
+         clib_warning ("sw_if_index %u does not exist", sw_if_index);
+         rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
+         goto err;
+       }
+
+      si = vnet_get_sw_interface (vnm, sw_if_index);
+      if (si->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
+       {
+         clib_warning ("interface type is not HARDWARE! P2P, PIPE and SUB"
+                       " interfaces are not supported");
+         rv = VNET_API_ERROR_INVALID_INTERFACE;
+         goto err;
+       }
+
+      vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, si->hw_if_index);
+      for (qi = 0; qi < vec_len (hw->tx_queue_indices); qi++)
+       {
+         q = vnet_hw_if_get_tx_queue (vnm, hw->tx_queue_indices[qi]);
+         vec_add1 (all_queues, q);
+       }
+    }
+
+  REPLY_AND_DETAILS_VEC_MACRO_END (VL_API_SW_INTERFACE_TX_PLACEMENT_GET_REPLY,
+                                  all_queues, mp, rmp, rv, ({
+                                    send_interface_tx_placement_details (
+                                      all_queues, cursor, rp, mp->context);
+                                  }));
+
+  vec_free (all_queues);
+  return;
+
+err:
+  REPLY_MACRO_END (VL_API_SW_INTERFACE_TX_PLACEMENT_GET_REPLY);
+}
+
+static void
+vl_api_sw_interface_set_tx_placement_t_handler (
+  vl_api_sw_interface_set_tx_placement_t *mp)
+{
+  vl_api_sw_interface_set_tx_placement_reply_t *rmp;
+  vnet_main_t *vnm = vnet_get_main ();
+  u32 sw_if_index = mp->sw_if_index;
+  vnet_sw_interface_t *si;
+  uword *bitmap = 0;
+  u32 queue_id = ~0;
+  u32 size = 0;
+  clib_error_t *error = 0;
+  int rv = 0;
+
+  VALIDATE_SW_IF_INDEX_END (mp);
+
+  si = vnet_get_sw_interface (vnm, sw_if_index);
+  if (si->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
+    {
+      rv = VNET_API_ERROR_INVALID_VALUE;
+      goto bad_sw_if_index;
+    }
+
+  size = mp->array_size;
+  for (u32 i = 0; i < size; i++)
+    {
+      u32 thread_index = mp->threads[i];
+      bitmap = clib_bitmap_set (bitmap, thread_index, 1);
+    }
+
+  queue_id = mp->queue_id;
+  rv = set_hw_interface_tx_queue (si->hw_if_index, queue_id, bitmap);
+
+  switch (rv)
+    {
+    case VNET_API_ERROR_INVALID_VALUE:
+      error = clib_error_return (
+       0, "please specify valid thread(s) - last thread index %u",
+       clib_bitmap_last_set (bitmap));
+      break;
+    case VNET_API_ERROR_INVALID_QUEUE:
+      error = clib_error_return (
+       0, "unknown queue %u on interface %s", queue_id,
+       vnet_get_hw_interface (vnet_get_main (), si->hw_if_index)->name);
+      break;
+    default:
+      break;
+    }
+
+  if (error)
+    {
+      clib_error_report (error);
+      goto out;
+    }
+
+  BAD_SW_IF_INDEX_LABEL;
+out:
+  REPLY_MACRO_END (VL_API_SW_INTERFACE_SET_TX_PLACEMENT_REPLY);
+  clib_bitmap_free (bitmap);
+}
+
 static void
 vl_api_create_vlan_subif_t_handler (vl_api_create_vlan_subif_t * mp)
 {
@@ -1321,12 +1470,10 @@ vl_api_create_subif_t_handler (vl_api_create_subif_t * mp)
 
   BAD_SW_IF_INDEX_LABEL;
 
-  /* *INDENT-OFF* */
   REPLY_MACRO2(VL_API_CREATE_SUBIF_REPLY,
   ({
     rmp->sw_if_index = ntohl(sub_sw_if_index);
   }));
-  /* *INDENT-ON* */
 }
 
 static void
@@ -1368,12 +1515,10 @@ vl_api_create_loopback_t_handler (vl_api_create_loopback_t * mp)
   mac_address_decode (mp->mac_address, &mac);
   rv = vnet_create_loopback_interface (&sw_if_index, (u8 *) & mac, 0, 0);
 
-  /* *INDENT-OFF* */
   REPLY_MACRO2(VL_API_CREATE_LOOPBACK_REPLY,
   ({
     rmp->sw_if_index = ntohl (sw_if_index);
   }));
-  /* *INDENT-ON* */
 }
 
 static void vl_api_create_loopback_instance_t_handler
@@ -1390,12 +1535,10 @@ static void vl_api_create_loopback_instance_t_handler
   rv = vnet_create_loopback_interface (&sw_if_index, (u8 *) & mac,
                                       is_specified, user_instance);
 
-  /* *INDENT-OFF* */
   REPLY_MACRO2(VL_API_CREATE_LOOPBACK_INSTANCE_REPLY,
   ({
     rmp->sw_if_index = ntohl (sw_if_index);
   }));
-  /* *INDENT-ON* */
 }
 
 static void
@@ -1449,6 +1592,92 @@ static void
   REPLY_MACRO (VL_API_SW_INTERFACE_ADDRESS_REPLACE_END_REPLY);
 }
 
+static void
+vl_api_pcap_set_filter_function_t_handler (
+  vl_api_pcap_set_filter_function_t *mp)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  vnet_pcap_t *pp = &vnm->pcap;
+  vl_api_pcap_set_filter_function_reply_t *rmp;
+  unformat_input_t input = { 0 };
+  vlib_is_packet_traced_fn_t *f;
+  char *filter_name;
+  int rv = 0;
+  filter_name = vl_api_from_api_to_new_c_string (&mp->filter_function_name);
+  unformat_init_cstring (&input, filter_name);
+  if (unformat (&input, "%U", unformat_vlib_trace_filter_function, &f) == 0)
+    {
+      rv = -1;
+      goto done;
+    }
+
+  pp->current_filter_function = f;
+
+done:
+  unformat_free (&input);
+  vec_free (filter_name);
+  REPLY_MACRO (VL_API_PCAP_SET_FILTER_FUNCTION_REPLY);
+}
+
+static void
+vl_api_pcap_trace_on_t_handler (vl_api_pcap_trace_on_t *mp)
+{
+  vl_api_pcap_trace_on_reply_t *rmp;
+  unformat_input_t filename, drop_err_name;
+  vnet_pcap_dispatch_trace_args_t capture_args;
+  int rv = 0;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  unformat_init_cstring (&filename, (char *) mp->filename);
+  if (!unformat_user (&filename, unformat_vlib_tmpfile,
+                     &capture_args.filename))
+    {
+      rv = VNET_API_ERROR_ILLEGAL_NAME;
+      goto out;
+    }
+
+  capture_args.rx_enable = mp->capture_rx;
+  capture_args.tx_enable = mp->capture_tx;
+  capture_args.preallocate_data = mp->preallocate_data;
+  capture_args.free_data = mp->free_data;
+  capture_args.drop_enable = mp->capture_drop;
+  capture_args.status = 0;
+  capture_args.packets_to_capture = ntohl (mp->max_packets);
+  capture_args.sw_if_index = ntohl (mp->sw_if_index);
+  capture_args.filter = mp->filter;
+  capture_args.max_bytes_per_pkt = ntohl (mp->max_bytes_per_packet);
+  capture_args.drop_err = ~0;
+
+  unformat_init_cstring (&drop_err_name, (char *) mp->error);
+  unformat_user (&drop_err_name, unformat_vlib_error, vlib_get_main (),
+                &capture_args.drop_err);
+
+  rv = vnet_pcap_dispatch_trace_configure (&capture_args);
+
+  BAD_SW_IF_INDEX_LABEL;
+
+out:
+  unformat_free (&filename);
+  unformat_free (&drop_err_name);
+
+  REPLY_MACRO (VL_API_PCAP_TRACE_ON_REPLY);
+}
+
+static void
+vl_api_pcap_trace_off_t_handler (vl_api_pcap_trace_off_t *mp)
+{
+  vl_api_pcap_trace_off_reply_t *rmp;
+  vnet_pcap_dispatch_trace_args_t capture_args;
+  int rv = 0;
+
+  clib_memset (&capture_args, 0, sizeof (capture_args));
+
+  rv = vnet_pcap_dispatch_trace_configure (&capture_args);
+
+  REPLY_MACRO (VL_API_PCAP_TRACE_OFF_REPLY);
+}
+
 /*
  * vpe_api_hookup
  * Add vpe's API message handlers to the table.
@@ -1465,20 +1694,31 @@ interface_api_hookup (vlib_main_t * vm)
 {
   api_main_t *am = vlibapi_get_main ();
 
-  /* Mark these APIs as mp safe */
-  am->is_mp_safe[VL_API_SW_INTERFACE_DUMP] = 1;
-  am->is_mp_safe[VL_API_SW_INTERFACE_DETAILS] = 1;
-  am->is_mp_safe[VL_API_SW_INTERFACE_TAG_ADD_DEL] = 1;
-  am->is_mp_safe[VL_API_SW_INTERFACE_SET_INTERFACE_NAME] = 1;
-
-  /* Do not replay VL_API_SW_INTERFACE_DUMP messages */
-  am->api_trace_cfg[VL_API_SW_INTERFACE_DUMP].replay_enable = 0;
-
   /*
    * Set up the (msg_name, crc, message-id) table
    */
   REPLY_MSG_ID_BASE = setup_message_id_table ();
 
+  /* Mark these APIs as mp safe */
+  vl_api_set_msg_thread_safe (am, REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_DUMP,
+                             1);
+  vl_api_set_msg_thread_safe (
+    am, REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_DETAILS, 1);
+  vl_api_set_msg_thread_safe (
+    am, REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_TAG_ADD_DEL, 1);
+  vl_api_set_msg_thread_safe (
+    am, REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_SET_INTERFACE_NAME, 1);
+
+  /* Do not replay VL_API_SW_INTERFACE_DUMP messages */
+  vl_api_allow_msg_replay (am, REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_DUMP,
+                          0);
+
+  /* Mark these APIs as autoendian */
+  vl_api_set_msg_autoendian (
+    am, REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_SET_TX_PLACEMENT, 1);
+  vl_api_set_msg_autoendian (
+    am, REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_TX_PLACEMENT_GET, 1);
+
   return 0;
 }