ipip: Multi-point interface
[vpp.git] / src / vnet / adj / adj_nbr.c
index ff53529..7531326 100644 (file)
@@ -18,6 +18,8 @@
 #include <vnet/ethernet/arp_packet.h>
 #include <vnet/fib/fib_walk.h>
 
+#include <vppinfra/bihash_24_8.h>
+
 /*
  * Vector Hash tables of neighbour (traditional) adjacencies
  *  Key: interface(for the vector index), address (and its proto),
@@ -195,6 +197,8 @@ adj_nbr_alloc (fib_protocol_t nh_proto,
     adj->ia_link = link_type;
     adj->ia_nh_proto = nh_proto;
     adj->rewrite_header.sw_if_index = sw_if_index;
+    vnet_rewrite_update_mtu(vnet_get_main(), adj->ia_link,
+                            &adj->rewrite_header);
 
     adj_nbr_evaluate_feature (adj_get_index(adj));
     return (adj);
@@ -217,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();
@@ -252,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);
 }
 
@@ -263,33 +268,33 @@ adj_nbr_add_or_lock_w_rewrite (fib_protocol_t nh_proto,
                               u8 *rewrite)
 {
     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)
     {
-       adj = adj_nbr_alloc(nh_proto, link_type, nh_addr, sw_if_index);
+        ip_adjacency_t *adj;
+
+        adj = adj_nbr_alloc(nh_proto, link_type, nh_addr, sw_if_index);
        adj->rewrite_header.sw_if_index = sw_if_index;
-    }
-    else
-    {
-        adj = adj_get(adj_index);
+        adj_index = adj_get_index(adj);
     }
 
-    adj_lock(adj_get_index(adj));
-    adj_nbr_update_rewrite(adj_get_index(adj),
+    adj_lock(adj_index);
+    adj_nbr_update_rewrite(adj_index,
                           ADJ_NBR_REWRITE_FLAG_COMPLETE,
                           rewrite);
 
-    return (adj_get_index(adj));
+    adj_delegate_adj_created(adj_get(adj_index));
+
+    return (adj_index);
 }
 
 /**
  * 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
@@ -331,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
@@ -342,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;
@@ -350,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,
@@ -392,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);
 
     /*
@@ -405,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
@@ -416,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
@@ -438,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.
@@ -459,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)
     {
@@ -482,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);
 
@@ -505,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);
 }
 
@@ -516,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
@@ -558,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
@@ -658,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;
     }
 }
 
@@ -821,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);
 }
 
@@ -892,15 +907,19 @@ adj_nbr_show (vlib_main_t * vm,
              vlib_cli_command_t * cmd)
 {
     adj_index_t ai = ADJ_INDEX_INVALID;
+    ip46_address_t nh = ip46_address_initializer;
     u32 sw_if_index = ~0;
 
     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
-       if (unformat (input, "%d", &ai))
+       if (unformat (input, "%U",
+                      unformat_vnet_sw_interface, vnet_get_main(),
+                      &sw_if_index))
            ;
        else if (unformat (input, "%U",
-                          unformat_vnet_sw_interface, vnet_get_main(),
-                          &sw_if_index))
+                          unformat_ip46_address, &nh, IP46_TYPE_ANY))
+           ;
+       else if (unformat (input, "%d", &ai))
            ;
        else
            break;
@@ -917,12 +936,24 @@ adj_nbr_show (vlib_main_t * vm,
     {
        fib_protocol_t proto;
 
-       for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
-       {
-           adj_nbr_walk(sw_if_index, proto,
-                        adj_nbr_show_one,
-                        vm);
-       }
+        if (ip46_address_is_zero(&nh))
+        {
+            for (proto = FIB_PROTOCOL_IP4; proto <= FIB_PROTOCOL_IP6; proto++)
+            {
+                adj_nbr_walk(sw_if_index, proto,
+                             adj_nbr_show_one,
+                             vm);
+            }
+        }
+        else
+        {
+            proto = (ip46_address_is_ip4(&nh) ?
+                     FIB_PROTOCOL_IP4 :
+                     FIB_PROTOCOL_IP6);
+            adj_nbr_walk_nh(sw_if_index, proto, &nh,
+                            adj_nbr_show_one,
+                            vm);
+        }
     }
     else
     {