IPv6: Make link-local configurable per-interface (VPP-1446)

Remove old nonfunctional code for setting link-local addresses.
Use common API for setting all IPv6 addresses.

Change-Id: I562329df86341f81ef2441510a9eefbbf710f6e0
Signed-off-by: Juraj Sloboda <jsloboda@cisco.com>
Signed-off-by: Matus Fabian <matfabia@cisco.com>
diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h
index fdafb7e..1ec5ad4 100644
--- a/src/vnet/api_errno.h
+++ b/src/vnet/api_errno.h
@@ -53,7 +53,7 @@
 _(INVALID_DST_ADDRESS, -58, "Invalid dst address")                      \
 _(ADDRESS_LENGTH_MISMATCH, -59, "Address length mismatch")              \
 _(ADDRESS_NOT_FOUND_FOR_INTERFACE, -60, "Address not found for interface") \
-_(ADDRESS_NOT_LINK_LOCAL, -61, "Address not link-local")                \
+_(ADDRESS_NOT_DELETABLE, -61, "Address not deletable")                  \
 _(IP6_NOT_ENABLED, -62, "ip6 not enabled")				\
 _(IN_PROGRESS, 10, "Operation in progress")				\
 _(NO_SUCH_NODE, -63, "No such graph node")				\
diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api
index 954ec92..cf25291 100644
--- a/src/vnet/ip/ip.api
+++ b/src/vnet/ip/ip.api
@@ -356,20 +356,6 @@
   u8 enable;			/* set to true if enable */
 };
 
-/** \brief IPv6 set link local address on interface request
-    @param client_index - opaque cookie to identify the sender
-    @param context - sender context, to match reply w/ request
-    @param sw_if_index - interface to set link local on
-    @param address[] - the new link local address
-*/
-autoreply define sw_interface_ip6_set_link_local_address
-{
-  u32 client_index;
-  u32 context;
-  u32 sw_if_index;
-  u8 address[16];
-};
-
 /** \brief Add / del route request
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c
index 303c4bb..be0037e 100644
--- a/src/vnet/ip/ip6_forward.c
+++ b/src/vnet/ip/ip6_forward.c
@@ -201,6 +201,7 @@
   clib_error_t *error;
   u32 if_address_index;
   ip6_address_fib_t ip6_af, *addr_fib = 0;
+  ip6_address_t ll_addr;
 
   /* local0 interface doesn't support IP addressing */
   if (sw_if_index == 0)
@@ -209,6 +210,36 @@
 	clib_error_create ("local0 interface doesn't support IP addressing");
     }
 
+  if (ip6_address_is_link_local_unicast (address))
+    {
+      if (address_length != 128)
+	{
+	  vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
+	  return
+	    clib_error_create
+	    ("prefix length of link-local address must be 128");
+	}
+      if (!is_del)
+	{
+	  return ip6_neighbor_set_link_local_address (vm, sw_if_index,
+						      address);
+	}
+      else
+	{
+	  ll_addr = ip6_neighbor_get_link_local_address (sw_if_index);
+	  if (ip6_address_is_equal (&ll_addr, address))
+	    {
+	      vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_DELETABLE;
+	      return clib_error_create ("address not deletable");
+	    }
+	  else
+	    {
+	      vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
+	      return clib_error_create ("address not found");
+	    }
+	}
+    }
+
   vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
   vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
 
diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c
index 177bcc1..9be5720 100755
--- a/src/vnet/ip/ip6_neighbor.c
+++ b/src/vnet/ip/ip6_neighbor.c
@@ -243,9 +243,10 @@
   static ip6_address_t empty_address = { {0} };
   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
   ip6_radv_t *radv_info;
-  u32 ri;
+  u32 ri = ~0;
 
