fib: Reload the adj after possible realloc (VPP-1822)
[vpp.git] / src / vnet / adj / adj_nbr.c
index 3f73ff9..9e990e0 100644 (file)
@@ -221,12 +221,12 @@ adj_nbr_add_or_lock (fib_protocol_t nh_proto,
                     u32 sw_if_index)
 {
     adj_index_t adj_index;
-    ip_adjacency_t *adj;
 
     adj_index = adj_nbr_find(nh_proto, link_type, nh_addr, sw_if_index);
 
     if (ADJ_INDEX_INVALID == adj_index)
     {
+        ip_adjacency_t *adj;
        vnet_main_t *vnm;
 
        vnm = vnet_get_main();
@@ -256,6 +256,7 @@ adj_nbr_add_or_lock (fib_protocol_t nh_proto,
        adj_lock(adj_index);
     }
 
+    adj_delegate_adj_created(adj_get(adj_index));
     return (adj_index);
 }
 
@@ -284,6 +285,8 @@ adj_nbr_add_or_lock_w_rewrite (fib_protocol_t nh_proto,
                           ADJ_NBR_REWRITE_FLAG_COMPLETE,
                           rewrite);
 
+    adj_delegate_adj_created(adj_get(adj_index));
+
     return (adj_index);
 }
 
