fib: adjacency midchain teardown (VPP-1841)
[vpp.git] / src / vnet / adj / adj_midchain.c
index a4b29c8..88648fe 100644 (file)
@@ -30,6 +30,8 @@
 static u32 adj_midchain_tx_feature_node[VNET_LINK_NUM];
 static u32 adj_midchain_tx_no_count_feature_node[VNET_LINK_NUM];
 
+static u32 *adj_midchain_feat_count_per_sw_if_index[VNET_LINK_NUM];
+
 /**
  * @brief Trace data for packets traversing the midchain tx node
  */
@@ -69,22 +71,13 @@ adj_midchain_tx_inline (vlib_main_t * vm,
 
        while (n_left_from >= 8 && n_left_to_next > 4)
        {
+           const ip_adjacency_t *adj0, *adj1, *adj2, *adj3;
+           const dpo_id_t *dpo0, *dpo1, *dpo2, *dpo3;
+           vlib_buffer_t * b0, *b1, *b2, *b3;
            u32 bi0, adj_index0, next0;
-           const ip_adjacency_t * adj0;
-           const dpo_id_t *dpo0;
-           vlib_buffer_t * b0;
            u32 bi1, adj_index1, next1;
-           const ip_adjacency_t * adj1;
-           const dpo_id_t *dpo1;
-           vlib_buffer_t * b1;
            u32 bi2, adj_index2, next2;
-           const ip_adjacency_t * adj2;
-           const dpo_id_t *dpo2;
-           vlib_buffer_t * b2;
            u32 bi3, adj_index3, next3;
-           const ip_adjacency_t * adj3;
-           const dpo_id_t *dpo3;
-           vlib_buffer_t * b3;
 
            /* Prefetch next iteration. */
            {
@@ -454,6 +447,30 @@ adj_nbr_midchain_get_feature_node (ip_adjacency_t *adj)
     return (adj_midchain_tx_feature_node[adj->ia_link]);
 }
 
+/**
+ * adj_midchain_setup
+ *
+ * Setup the adj as a mid-chain
+ */
+void
+adj_midchain_teardown (ip_adjacency_t *adj)
+{
+    u32 feature_index;
+    u8 arc_index;
+
+    dpo_reset(&adj->sub_type.midchain.next_dpo);
+
+    arc_index = adj_midchain_get_feature_arc_index_for_link_type (adj);
+    feature_index = adj_nbr_midchain_get_feature_node(adj);
+
+    if (0 == --adj_midchain_feat_count_per_sw_if_index[adj->ia_link][adj->rewrite_header.sw_if_index])
+    {
+        vnet_feature_enable_disable_with_index (arc_index, feature_index,
+                                                adj->rewrite_header.sw_if_index,
+                                                0, 0, 0);
+    }
+}
+
 /**
  * adj_midchain_setup
  *
@@ -482,9 +499,15 @@ adj_midchain_setup (adj_index_t adj_index,
     feature_index = adj_nbr_midchain_get_feature_node(adj);
     tx_node = adj_nbr_midchain_get_tx_node(adj);
 
-    vnet_feature_enable_disable_with_index (arc_index, feature_index,
-                                           adj->rewrite_header.sw_if_index,
-                                           1 /* enable */, 0, 0);
+    vec_validate (adj_midchain_feat_count_per_sw_if_index[adj->ia_link],
+                  adj->rewrite_header.sw_if_index);
+
+    if (0 == adj_midchain_feat_count_per_sw_if_index[adj->ia_link][adj->rewrite_header.sw_if_index]++)
+    {
+        vnet_feature_enable_disable_with_index (arc_index, feature_index,
+                                                adj->rewrite_header.sw_if_index,
+                                                1 /* enable */, 0, 0);
+    }
 
     /*
      * stack the midchain on the drop so it's ready to forward in the adj-midchain-tx.
@@ -502,7 +525,7 @@ adj_midchain_setup (adj_index_t adj_index,
  * adj_nbr_midchain_update_rewrite
  *
  * Update the adjacency's rewrite string. A NULL string implies the
- * rewrite 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
@@ -519,22 +542,17 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
     adj = adj_get(adj_index);
 
     /*
-     * one time only update. since we don't support chainging the tunnel
+     * one time only update. since we don't support changing the tunnel
      * src,dst, this is all we need.
      */
-    ASSERT((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP) ||
-           (adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN) ||
-           (adj->lookup_next_index == IP_LOOKUP_NEXT_BCAST));
-
-    /*
-     * tunnels can always provide a rewrite.
-     */
-    ASSERT(NULL != rewrite);
-
-    adj_midchain_setup(adj_index, fixup, fixup_data, flags);
+    if (adj->lookup_next_index != IP_LOOKUP_NEXT_MIDCHAIN &&
+        adj->lookup_next_index != IP_LOOKUP_NEXT_MCAST_MIDCHAIN)
+    {
+        adj_midchain_setup(adj_index, fixup, fixup_data, flags);
+    }
 
     /*
-     * update the rewirte with the workers paused.
+     * update the rewrite with the workers paused.
      */
     adj_nbr_update_rewrite_internal(adj,
                                    IP_LOOKUP_NEXT_MIDCHAIN,
@@ -685,7 +703,7 @@ adj_ndr_midchain_recursive_loop_detect (adj_index_t ai,
         {
             /*
              * The entry this midchain links to is already in the set
-             * of visisted entries, this is a loop
+             * of visited entries, this is a loop
              */
             adj->ia_flags |= ADJ_FLAG_MIDCHAIN_LOOPED;
             return (1);
@@ -704,6 +722,8 @@ format_adj_midchain (u8* s, va_list *ap)
     ip_adjacency_t * adj = adj_get(index);
 
     s = format (s, "%U", format_vnet_link, adj->ia_link);
+    if (adj->rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)
+        s = format(s, " [features]");
     s = format (s, " via %U",
                format_ip46_address, &adj->sub_type.nbr.next_hop,
                adj_proto_to_46(adj->ia_nh_proto));