FIB table add/delete API
[vpp.git] / src / vnet / interface_api.c
index 39c0627..419fef9 100644 (file)
@@ -46,6 +46,7 @@
 #undef vl_printfun
 
 #include <vlibapi/api_helper_macros.h>
+vpe_api_main_t vpe_api_main;
 
 #define foreach_vpe_api_msg                                     \
 _(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags)               \
@@ -57,7 +58,8 @@ _(SW_INTERFACE_SET_TABLE, sw_interface_set_table)               \
 _(SW_INTERFACE_GET_TABLE, sw_interface_get_table)               \
 _(SW_INTERFACE_SET_UNNUMBERED, sw_interface_set_unnumbered)     \
 _(SW_INTERFACE_CLEAR_STATS, sw_interface_clear_stats)           \
-_(SW_INTERFACE_TAG_ADD_DEL, sw_interface_tag_add_del)
+_(SW_INTERFACE_TAG_ADD_DEL, sw_interface_tag_add_del)           \
+_(SW_INTERFACE_SET_MAC_ADDRESS, sw_interface_set_mac_address)
 
 static void
 vl_api_sw_interface_set_flags_t_handler (vl_api_sw_interface_set_flags_t * mp)
@@ -96,8 +98,15 @@ vl_api_sw_interface_set_mtu_t_handler (vl_api_sw_interface_set_mtu_t * mp)
 
   VALIDATE_SW_IF_INDEX (mp);
 
