ip: Replace Sematics for Interface IP addresses
[vpp.git] / src / vnet / ip / ip4_forward.c
index 7471a00..acff66d 100644 (file)
@@ -680,7 +680,7 @@ ip4_add_del_interface_address_internal (vlib_main_t * vm,
   ip4_main_t *im = &ip4_main;
   ip_lookup_main_t *lm = &im->lookup_main;
   clib_error_t *error = 0;
-  u32 if_address_index, elts_before;
+  u32 if_address_index;
   ip4_address_fib_t ip4_af, *addr_fib = 0;
 
   /* local0 interface doesn't support IP addressing  */
@@ -720,6 +720,7 @@ ip4_add_del_interface_address_internal (vlib_main_t * vm,
                    ip4_address_t * x =
                      ip_interface_address_get_address
                      (&im->lookup_main, ia);
+
                    if (ip4_destination_matches_route
                        (im, address, x, ia->address_length) ||
                        ip4_destination_matches_route (im,
@@ -733,11 +734,18 @@ ip4_add_del_interface_address_internal (vlib_main_t * vm,
                           (x->as_u32 != address->as_u32))
                         continue;
 
+                       if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
+                         /* if the address we're comparing against is stale
+                          * then the CP has not added this one back yet, maybe
+                          * it never will, so we have to assume it won't and
+                          * ignore it. if it does add it back, then it will fail
+                          * because this one is now present */
+                         continue;
+
                       /* error if the length or intf was different */
-                       vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
+                       vnm->api_errno = VNET_API_ERROR_ADDRESS_IN_USE;
 
-                       return
-                         clib_error_create
+                       error = clib_error_create
                          ("failed to add %U on %U which conflicts with %U for interface %U",
                           format_ip4_address_and_length, address,
                           address_length,
@@ -747,6 +755,7 @@ ip4_add_del_interface_address_internal (vlib_main_t * vm,
                           ia->address_length,
                           format_vnet_sw_if_index_name, vnm,
                           sif->sw_if_index);
+                       goto done;
                      }
                  }));
             }
@@ -754,10 +763,70 @@ ip4_add_del_interface_address_internal (vlib_main_t * vm,
     }
   /* *INDENT-ON* */
 
-  elts_before = pool_elts (lm->if_address_pool);
+  if_address_index = ip_interface_address_find (lm, addr_fib, address_length);
+
+  if (is_del)
+    {
+      if (~0 == if_address_index)
+       {
+         vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
+         error = clib_error_create ("%U not found for interface %U",
+                                    lm->format_address_and_length,
+                                    addr_fib, address_length,
+                                    format_vnet_sw_if_index_name, vnm,
+                                    sw_if_index);
+         goto done;
+       }
+
+      ip_interface_address_del (lm, if_address_index, addr_fib);
+    }
+  else
+    {
+      if (~0 != if_address_index)
+       {
+         ip_interface_address_t *ia;
+
+         ia = pool_elt_at_index (lm->if_address_pool, if_address_index);
+
+         if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
+           {
+             if (ia->sw_if_index == sw_if_index)
+               {
+                 /* re-adding an address during the replace action.
+                  * consdier this the update. clear the flag and
+                  * we're done */
+                 ia->flags &= ~IP_INTERFACE_ADDRESS_FLAG_STALE;
+                 goto done;
+               }
+             else
+               {
+                 /* The prefix is moving from one interface to another.
+                  * delete the stale and add the new */
+                 ip4_add_del_interface_address_internal (vm,
+                                                         ia->sw_if_index,
+                                                         address,
+                                                         address_length, 1);
+                 ia = NULL;
+                 error = ip_interface_address_add (lm, sw_if_index,
+                                                   addr_fib, address_length,
+                                                   &if_address_index);
+               }
+           }
+         else
+           {
+             vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
+             error = clib_error_create
+               ("Prefix %U already found on interface %U",
+                lm->format_address_and_length, addr_fib, address_length,
+                format_vnet_sw_if_index_name, vnm, ia->sw_if_index);
+           }
+       }
+      else
+       error = ip_interface_address_add (lm, sw_if_index,
+                                         addr_fib, address_length,
+                                         &if_address_index);
+    }
 
