ip-neighbor: Replace feature for the ip-neighbor data-base
[vpp.git] / src / vnet / ip-neighbor / ip_neighbor.c
index 6af76d2..5b18473 100644 (file)
@@ -99,6 +99,12 @@ ip_neighbor_get_index (const ip_neighbor_t * ipn)
   return (ipn - ip_neighbor_pool);
 }
 
+static void
+ip_neighbor_touch (ip_neighbor_t * ipn)
+{
+  ipn->ipn_flags &= ~IP_NEIGHBOR_FLAG_STALE;
+}
+
 static bool
 ip_neighbor_is_dynamic (const ip_neighbor_t * ipn)
 {
@@ -145,6 +151,7 @@ ip_neighbor_refresh (ip_neighbor_t * ipn)
    * list is time sorted, newest first */
   ip_neighbor_elt_t *elt, *head;
 
+  ip_neighbor_touch (ipn);
   ipn->ipn_time_last_updated = vlib_time_now (vlib_get_main ());
   ipn->ipn_n_probes = 0;
 
@@ -473,6 +480,8 @@ ip_neighbor_add (const ip46_address_t * ip,
                       format_ip_neighbor_flags, flags, format_mac_address_t,
                       mac);
 
+      ip_neighbor_touch (ipn);
+
       /* Refuse to over-write static neighbor entry. */
       if (!(flags & IP_NEIGHBOR_FLAG_STATIC) &&
          (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STATIC))
@@ -1177,6 +1186,60 @@ ip_neighbor_flush (ip46_type_t type, u32 sw_if_index)
   vec_free (ipnis);
 }
 
+static walk_rc_t
+ip_neighbor_mark_one (index_t ipni, void *ctx)
+{
+  ip_neighbor_t *ipn;
+
+  ipn = ip_neighbor_get (ipni);
+
+  ipn->ipn_flags |= IP_NEIGHBOR_FLAG_STALE;
+
+  return (WALK_CONTINUE);
+}
+
+void
+ip_neighbor_mark (ip46_type_t type)
+{
+  ip_neighbor_walk (type, ~0, ip_neighbor_mark_one, NULL);
+}
+
+typedef struct ip_neighbor_sweep_ctx_t_
+{
+  index_t *ipnsc_stale;
+} ip_neighbor_sweep_ctx_t;
+
+static walk_rc_t
+ip_neighbor_sweep_one (index_t ipni, void *arg)
+{
+  ip_neighbor_sweep_ctx_t *ctx = arg;
+  ip_neighbor_t *ipn;
+
+  ipn = ip_neighbor_get (ipni);
+
+  if (ipn->ipn_flags & IP_NEIGHBOR_FLAG_STALE)
+    {
+      vec_add1 (ctx->ipnsc_stale, ipni);
+    }
+
+  return (WALK_CONTINUE);
+}
+
+void
+ip_neighbor_sweep (ip46_type_t type)
+{
+  ip_neighbor_sweep_ctx_t ctx = { };
+  index_t *ipni;
+
+  ip_neighbor_walk (type, ~0, ip_neighbor_sweep_one, &ctx);
+
+  vec_foreach (ipni, ctx.ipnsc_stale)
+  {
+    ip_neighbor_free (ip_neighbor_get (*ipni));
+  }
+  vec_free (ctx.ipnsc_stale);
+}
+
 /*
  * Remove any arp entries associated with the specified interface
  */
@@ -1402,22 +1465,24 @@ static ip_neighbor_age_state_t
 ip_neighbour_age_out (index_t ipni, f64 now, f64 * wait)
 {
   ip_neighbor_t *ipn;
-  f64 ttl;
+  u32 ipndb_age;
+  u32 ttl;
 
   ipn = ip_neighbor_get (ipni);
+  ipndb_age = ip_neighbor_db[ipn->ipn_key->ipnk_type].ipndb_age;
   ttl = now - ipn->ipn_time_last_updated;
-  *wait = IP_NEIGHBOR_PROCESS_SLEEP_LONG;
+  *wait = ipndb_age;
 
-  if (ttl > ip_neighbor_db[ipn->ipn_key->ipnk_type].ipndb_age)
+  if (ttl > ipndb_age)
     {
       IP_NEIGHBOR_DBG ("aged: %U @%f - %f > %d",
                       format_ip_neighbor, ipni, now,
-                      ipn->ipn_time_last_updated,
-                      ip_neighbor_db[ipn->ipn_key->ipnk_type].ipndb_age);
+                      ipn->ipn_time_last_updated, ipndb_age);
       if (ipn->ipn_n_probes > 2)
        {
          /* 3 strikes and yea-re out */
          IP_NEIGHBOR_DBG ("dead: %U", format_ip_neighbor, ipni);
+         *wait = 1;
          return (IP_NEIGHBOR_AGE_DEAD);
        }
       else
@@ -1436,7 +1501,8 @@ ip_neighbour_age_out (index_t ipni, f64 now, f64 * wait)
     }
   else
     {
-      *wait = ttl;
+      /* here we are sure that ttl <= ipndb_age */
+      *wait = ipndb_age - ttl + 1;
       return (IP_NEIGHBOR_AGE_ALIVE);
     }
 
@@ -1481,7 +1547,7 @@ ip_neighbor_age_loop (vlib_main_t * vm,
            ip_neighbor_elt_t *elt, *head;
            f64 wait;
 
-           timeout = 1e5;
+           timeout = ip_neighbor_db[type].ipndb_age;
            head = pool_elt_at_index (ip_neighbor_elt_pool,
                                      ip_neighbor_list_head[type]);
 
@@ -1498,6 +1564,7 @@ ip_neighbor_age_loop (vlib_main_t * vm,
 
             if (IP_NEIGHBOR_AGE_ALIVE == res) {
               /* the oldest neighbor has not yet expired, go back to sleep */
+              timeout = clib_min (wait, timeout);
               break;
             }
             else if (IP_NEIGHBOR_AGE_DEAD == res) {
@@ -1525,13 +1592,16 @@ ip_neighbor_age_loop (vlib_main_t * vm,
 
            head = pool_elt_at_index (ip_neighbor_elt_pool,
                                      ip_neighbor_list_head[type]);
-           elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head);
+           /* no neighbors yet */
+           if (clib_llist_is_empty (ip_neighbor_elt_pool, ipne_anchor, head))
+             {
+               timeout = ip_neighbor_db[type].ipndb_age;
+               break;
+             }
 
            /* poke the oldset neighbour for aging, which returns how long we sleep for */
-           if (IP_NEIGHBOR_AGE_PROBE ==
-               ip_neighbour_age_out (elt->ipne_index, now, &timeout))
-             /* we probed for the oldest entry, sleep for a short time to get to the next */
-             timeout = 0.01;
+           elt = clib_llist_prev (ip_neighbor_elt_pool, ipne_anchor, head);
+           ip_neighbour_age_out (elt->ipne_index, now, &timeout);
            break;
          }
        }