-  vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, sw_if_index);
-  ethernet_interface_t *eif = ethernet_get_interface (em, sw_if_index);
+  vnet_sw_interface_t *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;
+    }
+
+  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)
     {
@@ -120,7 +129,7 @@ vl_api_sw_interface_set_mtu_t_handler (vl_api_sw_interface_set_mtu_t * mp)
   if (hi->max_packet_bytes != mtu)
     {
       hi->max_packet_bytes = mtu;
-      ethernet_set_flags (vnm, sw_if_index, flags);
+      ethernet_set_flags (vnm, si->hw_if_index, flags);
     }
 
   BAD_SW_IF_INDEX_LABEL;
@@ -311,68 +320,189 @@ stats_dsunlock (void)
 static void
 vl_api_sw_interface_set_table_t_handler (vl_api_sw_interface_set_table_t * mp)
 {
-  int rv = 0;
-  u32 table_id = ntohl (mp->vrf_id);
-  u32 sw_if_index = ntohl (mp->sw_if_index);
   vl_api_sw_interface_set_table_reply_t *rmp;
-  CLIB_UNUSED (ip_interface_address_t * ia);
-  u32 fib_index;
+  u32 sw_if_index = ntohl (mp->sw_if_index);
+  u32 table_id = ntohl (mp->vrf_id);
+  int rv = 0;
 
   VALIDATE_SW_IF_INDEX (mp);
 
   stats_dslock_with_hint (1 /* release hint */ , 4 /* tag */ );
 
   if (mp->is_ipv6)
+    rv = ip_table_bind (FIB_PROTOCOL_IP6, sw_if_index, table_id, 1);
+  else
+    rv = ip_table_bind (FIB_PROTOCOL_IP4, sw_if_index, table_id, 1);
+
+  stats_dsunlock ();
+
+  BAD_SW_IF_INDEX_LABEL;
+
+  REPLY_MACRO (VL_API_SW_INTERFACE_SET_TABLE_REPLY);
+}
+
+int
+ip_table_bind (fib_protocol_t fproto,
+              uint32_t sw_if_index, uint32_t table_id, u8 is_api)
+{
+  CLIB_UNUSED (ip_interface_address_t * ia);
+  u32 fib_index, mfib_index;
+  fib_source_t src;
+  mfib_source_t msrc;
+
+  if (is_api)
+    {
+      src = FIB_SOURCE_API;
+      msrc = MFIB_SOURCE_API;
+    }
+  else
+    {
+      src = FIB_SOURCE_CLI;
+      msrc = MFIB_SOURCE_CLI;
+    }
+
+  /*
+   * This is temporary whilst I do the song and dance with the CSIT version
+   */
+  if (0 != table_id)
+    {
+      fib_index = fib_table_find_or_create_and_lock (fproto, table_id, src);
+      mfib_index =
+       mfib_table_find_or_create_and_lock (fproto, table_id, msrc);
+    }
+  else
     {
+      fib_index = 0;
+      mfib_index = 0;
+    }
+
+  /*
+   * This if table does not exist = error is what we want in the end.
+   */
+  /* fib_index = fib_table_find (fproto, table_id); */
+  /* mfib_index = mfib_table_find (fproto, table_id); */
+
+  /* if (~0 == fib_index || ~0 == mfib_index) */
+  /*   { */
+  /*     return (VNET_API_ERROR_NO_SUCH_FIB); */
+  /*   } */
+
+  if (FIB_PROTOCOL_IP6 == fproto)
+    {
+      /*
+       * If the interface already has in IP address, then a change int
+       * VRF is not allowed. The IP address applied must first be removed.
+       * We do not do that automatically here, since VPP has no knowledge
+       * of whether thoses subnets are valid in the destination VRF.
+       */
       /* *INDENT-OFF* */
       foreach_ip_interface_address (&ip6_main.lookup_main,
                                    ia, sw_if_index,
                                    1 /* honor unnumbered */ ,
       ({
-        rv = VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE;
-        goto done;
+        return (VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE);
       }));
       /* *INDENT-ON* */
 
-      fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
-                                                    table_id);
       vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
-      ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
-
-      fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
-                                                     table_id);
       vec_validate (ip6_main.mfib_index_by_sw_if_index, sw_if_index);
-      ip6_main.mfib_index_by_sw_if_index[sw_if_index] = fib_index;
+
+      /*
+       * tell those that are interested that the binding is changing.
+       */
+      ip6_table_bind_callback_t *cb;
+      vec_foreach (cb, ip6_main.table_bind_callbacks)
+       cb->function (&ip6_main, cb->function_opaque,
+                     sw_if_index,
+                     fib_index,
+                     ip6_main.fib_index_by_sw_if_index[sw_if_index]);
+
+      if (0 == table_id)
+       {
+         /* reset back to default */
+         if (0 != ip6_main.fib_index_by_sw_if_index[sw_if_index])
+           fib_table_unlock (ip6_main.fib_index_by_sw_if_index[sw_if_index],
+                             FIB_PROTOCOL_IP6, src);
+         if (0 != ip6_main.mfib_index_by_sw_if_index[sw_if_index])
+           mfib_table_unlock (ip6_main.mfib_index_by_sw_if_index
+                              [sw_if_index], FIB_PROTOCOL_IP6, msrc);
+
+       }
+      else
+       {
+         /* we need to lock the table now it's inuse */
+         fib_table_lock (fib_index, FIB_PROTOCOL_IP6, src);
+         mfib_table_lock (mfib_index, FIB_PROTOCOL_IP6, msrc);
+       }
+
+      ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
+      ip6_main.mfib_index_by_sw_if_index[sw_if_index] = mfib_index;
     }
   else
     {
+      /*
+       * If the interface already has in IP address, then a change int
+       * VRF is not allowed. The IP address applied must first be removed.
+       * We do not do that automatically here, since VPP has no knowledge
+       * of whether thoses subnets are valid in the destination VRF.
+       */
       /* *INDENT-OFF* */
       foreach_ip_interface_address (&ip4_main.lookup_main,
                                    ia, sw_if_index,
                                    1 /* honor unnumbered */ ,
       ({
-        rv = VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE;
-        goto done;
+        return (VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE);
       }));
       /* *INDENT-ON* */
 
-      fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
-                                                    table_id);
       vec_validate (ip4_main.fib_index_by_sw_if_index, sw_if_index);
-      ip4_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
-
-      fib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
-                                                     table_id);
       vec_validate (ip4_main.mfib_index_by_sw_if_index, sw_if_index);
-      ip4_main.mfib_index_by_sw_if_index[sw_if_index] = fib_index;
-    }
 