-  error = ip_interface_address_add_del
-    (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
   if (error)
     goto done;
 
@@ -778,14 +847,10 @@ ip4_add_del_interface_address_internal (vlib_main_t * vm,
                                  (lm->if_address_pool, if_address_index));
     }
 
-  /* If pool did not grow/shrink: add duplicate address. */
-  if (elts_before != pool_elts (lm->if_address_pool))
-    {
-      ip4_add_del_interface_address_callback_t *cb;
-      vec_foreach (cb, im->add_del_interface_address_callbacks)
-       cb->function (im, cb->function_opaque, sw_if_index,
-                     address, address_length, if_address_index, is_del);
-    }
+  ip4_add_del_interface_address_callback_t *cb;
+  vec_foreach (cb, im->add_del_interface_address_callbacks)
+    cb->function (im, cb->function_opaque, sw_if_index,
+                 address, address_length, if_address_index, is_del);
 
 done:
   vec_free (addr_fib);
@@ -903,20 +968,6 @@ VNET_FEATURE_INIT (ip4_inacl, static) =
 {
   .arc_name = "ip4-unicast",
   .node_name = "ip4-inacl",
-  .runs_before = VNET_FEATURES ("ip4-source-check-via-rx"),
-};
-
-VNET_FEATURE_INIT (ip4_source_check_1, static) =
-{
-  .arc_name = "ip4-unicast",
-  .node_name = "ip4-source-check-via-rx",
-  .runs_before = VNET_FEATURES ("ip4-source-check-via-any"),
-};
-
-VNET_FEATURE_INIT (ip4_source_check_2, static) =
-{
-  .arc_name = "ip4-unicast",
-  .node_name = "ip4-source-check-via-any",
   .runs_before = VNET_FEATURES ("ip4-policer-classify"),
 };
 
@@ -1990,10 +2041,7 @@ ip4_ttl_inc (vlib_buffer_t * b, ip4_header_t * ip)
   i32 ttl;
   u32 checksum;
   if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
-    {
-      b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
-      return;
-    }
+    return;
 
   ttl = ip->ttl;
 
@@ -2016,10 +2064,7 @@ ip4_ttl_and_checksum_check (vlib_buffer_t * b, ip4_header_t * ip, u16 * next,
   i32 ttl;
   u32 checksum;
   if (PREDICT_FALSE (b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED))
-    {
-      b->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
-      return;
-    }
+    return;
 
   ttl = ip->ttl;
 
@@ -2181,7 +2226,9 @@ ip4_rewrite_inline_with_gso (vlib_main_t * vm,
                                    tx_sw_if_index0, &next_index, b[0]);
          next[0] = next_index;
          if (is_midchain)
-           calc_checksums (vm, b[0]);
+           vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
+                                       0 /* is_ip6 */ ,
+                                       0 /* with gso */ );
        }
       else
        {
@@ -2203,7 +2250,9 @@ ip4_rewrite_inline_with_gso (vlib_main_t * vm,
                                    tx_sw_if_index1, &next_index, b[1]);
          next[1] = next_index;
          if (is_midchain)
-           calc_checksums (vm, b[1]);
+           vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
+                                       0 /* is_ip6 */ ,
+                                       0 /* with gso */ );
        }
       else
        {
@@ -2347,7 +2396,9 @@ ip4_rewrite_inline_with_gso (vlib_main_t * vm,
          next[0] = next_index;
 
          if (is_midchain)
-           calc_checksums (vm, b[0]);
+           vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
+                                       0 /* is_ip6 */ ,
+                                       0 /* with gso */ );
 
          /* Guess we are only writing on simple Ethernet header. */
          vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
@@ -2446,7 +2497,9 @@ ip4_rewrite_inline_with_gso (vlib_main_t * vm,
 
          if (is_midchain)
            /* this acts on the packet that is about to be encapped */
-           calc_checksums (vm, b[0]);
+           vnet_calc_checksums_inline (vm, b[0], 1 /* is_ip4 */ ,
+                                       0 /* is_ip6 */ ,
+                                       0 /* with gso */ );
 
          /* Guess we are only writing on simple Ethernet header. */
          vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));