-  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
+  if (vec_len (nm->if_radv_pool_index_by_sw_if_index) > sw_if_index)
+    ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
   if (ri == ~0)
     {
       clib_warning ("IPv6 is not enabled for sw_if_index %d", sw_if_index);
@@ -4424,21 +4425,19 @@
 /* *INDENT-ON* */
 
 clib_error_t *
-set_ip6_link_local_address (vlib_main_t * vm,
-			    u32 sw_if_index, ip6_address_t * address)
+ip6_neighbor_set_link_local_address (vlib_main_t * vm, u32 sw_if_index,
+				     ip6_address_t * address)
 {
   clib_error_t *error = 0;
   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
   u32 ri;
   ip6_radv_t *radv_info;
   vnet_main_t *vnm = vnet_get_main ();
+  ip6_ll_prefix_t pfx = { 0, };
 
   if (!ip6_address_is_link_local_unicast (address))
-    {
-      vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_LINK_LOCAL;
-      return (error = clib_error_return (0, "address not link-local",
-					 format_unformat_error));
-    }
+    return (error = clib_error_return (0, "address not link-local",
+				       format_unformat_error));
 
   /* call enable ipv6  */
   enable_ip6_interface (vm, sw_if_index);
@@ -4449,25 +4448,16 @@
     {
       radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
 
-      /* save if link local address (overwrite default) */
+      pfx.ilp_sw_if_index = sw_if_index;
 
-      /* delete the old one */
-      error = ip6_add_del_interface_address (vm, sw_if_index,
-					     &radv_info->link_local_address,
-					     128, 1 /* is_del */ );
+      pfx.ilp_addr = radv_info->link_local_address;
+      ip6_ll_table_entry_delete (&pfx);
 
-      if (!error)
-	{
-	  /* add the new one */
-	  error = ip6_add_del_interface_address (vm, sw_if_index,
-						 address, 128,
-						 0 /* is_del */ );
+      pfx.ilp_addr = *address;
+      ip6_ll_table_entry_update (&pfx, FIB_ROUTE_PATH_LOCAL);
 
-	  if (!error)
-	    {
-	      radv_info->link_local_address = *address;
-	    }
-	}
+      radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
+      radv_info->link_local_address = *address;
     }
   else
     {
@@ -4478,50 +4468,6 @@
   return error;
 }
 
-clib_error_t *
-set_ip6_link_local_address_cmd (vlib_main_t * vm,
-				unformat_input_t * input,
-				vlib_cli_command_t * cmd)
-{
-  vnet_main_t *vnm = vnet_get_main ();
-  clib_error_t *error = 0;
-  u32 sw_if_index;
-  ip6_address_t ip6_addr;
-
-  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
-    {
-      /* get the rest of the command */
-      while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
-	{
-	  if (unformat (input, "%U", unformat_ip6_address, &ip6_addr))
-	    break;
-	  else
-	    return (unformat_parse_error (input));
-	}
-    }
-  error = set_ip6_link_local_address (vm, sw_if_index, &ip6_addr);
-  return error;
-}
-
-/*?
- * This command is used to assign an IPv6 Link-local address to an
- * interface. This command will enable IPv6 on an interface if it
- * is not already enabled. Use the '<em>show ip6 interface</em>' command
- * to display the assigned Link-local address.
- *
- * @cliexpar
- * Example of how to assign an IPv6 Link-local address to an interface:
- * @cliexcmd{set ip6 link-local address GigabitEthernet2/0/0 FE80::AB8}
-?*/
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (set_ip6_link_local_address_command, static) =
-{
-  .path = "set ip6 link-local address",
-  .short_help = "set ip6 link-local address <interface> <ip6-address>",
-  .function = set_ip6_link_local_address_cmd,
-};
-/* *INDENT-ON* */
-
 /**
  * @brief callback when an interface address is added or deleted
  */
diff --git a/src/vnet/ip/ip6_neighbor.h b/src/vnet/ip/ip6_neighbor.h
index 3256ba7..e273a10 100644
--- a/src/vnet/ip/ip6_neighbor.h
+++ b/src/vnet/ip/ip6_neighbor.h
@@ -46,6 +46,11 @@
 
 extern ip6_address_t ip6_neighbor_get_link_local_address (u32 sw_if_index);
 
+extern clib_error_t *ip6_neighbor_set_link_local_address (vlib_main_t * vm,
+							  u32 sw_if_index,
+							  ip6_address_t *
+							  address);
+
 extern ip6_neighbor_t *ip6_neighbors_pool (void);
 
 extern ip6_neighbor_t *ip6_neighbors_entries (u32 sw_if_index);
diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c
index 0d98ba5..1a31b5a 100644
--- a/src/vnet/ip/ip_api.c
+++ b/src/vnet/ip/ip_api.c
@@ -100,8 +100,6 @@
 _(IP6ND_PROXY_DUMP, ip6nd_proxy_dump)                                   \
 _(IP6ND_SEND_ROUTER_SOLICITATION, ip6nd_send_router_solicitation)       \
 _(SW_INTERFACE_IP6_ENABLE_DISABLE, sw_interface_ip6_enable_disable )    \
-_(SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS, 				\
-  sw_interface_ip6_set_link_local_address)				\
 _(IP_CONTAINER_PROXY_ADD_DEL, ip_container_proxy_add_del)               \
 _(IP_CONTAINER_PROXY_DUMP, ip_container_proxy_dump)                     \
 _(IOAM_ENABLE, ioam_enable)                                             \
@@ -1825,38 +1823,6 @@
   REPLY_MACRO (VL_API_SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY);
 }
 
-static void
-  vl_api_sw_interface_ip6_set_link_local_address_t_handler
-  (vl_api_sw_interface_ip6_set_link_local_address_t * mp)
-{
-  vlib_main_t *vm = vlib_get_main ();
-  vl_api_sw_interface_ip6_set_link_local_address_reply_t *rmp;
-  int rv = 0;
-  clib_error_t *error;
-  vnet_main_t *vnm = vnet_get_main ();
-
-  vnm->api_errno = 0;
-
-  VALIDATE_SW_IF_INDEX (mp);
-
-  error = set_ip6_link_local_address (vm,
-				      ntohl (mp->sw_if_index),
-				      (ip6_address_t *) mp->address);
-  if (error)
-    {
-      clib_error_report (error);
-      rv = VNET_API_ERROR_UNSPECIFIED;
-    }
-  else
-    {
-      rv = vnm->api_errno;
-    }
-
-  BAD_SW_IF_INDEX_LABEL;
-
-  REPLY_MACRO (VL_API_SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY);
-}
-
 void
 vl_mfib_signal_send_one (vl_api_registration_t * reg,
 			 u32 context, const mfib_signal_t * mfs)