-done:
-  stats_dsunlock ();
+      /*
+       * tell those that are interested that the binding is changing.
+       */
+      ip4_table_bind_callback_t *cb;
+      vec_foreach (cb, ip4_main.table_bind_callbacks)
+       cb->function (&ip4_main, cb->function_opaque,
+                     sw_if_index,
+                     fib_index,
+                     ip4_main.fib_index_by_sw_if_index[sw_if_index]);
+
+      if (0 == table_id)
+       {
+         /* reset back to default */
+         if (0 != ip4_main.fib_index_by_sw_if_index[sw_if_index])
+           fib_table_unlock (ip4_main.fib_index_by_sw_if_index[sw_if_index],
+                             FIB_PROTOCOL_IP4, src);
+         if (0 != ip4_main.mfib_index_by_sw_if_index[sw_if_index])
+           mfib_table_unlock (ip4_main.mfib_index_by_sw_if_index
+                              [sw_if_index], FIB_PROTOCOL_IP4, msrc);
 
-  BAD_SW_IF_INDEX_LABEL;
+       }
+      else
+       {
+         /* we need to lock the table now it's inuse */
+         fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
+                                                        table_id, src);
 
-  REPLY_MACRO (VL_API_SW_INTERFACE_SET_TABLE_REPLY);
+         mfib_index = mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
+                                                          table_id, msrc);
+       }
+
+      ip4_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
+      ip4_main.mfib_index_by_sw_if_index[sw_if_index] = mfib_index;
+    }
+
+  /*
+   * Temporary. undo the locks from the find and create at the staart
+   */
+  if (0 != table_id)
+    {
+      fib_table_unlock (fib_index, fproto, src);
+      mfib_table_unlock (mfib_index, fproto, msrc);
+    }
+
+  return (0);
 }
 
 static void
@@ -569,19 +699,22 @@ event_data_cmp (void *a1, void *a2)
 }
 
 static void
-send_sw_interface_flags (vpe_api_main_t * am,
+send_sw_interface_event (vpe_api_main_t * am,
+                        vpe_client_registration_t * reg,
                         unix_shared_memory_queue_t * q,
                         vnet_sw_interface_t * swif)
 {
-  vl_api_sw_interface_set_flags_t *mp;
+  vl_api_sw_interface_event_t *mp;
   vnet_main_t *vnm = am->vnet_main;
 
   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm,
                                                       swif->sw_if_index);
   mp = vl_msg_api_alloc (sizeof (*mp));
   memset (mp, 0, sizeof (*mp));
-  mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_SET_FLAGS);
+  mp->_vl_msg_id = ntohs (VL_API_SW_INTERFACE_EVENT);
   mp->sw_if_index = ntohl (swif->sw_if_index);
+  mp->client_index = reg->client_index;
+  mp->pid = reg->client_pid;
 
   mp->admin_up_down = (swif->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? 1 : 0;
   mp->link_up_down = (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) ? 1 : 0;
@@ -636,7 +769,7 @@ link_state_process (vlib_main_t * vm,
                                          event_data[i]))
                   {
                     swif = vnet_get_sw_interface (vnm, event_data[i]);
-                    send_sw_interface_flags (vam, q, swif);
+                    send_sw_interface_event (vam, reg, q, swif);
                   }
               }
           }));
@@ -725,6 +858,38 @@ out:
   REPLY_MACRO (VL_API_SW_INTERFACE_TAG_ADD_DEL_REPLY);
 }
 
+static void vl_api_sw_interface_set_mac_address_t_handler
+  (vl_api_sw_interface_set_mac_address_t * mp)
+{
+  vl_api_sw_interface_set_mac_address_reply_t *rmp;
+  vnet_main_t *vnm = vnet_get_main ();
+  u32 sw_if_index = ntohl (mp->sw_if_index);
+  u64 mac;
+  clib_error_t *error;
+  int rv = 0;
+
+  VALIDATE_SW_IF_INDEX (mp);
+
+  mac = ((u64) mp->mac_address[0] << (8 * 0)
+        | (u64) mp->mac_address[1] << (8 * 1)
+        | (u64) mp->mac_address[2] << (8 * 2)
+        | (u64) mp->mac_address[3] << (8 * 3)
+        | (u64) mp->mac_address[4] << (8 * 4)
+        | (u64) mp->mac_address[5] << (8 * 5));
+
+  error = vnet_hw_interface_change_mac_address (vnm, sw_if_index, mac);
+  if (error)
+    {
+      rv = VNET_API_ERROR_UNIMPLEMENTED;
+      clib_error_report (error);
+      goto out;
+    }
+
+  BAD_SW_IF_INDEX_LABEL;
+out:
+  REPLY_MACRO (VL_API_SW_INTERFACE_SET_MAC_ADDRESS_REPLY);
+}
+
 /*
  * vpe_api_hookup
  * Add vpe's API message handlers to the table.