@@ -291,7 +294,7 @@ adj_nbr_add_or_lock_w_rewrite (fib_protocol_t nh_proto,
  * adj_nbr_update_rewrite
  *
  * Update the adjacency's rewrite string. A NULL string implies the
- * rewirte is reset (i.e. when ARP/ND etnry is gone).
+ * rewrite is reset (i.e. when ARP/ND entry is gone).
  * NB: the adj being updated may be handling traffic in the DP.
  */
 void
@@ -333,7 +336,7 @@ adj_nbr_update_rewrite (adj_index_t adj_index,
  * adj_nbr_update_rewrite_internal
  *
  * Update the adjacency's rewrite string. A NULL string implies the
- * rewirte is reset (i.e. when ARP/ND etnry is gone).
+ * rewrite is reset (i.e. when ARP/ND entry is gone).
  * NB: the adj being updated may be handling traffic in the DP.
  */
 void
@@ -344,7 +347,7 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
                                 u8 *rewrite)
 {
     ip_adjacency_t *walk_adj;
-    adj_index_t walk_ai;
+    adj_index_t walk_ai, ai;
     vlib_main_t * vm;
     u32 old_next;
     int do_walk;
@@ -352,12 +355,12 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
     vm = vlib_get_main();
     old_next = adj->lookup_next_index;
 
-    walk_ai = adj_get_index(adj);
+    ai = walk_ai = adj_get_index(adj);
     if (VNET_LINK_MPLS == adj->ia_link)
     {
         /*
          * The link type MPLS has no children in the control plane graph, it only
-         * has children in the data-palne graph. The backwalk is up the former.
+         * has children in the data-plane graph. The backwalk is up the former.
          * So we need to walk from its IP cousin.
          */
         walk_ai = adj_nbr_find(adj->ia_nh_proto,
@@ -394,9 +397,9 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
      * lock the adjacencies that are affected by updates this walk will provoke.
      * Since the aim of the walk is to update children to link to a different
      * DPO, this adj will no longer be in use and its lock count will drop to 0.
-     * We don't want it to be deleted as part of this endevour.
+     * We don't want it to be deleted as part of this endeavour.
      */
-    adj_lock(adj_get_index(adj));
+    adj_lock(ai);
     adj_lock(walk_ai);
 
     /*
@@ -407,7 +410,7 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
      * ideally we would only want to suspend forwarding via this adj whilst we
      * do this, but we do not have that level of granularity - it's suspend all
      * worker threads or nothing.
-     * The other chioces are:
+     * The other choices are:
      *  - to mark the adj down and back walk so child load-balances drop this adj
      *    from the set.
      *  - update the next_node index of this adj to point to error-drop
@@ -418,7 +421,7 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
      * node. So from the options above, updating the next_node of the adj to
      * be drop will work, but it relies on each graph node v4/v6/mpls, rewrite/
      * arp/midchain always be valid w.r.t. a mis-match of adj type and node type
-     * (i.e. a rewrite adj in the arp node). This is not enforcable. Getting it
+     * (i.e. a rewrite adj in the arp node). This is not enforceable. Getting it
      * wrong will lead to hard to find bugs since its a race condition. So we
      * choose the more reliable method of updating the children to use the drop,
      * then switching adj's type, then updating the children again. Did I mention
@@ -440,7 +443,7 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
        fib_node_back_walk_ctx_t bw_ctx = {
            .fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_DOWN,
             /*
-             * force this walk to be synchrous. if we don't and a node in the graph
+             * force this walk to be synchronous. if we don't and a node in the graph
              * (a heavily shared path-list) chooses to back-ground the walk (make it
              * async) then it will pause and we will do the adj update below, before
              * all the children are updated. not good.
@@ -461,6 +464,7 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
     vlib_worker_thread_barrier_sync(vm);
 
     adj->lookup_next_index = adj_next_index;
+    adj->ia_node_index = this_node;
 
     if (NULL != rewrite)
     {
@@ -484,7 +488,7 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
                                                         next_node);
 
     /*
-     * done with the rewirte update - let the workers loose.
+     * done with the rewrite update - let the workers loose.
      */
     vlib_worker_thread_barrier_release(vm);
 
@@ -507,10 +511,11 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
      */
     if (do_walk)
     {
+        walk_adj = adj_get(walk_ai);
         walk_adj->ia_flags &= ~ADJ_FLAG_SYNC_WALK_ACTIVE;
     }
 
-    adj_unlock(adj_get_index(adj));
+    adj_unlock(ai);
     adj_unlock(walk_ai);
 }
 
@@ -518,12 +523,13 @@ typedef struct adj_db_count_ctx_t_ {
     u64 count;
 } adj_db_count_ctx_t;
 
-static void
+static int
 adj_db_count (BVT(clib_bihash_kv) * kvp,
              void *arg)
 {
     adj_db_count_ctx_t * ctx = arg;
     ctx->count++;
+    return (BIHASH_WALK_CONTINUE);
 }
 
 u32
@@ -560,14 +566,16 @@ typedef struct adj_walk_ctx_t_
     void *awc_ctx;
 } adj_walk_ctx_t;
 
-static void
+static int
 adj_nbr_walk_cb (BVT(clib_bihash_kv) * kvp,
                 void *arg)
 {
     adj_walk_ctx_t *ctx = arg;
 
     // FIXME: can't stop early...
-    ctx->awc_cb(kvp->value, ctx->awc_ctx);
+    if (ADJ_WALK_RC_STOP == ctx->awc_cb(kvp->value, ctx->awc_ctx))
+        return (BIHASH_WALK_STOP);
+    return (BIHASH_WALK_CONTINUE);
 }
 
 void
@@ -660,15 +668,17 @@ adj_nbr_walk_nh (u32 sw_if_index,
     if (!ADJ_NBR_ITF_OK(adj_nh_proto, sw_if_index))
        return;
 
-    vnet_link_t linkt;
-    adj_index_t ai;
-
-    FOR_EACH_VNET_LINK(linkt)
+    switch (adj_nh_proto)
     {
-        ai = adj_nbr_find (FIB_PROTOCOL_IP4, linkt, nh, sw_if_index);
-
-        if (INDEX_INVALID != ai)
-            cb(ai, ctx);
+    case FIB_PROTOCOL_IP4:
+        adj_nbr_walk_nh4(sw_if_index, &nh->ip4, cb, ctx);
+        break; 
+    case FIB_PROTOCOL_IP6:
+        adj_nbr_walk_nh6(sw_if_index, &nh->ip6, cb, ctx);
+        break;
+    case FIB_PROTOCOL_MPLS:
+        ASSERT(0);
+        break;
     }
 }
 
@@ -823,12 +833,15 @@ adj_nbr_interface_delete_one (adj_index_t ai,
     };
     ip_adjacency_t *adj;
 
+    adj_lock(ai);
+
     adj = adj_get(ai);
 
     adj->ia_flags |= ADJ_FLAG_SYNC_WALK_ACTIVE;
     fib_walk_sync(FIB_NODE_TYPE_ADJ, ai, &bw_ctx);
     adj->ia_flags &= ~ADJ_FLAG_SYNC_WALK_ACTIVE;
 
+    adj_unlock(ai);
     return (ADJ_WALK_RC_CONTINUE);
 }