fib: Don't use [midchain] adjacencies to change an interface's feature arc 04/34004/5
authorNeale Ranns <neale@graphiant.com>
Fri, 8 Oct 2021 07:30:47 +0000 (07:30 +0000)
committerBeno�t Ganne <bganne@cisco.com>
Fri, 19 Nov 2021 14:41:28 +0000 (14:41 +0000)
Type: fix

Using the adjacency to modify the interface's feature arc doesn't work, since there are potentially more than one adj per-interface.
Instead have the interface, when it is created, register what the end node of the feature arc is. This end node is then also used as the interface's tx node (i.e. it is used as the adjacency's next-node).

rename adj-midhcain-tx as 'tunnel-output', that's a bit more intuitive.

There's also a fix in config string handling to:
 1- prevent false sharing of strings when the end node of the arc is different.
 2- call registered listeners when the end node is changed

For IPSec the consequences are that one cannot provide per-adjacency behaviour using different end-nodes - this was previously done for the no-SA and an SA with no protection. These cases are no handled in the esp-encrypt node.

Signed-off-by: Neale Ranns <neale@graphiant.com>
Change-Id: If3a83d03a3000f28820d9a9cb4101d244803d084

30 files changed:
src/plugins/lisp/lisp-gpe/interface.c
src/plugins/lisp/lisp-gpe/lisp_gpe_adjacency.c
src/plugins/lisp/lisp-gpe/lisp_gpe_sub_interface.c
src/plugins/pppoe/pppoe.c
src/plugins/wireguard/wireguard_if.c
src/vnet/adj/adj.h
src/vnet/adj/adj_internal.h
src/vnet/adj/adj_midchain.c
src/vnet/adj/adj_midchain_node.c
src/vnet/adj/adj_nbr.c
src/vnet/config.c
src/vnet/config.h
src/vnet/feature/feature.c
src/vnet/feature/feature.h
src/vnet/gre/gre.c
src/vnet/gre/interface.c
src/vnet/interface.c
src/vnet/interface_funcs.h
src/vnet/ipip/ipip.c
src/vnet/ipip/sixrd.c
src/vnet/ipsec/esp_encrypt.c
src/vnet/ipsec/ipsec.c
src/vnet/ipsec/ipsec.h
src/vnet/ipsec/ipsec_itf.c
src/vnet/ipsec/ipsec_itf.h
src/vnet/ipsec/ipsec_sa.h
src/vnet/ipsec/ipsec_tun.c
src/vnet/ipsec/ipsec_tun.h
src/vnet/mpls/mpls_tunnel.c
test/test_ipsec_tun_if_esp.py

index d73471d..f1c49ea 100644 (file)
@@ -88,9 +88,8 @@ format_lisp_gpe_tx_trace (u8 * s, va_list * args)
  *
  * @return number of vectors in frame.
  */
-static uword
-lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
-                      vlib_frame_t * from_frame)
+VLIB_NODE_FN (lisp_tunnel_output)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
 {
   u32 n_left_from, next_index, *from, *to_next;
   lisp_gpe_main_t *lgm = &lisp_gpe_main;
@@ -122,6 +121,7 @@ lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
          n_left_to_next -= 1;
 
          b0 = vlib_get_buffer (vm, bi0);
+         b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
 
          /* Fixup the checksum and len fields in the LISP tunnel encap
           * that was applied at the midchain node */
@@ -151,6 +151,13 @@ lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
   return from_frame->n_vectors;
 }
 
+VLIB_REGISTER_NODE (lisp_tunnel_output) = {
+  .name = "lisp-tunnel-output",
+  .vector_size = sizeof (u32),
+  .format_trace = format_lisp_gpe_tx_trace,
+  .sibling_of = "tunnel-output",
+};
+
 static u8 *
 format_lisp_gpe_name (u8 * s, va_list * args)
 {
@@ -162,8 +169,6 @@ format_lisp_gpe_name (u8 * s, va_list * args)
 VNET_DEVICE_CLASS (lisp_gpe_device_class) = {
   .name = "LISP_GPE",
   .format_device_name = format_lisp_gpe_name,
-  .format_tx_trace = format_lisp_gpe_tx_trace,
-  .tx_function = lisp_gpe_interface_tx,
 };
 /* *INDENT-ON* */
 
index 8d20412..dd8a252 100644 (file)
@@ -317,8 +317,6 @@ lisp_gpe_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
   lgt = lisp_gpe_tunnel_get (ladj->tunnel_index);
   linkt = adj_get_link_type (ai);
   af = ADJ_FLAG_MIDCHAIN_IP_STACK;
-  if (VNET_LINK_ETHERNET == linkt)
-    af |= ADJ_FLAG_MIDCHAIN_NO_COUNT;
 
   adj_nbr_midchain_update_rewrite
     (ai, lisp_gpe_fixup, NULL, af,
index aea84a3..b40ed2e 100644 (file)
@@ -168,6 +168,8 @@ lisp_gpe_sub_interface_find_or_create_and_lock (const ip_address_t * lrloc,
       vnet_sw_interface_set_flags (vnet_get_main (),
                                   l3s->sw_if_index,
                                   VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+      vnet_set_interface_l3_output_node (vlib_get_main (), l3s->sw_if_index,
+                                        (u8 *) "lisp-tunnel-output");
 
       lisp_gpe_sub_interface_db_insert (l3s);
     }
@@ -200,6 +202,7 @@ lisp_gpe_sub_interface_unlock (index_t l3si)
 
       lisp_gpe_tenant_l3_iface_unlock (l3s->key->vni);
       vnet_sw_interface_set_flags (vnet_get_main (), l3s->sw_if_index, 0);
+      vnet_reset_interface_l3_output_node (vlib_get_main (), l3s->sw_if_index);
       vnet_delete_sub_interface (l3s->sw_if_index);
 
       lisp_gpe_sub_interface_db_remove (l3s);
index d073a94..182f93b 100644 (file)
@@ -413,6 +413,8 @@ int vnet_pppoe_add_del_session
       si->flags &= ~VNET_SW_INTERFACE_FLAG_HIDDEN;
       vnet_sw_interface_set_flags (vnm, sw_if_index,
                                   VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+      vnet_set_interface_l3_output_node (vnm->vlib_main, sw_if_index,
+                                        (u8 *) "tunnel-output");
 
       /* add reverse route for client ip */
       fib_table_entry_path_add (a->decap_fib_index, &pfx,
@@ -431,6 +433,7 @@ int vnet_pppoe_add_del_session
       t = pool_elt_at_index (pem->sessions, result.fields.session_index);
       sw_if_index = t->sw_if_index;
 
+      vnet_reset_interface_l3_output_node (vnm->vlib_main, sw_if_index);
       vnet_sw_interface_set_flags (vnm, t->sw_if_index, 0 /* down */ );
       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, t->sw_if_index);
       si->flags |= VNET_SW_INTERFACE_FLAG_HIDDEN;
index ad8f42c..64e4056 100644 (file)
@@ -315,6 +315,8 @@ wg_if_create (u32 user_instance,
 
   ip_address_copy (&wg_if->src_ip, src_ip);
   wg_if->sw_if_index = *sw_if_indexp = hi->sw_if_index;
+  vnet_set_interface_l3_output_node (vnm->vlib_main, hi->sw_if_index,
+                                    (u8 *) "tunnel-output");
 
   return 0;
 }
@@ -359,6 +361,7 @@ wg_if_delete (u32 sw_if_index)
       udp_unregister_dst_port (vlib_get_main (), wg_if->port, 0);
     }
 
+  vnet_reset_interface_l3_output_node (vnm->vlib_main, sw_if_index);
   vnet_delete_hw_interface (vnm, hw->hw_if_index);
   pool_put_index (noise_local_pool, wg_if->local_idx);
   pool_put (wg_if_pool, wg_if);
index c1922c7..860193c 100644 (file)
@@ -164,14 +164,6 @@ typedef enum adj_attr_t_
      */
     ADJ_ATTR_SYNC_WALK_ACTIVE = 0,
 
-    /**
-     * Packets TX through the midchain do not increment the interface
-     * counters. This should be used when the adj is associated with an L2
-     * interface and that L2 interface is in a bridge domain. In that case
-     * the packet will have traversed the interface's TX node, and hence have
-     * been counted, before it traverses ths midchain
-     */
-    ADJ_ATTR_MIDCHAIN_NO_COUNT,
     /**
      * When stacking midchains on a fib-entry extract the choice from the
      * load-balance returned based on an IP hash of the adj's rewrite
@@ -195,7 +187,6 @@ typedef enum adj_attr_t_
 
 #define ADJ_ATTR_NAMES {                                        \
     [ADJ_ATTR_SYNC_WALK_ACTIVE] = "walk-active",                \
-    [ADJ_ATTR_MIDCHAIN_NO_COUNT] = "midchain-no-count",         \
     [ADJ_ATTR_MIDCHAIN_IP_STACK] = "midchain-ip-stack",         \
     [ADJ_ATTR_MIDCHAIN_LOOPED] = "midchain-looped",             \
     [ADJ_ATTR_MIDCHAIN_FIXUP_IP4O4_HDR] = "midchain-ip4o4-hdr-fixup",   \
@@ -214,7 +205,6 @@ typedef enum adj_flags_t_
 {
     ADJ_FLAG_NONE = 0,
     ADJ_FLAG_SYNC_WALK_ACTIVE = (1 << ADJ_ATTR_SYNC_WALK_ACTIVE),
-    ADJ_FLAG_MIDCHAIN_NO_COUNT = (1 << ADJ_ATTR_MIDCHAIN_NO_COUNT),
     ADJ_FLAG_MIDCHAIN_IP_STACK = (1 << ADJ_ATTR_MIDCHAIN_IP_STACK),
     ADJ_FLAG_MIDCHAIN_LOOPED = (1 << ADJ_ATTR_MIDCHAIN_LOOPED),
     ADJ_FLAG_MIDCHAIN_FIXUP_IP4O4_HDR = (1 << ADJ_ATTR_MIDCHAIN_FIXUP_IP4O4_HDR),
index 3dbf7e2..6842bc4 100644 (file)
@@ -47,8 +47,7 @@
  */
 extern vlib_node_registration_t adj_nsh_midchain_node;
 extern vlib_node_registration_t adj_nsh_rewrite_node;
-extern vlib_node_registration_t adj_midchain_tx_no_count_node;
-extern vlib_node_registration_t adj_midchain_tx_node;
+extern vlib_node_registration_t adj_midchain_tx;
 
 static inline u32
 adj_get_rewrite_node (vnet_link_t linkt)
@@ -128,6 +127,7 @@ extern void adj_nbr_remove(adj_index_t ai,
                           vnet_link_t link_type,
                           const ip46_address_t *nh_addr,
                           u32 sw_if_index);
+extern u32 adj_nbr_get_n_adjs(vnet_link_t link_type, u32 sw_if_index);
 extern void adj_glean_remove(ip_adjacency_t *adj);
 extern void adj_mcast_remove(fib_protocol_t proto,
                             u32 sw_if_index);
index 9f709ad..8e6a940 100644 (file)
@@ -75,52 +75,37 @@ adj_get_midchain_node (vnet_link_t link)
 }
 
 static u8
-adj_midchain_get_feature_arc_index_for_link_type (const ip_adjacency_t *adj)
+adj_midchain_get_feature_arc_index (const ip_adjacency_t *adj)
 {
-    u8 arc = (u8) ~0;
     switch (adj->ia_link)
     {
     case VNET_LINK_IP4:
-       {
-           arc = ip4_main.lookup_main.output_feature_arc_index;
-           break;
-       }
+        return ip4_main.lookup_main.output_feature_arc_index;
     case VNET_LINK_IP6:
-       {
-           arc = ip6_main.lookup_main.output_feature_arc_index;
-           break;
-       }
+        return ip6_main.lookup_main.output_feature_arc_index;
     case VNET_LINK_MPLS:
-       {
-           arc = mpls_main.output_feature_arc_index;
-           break;
-       }
+        return mpls_main.output_feature_arc_index;
     case VNET_LINK_ETHERNET:
-       {
-           arc = ethernet_main.output_feature_arc_index;
-           break;
-       }
+        return ethernet_main.output_feature_arc_index;
     case VNET_LINK_NSH:
-        {
-          arc = nsh_main_placeholder.output_feature_arc_index;
-          break;
-        }
     case VNET_LINK_ARP:
-       ASSERT(0);
        break;
     }
-
-    ASSERT (arc != (u8) ~0);
-
-    return (arc);
+    ASSERT (0);
+    return (0);
 }
 
 static u32
 adj_nbr_midchain_get_tx_node (ip_adjacency_t *adj)
 {
-    return ((adj->ia_flags & ADJ_FLAG_MIDCHAIN_NO_COUNT) ?
-            adj_midchain_tx_no_count_node.index :
-            adj_midchain_tx_node.index);
+    return (adj_midchain_tx.index);
+}
+
+static u32
+adj_nbr_midchain_get_next_node (ip_adjacency_t *adj)
+{
+    return (vnet_feature_get_end_node(adj_midchain_get_feature_arc_index(adj),
+                                      adj->rewrite_header.sw_if_index));
 }
 
 /**
@@ -131,17 +116,7 @@ adj_nbr_midchain_get_tx_node (ip_adjacency_t *adj)
 void
 adj_midchain_teardown (ip_adjacency_t *adj)
 {
-    vlib_main_t *vm = vlib_get_main();
-
     dpo_reset(&adj->sub_type.midchain.next_dpo);
-
-    vlib_worker_thread_barrier_sync(vm);
-    adj->ia_cfg_index = vnet_feature_modify_end_node(
-        adj_midchain_get_feature_arc_index_for_link_type (adj),
-        adj->rewrite_header.sw_if_index,
-        vlib_get_node_by_name (vlib_get_main(),
-                               (u8*) "interface-output")->index);
-    vlib_worker_thread_barrier_release(vm);
 }
 
 /**
@@ -155,9 +130,7 @@ adj_midchain_setup (adj_index_t adj_index,
                     const void *data,
                     adj_flags_t flags)
 {
-    vlib_main_t *vm = vlib_get_main();
     ip_adjacency_t *adj;
-    u32 tx_node;
 
     ASSERT(ADJ_INDEX_INVALID != adj_index);
 
@@ -181,15 +154,6 @@ adj_midchain_setup (adj_index_t adj_index,
         adj->rewrite_header.flags &= ~VNET_REWRITE_FIXUP_FLOW_HASH;
     }
 
-    tx_node = adj_nbr_midchain_get_tx_node(adj);
-
-    vlib_worker_thread_barrier_sync(vm);
-    adj->ia_cfg_index = vnet_feature_modify_end_node(
-        adj_midchain_get_feature_arc_index_for_link_type (adj),
-        adj->rewrite_header.sw_if_index,
-        tx_node);
-    vlib_worker_thread_barrier_release(vm);
-
     /*
      * stack the midchain on the drop so it's ready to forward in the adj-midchain-tx.
      * The graph arc used/created here is from the midchain-tx node to the
@@ -197,7 +161,7 @@ adj_midchain_setup (adj_index_t adj_index,
      * node are any output features, then the midchain-tx.  from there we
      * need to get to the stacked child's node.
      */
-    dpo_stack_from_node(tx_node,
+    dpo_stack_from_node(adj_nbr_midchain_get_tx_node(adj),
                         &adj->sub_type.midchain.next_dpo,
                         drop_dpo_get(vnet_link_to_dpo_proto(adj->ia_link)));
 }
@@ -238,7 +202,7 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
     adj_nbr_update_rewrite_internal(adj,
                                    IP_LOOKUP_NEXT_MIDCHAIN,
                                    adj_get_midchain_node(adj->ia_link),
-                                   adj_nbr_midchain_get_tx_node(adj),
+                                   adj_nbr_midchain_get_next_node(adj),
                                    rewrite);
 }
 
@@ -260,11 +224,6 @@ adj_nbr_midchain_update_next_node (adj_index_t adj_index,
                                                         adj->ia_node_index,
                                                         next_node);
 
-    adj->ia_cfg_index = vnet_feature_modify_end_node(
-        adj_midchain_get_feature_arc_index_for_link_type (adj),
-        adj->rewrite_header.sw_if_index,
-        next_node);
-
     vlib_worker_thread_barrier_release(vm);
 }
 
@@ -284,12 +243,7 @@ adj_nbr_midchain_reset_next_node (adj_index_t adj_index)
     adj->rewrite_header.next_index =
         vlib_node_add_next(vlib_get_main(),
                            adj->ia_node_index,
-                           adj_nbr_midchain_get_tx_node(adj));
-
-    adj->ia_cfg_index = vnet_feature_modify_end_node(
-        adj_midchain_get_feature_arc_index_for_link_type (adj),
-        adj->rewrite_header.sw_if_index,
-        adj_nbr_midchain_get_tx_node(adj));
+                           adj_nbr_midchain_get_next_node(adj));
 
     vlib_worker_thread_barrier_release(vm);
 }
index 170ed19..fcc2c6c 100644 (file)
@@ -202,16 +202,20 @@ format_adj_midchain_tx_trace (u8 * s, va_list * args)
     return (s);
 }
 
-static uword
-adj_midchain_tx (vlib_main_t * vm,
-                vlib_node_runtime_t * node,
-                vlib_frame_t * frame)
+VLIB_NODE_FN (adj_midchain_tx) (vlib_main_t * vm,
+                                vlib_node_runtime_t * node,
+                                vlib_frame_t * frame)
+{
+    return (adj_midchain_tx_inline(vm, node, frame, 1));
+}
+VLIB_NODE_FN (tunnel_output) (vlib_main_t * vm,
+                              vlib_node_runtime_t * node,
+                              vlib_frame_t * frame)
 {
     return (adj_midchain_tx_inline(vm, node, frame, 1));
 }
 
-VLIB_REGISTER_NODE (adj_midchain_tx_node) = {
-    .function = adj_midchain_tx,
+VLIB_REGISTER_NODE (adj_midchain_tx) = {
     .name = "adj-midchain-tx",
     .vector_size = sizeof (u32),
 
@@ -222,20 +226,23 @@ VLIB_REGISTER_NODE (adj_midchain_tx_node) = {
        [0] = "error-drop",
     },
 };
+VLIB_REGISTER_NODE (tunnel_output) = {
+    .name = "tunnel-output",
+    .vector_size = sizeof (u32),
+    .format_trace = format_adj_midchain_tx_trace,
+    .sibling_of = "adj-midchain-tx",
+};
 
-static uword
-adj_midchain_tx_no_count (vlib_main_t * vm,
-                         vlib_node_runtime_t * node,
-                         vlib_frame_t * frame)
+VLIB_NODE_FN (tunnel_output_no_count) (vlib_main_t * vm,
+                                       vlib_node_runtime_t * node,
+                                       vlib_frame_t * frame)
 {
     return (adj_midchain_tx_inline(vm, node, frame, 0));
 }
 
-VLIB_REGISTER_NODE (adj_midchain_tx_no_count_node) = {
-    .function = adj_midchain_tx_no_count,
-    .name = "adj-midchain-tx-no-count",
+VLIB_REGISTER_NODE (tunnel_output_no_count) = {
+    .name = "tunnel-output-no-count",
     .vector_size = sizeof (u32),
-
     .format_trace = format_adj_midchain_tx_trace,
     .sibling_of = "adj-midchain-tx",
 };
index 8524c6c..293bade 100644 (file)
@@ -105,6 +105,46 @@ adj_nbr_remove (adj_index_t ai,
     }
 }
 
+typedef struct adj_nbr_get_n_adjs_walk_ctx_t_
+{
+    vnet_link_t linkt;
+    u32 count;
+} adj_nbr_get_n_adjs_walk_ctx_t;
+
+static adj_walk_rc_t
+adj_nbr_get_n_adjs_walk (adj_index_t ai,
+                         void *data)
+{
+    adj_nbr_get_n_adjs_walk_ctx_t *ctx = data;
+    const ip_adjacency_t *adj;
+
+    adj = adj_get(ai);
+
+    if (ctx->linkt == adj->ia_link)
+        ctx->count++;
+
+    return (ADJ_WALK_RC_CONTINUE);
+}
+
+u32
+adj_nbr_get_n_adjs (vnet_link_t link_type, u32 sw_if_index)
+{
+    adj_nbr_get_n_adjs_walk_ctx_t ctx = {
+        .linkt = link_type,
+    };
+    fib_protocol_t fproto;
+
+    FOR_EACH_FIB_IP_PROTOCOL(fproto)
+    {
+        adj_nbr_walk (sw_if_index,
+                      fproto,
+                      adj_nbr_get_n_adjs_walk,
+                      &ctx);
+    }
+
+    return (ctx.count);
+}
+
 adj_index_t
 adj_nbr_find (fib_protocol_t nh_proto,
              vnet_link_t link_type,
index c9d4909..4ff001a 100644 (file)
@@ -119,6 +119,12 @@ find_config_with_features (vlib_main_t * vm,
       vec_add1 (config_string, next_index);
     }
 
+  /* Add the end node index to the config string so that it is part of
+   * the key used to detect string sharing. If this is not included then
+   * a modification of the end node would affect all the user of a shared
+   * string. */
+  vec_add1 (config_string, end_node_index);
+
   /* See if config string is unique. */
   p = hash_get_mem (cm->config_string_hash, config_string);
   if (p)
@@ -249,6 +255,15 @@ vnet_config_del (vnet_config_main_t * cm, u32 config_id)
   remove_reference (cm, old);
 }
 
+u32
+vnet_config_reset_end_node (vlib_main_t *vm, vnet_config_main_t *cm, u32 ci)
+{
+  cm->end_node_indices_by_user_index[ci] = cm->default_end_node_index;
+
+  return (
+    vnet_config_modify_end_node (vm, cm, ci, cm->default_end_node_index));
+}
+
 u32
 vnet_config_modify_end_node (vlib_main_t * vm,
                             vnet_config_main_t * cm,
@@ -303,6 +318,18 @@ vnet_config_modify_end_node (vlib_main_t * vm,
   return new->config_string_heap_index + 1;
 }
 
+u32
+vnet_config_get_end_node (vlib_main_t *vm, vnet_config_main_t *cm,
+                         u32 config_string_heap_index)
+{
+  if (config_string_heap_index >= vec_len (cm->end_node_indices_by_user_index))
+    return cm->default_end_node_index;
+  if (~0 == cm->end_node_indices_by_user_index[config_string_heap_index])
+    return cm->default_end_node_index;
+
+  return (cm->end_node_indices_by_user_index[config_string_heap_index]);
+}
+
 u32
 vnet_config_add_feature (vlib_main_t * vm,
                         vnet_config_main_t * cm,
index ccbbbf4..9b01b4a 100644 (file)
@@ -169,6 +169,12 @@ u32 vnet_config_modify_end_node (vlib_main_t * vm,
                                 u32 config_string_heap_index,
                                 u32 end_node_index);
 
+u32 vnet_config_reset_end_node (vlib_main_t *vm, vnet_config_main_t *cm,
+                               u32 config_string_heap_index);
+
+u32 vnet_config_get_end_node (vlib_main_t *vm, vnet_config_main_t *cm,
+                             u32 config_string_heap_index);
+
 u8 *vnet_config_format_features (vlib_main_t * vm,
                                 vnet_config_main_t * cm,
                                 u32 config_index, u8 * s);
index c93f586..1750612 100644 (file)
@@ -293,9 +293,10 @@ vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index,
   fm->sw_if_index_has_features[arc_index] =
     clib_bitmap_set (fm->sw_if_index_has_features[arc_index], sw_if_index,
                     (feature_count > 0));
+  fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
+
   vnet_feature_reg_invoke (sw_if_index, arc_index, (feature_count > 0));
 
-  fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
   return 0;
 }
 
@@ -375,6 +376,52 @@ vnet_feature_is_enabled (const char *arc_name, const char *feature_node_name,
   return 0;
 }
 
+u32
+vnet_feature_get_end_node (u8 arc_index, u32 sw_if_index)
+{
+  vnet_feature_main_t *fm = &feature_main;
+  vnet_feature_config_main_t *cm;
+  u32 ci;
+
+  if (arc_index == (u8) ~0)
+    return VNET_API_ERROR_INVALID_VALUE;
+
+  cm = &fm->feature_config_mains[arc_index];
+  vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
+  ci = cm->config_index_by_sw_if_index[sw_if_index];
+
+  return (vnet_config_get_end_node (vlib_get_main (), &cm->config_main, ci));
+}
+
+u32
+vnet_feature_reset_end_node (u8 arc_index, u32 sw_if_index)
+{
+  vnet_feature_main_t *fm = &feature_main;
+  vnet_feature_config_main_t *cm;
+  u32 ci;
+
+  cm = &fm->feature_config_mains[arc_index];
+  vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
+  ci = cm->config_index_by_sw_if_index[sw_if_index];
+
+  ci = vnet_config_reset_end_node (vlib_get_main (), &cm->config_main, ci);
+
+  if (ci != ~0)
+    cm->config_index_by_sw_if_index[sw_if_index] = ci;
+
+  i16 feature_count;
+
+  if (NULL == fm->feature_count_by_sw_if_index ||
+      vec_len (fm->feature_count_by_sw_if_index) <= arc_index ||
+      vec_len (fm->feature_count_by_sw_if_index[arc_index]) <= sw_if_index)
+    feature_count = 0;
+  else
+    feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index];
+
+  vnet_feature_reg_invoke (sw_if_index, arc_index, (feature_count > 0));
+
+  return ci;
+}
 
 u32
 vnet_feature_modify_end_node (u8 arc_index,
@@ -400,6 +447,17 @@ vnet_feature_modify_end_node (u8 arc_index,
   if (ci != ~0)
     cm->config_index_by_sw_if_index[sw_if_index] = ci;
 
+  i16 feature_count;
+
+  if (NULL == fm->feature_count_by_sw_if_index ||
+      vec_len (fm->feature_count_by_sw_if_index) <= arc_index ||
+      vec_len (fm->feature_count_by_sw_if_index[arc_index]) <= sw_if_index)
+    feature_count = 0;
+  else
+    feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index];
+
+  vnet_feature_reg_invoke (sw_if_index, arc_index, (feature_count > 0));
+
   return ci;
 }
 
index 9aa3218..a8235d3 100644 (file)
@@ -222,6 +222,10 @@ vnet_feature_enable_disable (const char *arc_name, const char *node_name,
 u32
 vnet_feature_modify_end_node (u8 arc_index, u32 sw_if_index, u32 node_index);
 
+u32 vnet_feature_get_end_node (u8 arc_index, u32 sw_if_index);
+
+u32 vnet_feature_reset_end_node (u8 arc_index, u32 sw_if_index);
+
 static_always_inline u32
 vnet_get_feature_count (u8 arc, u32 sw_if_index)
 {
index fcdf9c0..dc735e6 100644 (file)
@@ -420,9 +420,6 @@ gre_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
   if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
     af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
 
-  if (VNET_LINK_ETHERNET == adj_get_link_type (ai))
-    af |= ADJ_FLAG_MIDCHAIN_NO_COUNT;
-
   adj_nbr_midchain_update_rewrite
     (ai, gre_get_fixup (t->tunnel_dst.fp_proto,
                        adj_get_link_type (ai)),
index 0251ced..3b566b6 100644 (file)
@@ -504,9 +504,15 @@ vnet_gre_tunnel_add (vnet_gre_tunnel_add_del_args_t * a,
     {
       t->l2_adj_index = adj_nbr_add_or_lock
        (t->tunnel_dst.fp_proto, VNET_LINK_ETHERNET, &zero_addr, sw_if_index);
+      vnet_set_interface_l3_output_node (gm->vlib_main, sw_if_index,
+                                        (u8 *) "tunnel-output-no-count");
       gre_update_adj (vnm, t->sw_if_index, t->l2_adj_index);
     }
-
+  else
+    {
+      vnet_set_interface_l3_output_node (gm->vlib_main, sw_if_index,
+                                        (u8 *) "tunnel-output");
+    }
   if (sw_if_indexp)
     *sw_if_indexp = sw_if_index;
 
@@ -562,6 +568,7 @@ vnet_gre_tunnel_delete (vnet_gre_tunnel_add_del_args_t * a,
       clib_mem_free (t->gre_sn);
     }
 
+  vnet_reset_interface_l3_output_node (gm->vlib_main, sw_if_index);
   hash_unset (gm->instance_used, t->user_instance);
   gre_tunnel_db_remove (t, &key);
   pool_put (gm->tunnels, t);
index ab12da5..ce02499 100644 (file)
@@ -804,6 +804,36 @@ setup_output_node (vlib_main_t * vm,
   n->unformat_buffer = hw_class->unformat_header;
 }
 
+void
+vnet_reset_interface_l3_output_node (vlib_main_t *vm, u32 sw_if_index)
+{
+  vnet_set_interface_l3_output_node (vm, sw_if_index,
+                                    (u8 *) "interface-output");
+}
+
+void
+vnet_set_interface_l3_output_node (vlib_main_t *vm, u32 sw_if_index,
+                                  u8 *output_node)
+{
+  vlib_node_t *l3_node;
+
+  l3_node = vlib_get_node_by_name (vm, output_node);
+
+  static char *arcs[] = {
+    "ip4-output",
+    "ip6-output",
+    "mpls-output",
+    "ethernet-output",
+  };
+  u8 a;
+
+  for (a = 0; a < ARRAY_LEN (arcs); a++)
+    {
+      u8 arc = vnet_get_feature_arc_index (arcs[a]);
+      vnet_feature_modify_end_node (arc, sw_if_index, l3_node->index);
+    }
+}
+
 /* Register an interface instance. */
 u32
 vnet_register_interface (vnet_main_t * vnm,
@@ -1106,7 +1136,6 @@ vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index)
       dn->tx_node_index = hw->tx_node_index;
       dn->output_node_index = hw->output_node_index;
     }
-
   hash_unset_mem (im->hw_interface_by_name, hw->name);
   vec_free (hw->name);
   vec_free (hw->hw_address);
index 28312d4..f253b23 100644 (file)
@@ -231,6 +231,10 @@ u32 vnet_register_interface (vnet_main_t * vnm,
 void vnet_set_interface_output_node (vnet_main_t * vnm,
                                     u32 hw_if_index, u32 node_index);
 
+void vnet_set_interface_l3_output_node (vlib_main_t *vm, u32 sw_if_index,
+                                       u8 *output_node);
+void vnet_reset_interface_l3_output_node (vlib_main_t *vm, u32 sw_if_index);
+
 /* Creates a software interface given template. */
 clib_error_t *vnet_create_sw_interface (vnet_main_t * vnm,
                                        vnet_sw_interface_t * template,
index 5dbe85a..2ac234e 100644 (file)
@@ -348,9 +348,6 @@ ipip_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
   if (!(t->flags & TUNNEL_ENCAP_DECAP_FLAG_ENCAP_INNER_HASH))
     af |= ADJ_FLAG_MIDCHAIN_IP_STACK;
 
-  if (VNET_LINK_ETHERNET == adj_get_link_type (ai))
-    af |= ADJ_FLAG_MIDCHAIN_NO_COUNT;
-
   fixup = ipip_get_fixup (t, adj_get_link_type (ai), &af);
   adj_nbr_midchain_update_rewrite
     (ai, fixup,
@@ -795,6 +792,8 @@ ipip_add_tunnel (ipip_transport_t transport,
 
   /* Standard default ipip MTU. */
   vnet_sw_interface_set_mtu (vnm, sw_if_index, 9000);
+  vnet_set_interface_l3_output_node (gm->vlib_main, sw_if_index,
+                                    (u8 *) "tunnel-output");
 
   t->tunnel_src = *src;
   t->tunnel_dst = *dst;
@@ -840,6 +839,7 @@ ipip_del_tunnel (u32 sw_if_index)
     teib_walk_itf (t->sw_if_index, ipip_tunnel_delete_teib_walk, t);
 
   vnet_sw_interface_set_flags (vnm, sw_if_index, 0 /* down */ );
+  vnet_reset_interface_l3_output_node (gm->vlib_main, t->sw_if_index);
   gm->tunnel_index_by_sw_if_index[sw_if_index] = ~0;
   vnet_delete_hw_interface (vnm, t->hw_if_index);
   hash_unset (gm->instance_used, t->user_instance);
index 492b4f8..c6c855d 100644 (file)
@@ -325,6 +325,8 @@ sixrd_add_tunnel (ip6_address_t * ip6_prefix, u8 ip6_prefix_len,
   t->user_instance = t_idx;
 
   vnet_sw_interface_set_mtu (vnet_get_main (), t->sw_if_index, 1480);
+  vnet_set_interface_l3_output_node (gm->vlib_main, hi->sw_if_index,
+                                    (u8 *) "tunnel-output");
 
   ipip_tunnel_db_add (t, &key);
 
@@ -403,6 +405,7 @@ sixrd_del_tunnel (u32 sw_if_index)
 
   vnet_sw_interface_set_flags (vnet_get_main (), t->sw_if_index,
                               0 /* down */ );
+  vnet_reset_interface_l3_output_node (gm->vlib_main, t->sw_if_index);
   ip6_sw_interface_enable_disable (t->sw_if_index, false);
   gm->tunnel_index_by_sw_if_index[t->sw_if_index] = ~0;
 
index 33484e9..0d29604 100644 (file)
@@ -50,7 +50,9 @@ typedef enum
   _ (SEQ_CYCLED, "sequence number cycled (packet dropped)")                   \
   _ (CRYPTO_ENGINE_ERROR, "crypto engine error (packet dropped)")             \
   _ (CRYPTO_QUEUE_FULL, "crypto queue full (packet dropped)")                 \
-  _ (NO_BUFFERS, "no buffers (packet dropped)")
+  _ (NO_BUFFERS, "no buffers (packet dropped)")                               \
+  _ (NO_PROTECTION, "no protecting SA (packet dropped)")                      \
+  _ (NO_ENCRYPTION, "no Encrypting SA (packet dropped)")
 
 typedef enum
 {
@@ -640,6 +642,14 @@ esp_encrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
          vnet_buffer (b[0])->ipsec.sad_index =
            sa_index0 = ipsec_tun_protect_get_sa_out
            (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
+
+         if (PREDICT_FALSE (INDEX_INVALID == sa_index0))
+           {
+             err = ESP_ENCRYPT_ERROR_NO_PROTECTION;
+             esp_set_next_index (b[0], node, err, n_noop, noop_nexts,
+                                 drop_next);
+             goto trace;
+           }
        }
       else
        sa_index0 = vnet_buffer (b[0])->ipsec.sad_index;
@@ -655,6 +665,15 @@ esp_encrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
 
          sa0 = ipsec_sa_get (sa_index0);
 
+         if (PREDICT_FALSE ((sa0->crypto_alg == IPSEC_CRYPTO_ALG_NONE &&
+                             sa0->integ_alg == IPSEC_INTEG_ALG_NONE) &&
+                            !ipsec_sa_is_set_NO_ALGO_NO_DROP (sa0)))
+           {
+             err = ESP_ENCRYPT_ERROR_NO_ENCRYPTION;
+             esp_set_next_index (b[0], node, err, n_noop, noop_nexts,
+                                 drop_next);
+             goto trace;
+           }
          /* fetch the second cacheline ASAP */
          clib_prefetch_load (sa0->cacheline1);
 
@@ -970,13 +989,19 @@ esp_encrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
        {
          esp_encrypt_trace_t *tr = vlib_add_trace (vm, node, b[0],
                                                    sizeof (*tr));
-         tr->sa_index = sa_index0;
-         tr->spi = sa0->spi;
-         tr->seq = sa0->seq;
-         tr->sa_seq_hi = sa0->seq_hi;
-         tr->udp_encap = ipsec_sa_is_set_UDP_ENCAP (sa0);
-         tr->crypto_alg = sa0->crypto_alg;
-         tr->integ_alg = sa0->integ_alg;
+         if (INDEX_INVALID == sa_index0)
+           clib_memset_u8 (tr, 0xff, sizeof (*tr));
+         else
+           {
+             tr->sa_index = sa_index0;
+             tr->spi = sa0->spi;
+             tr->spi = sa0->spi;
+             tr->seq = sa0->seq;
+             tr->sa_seq_hi = sa0->seq_hi;
+             tr->udp_encap = ipsec_sa_is_set_UDP_ENCAP (sa0);
+             tr->crypto_alg = sa0->crypto_alg;
+             tr->integ_alg = sa0->integ_alg;
+           }
        }
 
       /* next */
@@ -1002,9 +1027,10 @@ esp_encrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
       b += 1;
     }
 
-  vlib_increment_combined_counter (&ipsec_sa_counters, thread_index,
-                                  current_sa_index, current_sa_packets,
-                                  current_sa_bytes);
+  if (INDEX_INVALID != current_sa_index)
+    vlib_increment_combined_counter (&ipsec_sa_counters, thread_index,
+                                    current_sa_index, current_sa_packets,
+                                    current_sa_bytes);
   if (n_sync)
     {
       esp_process_ops (vm, node, ptd->crypto_ops, sync_bufs, sync_nexts,
@@ -1368,120 +1394,6 @@ VLIB_REGISTER_NODE (esp_mpls_encrypt_tun_post_node) = {
   .error_strings = esp_encrypt_error_strings,
 };
 
-typedef struct
-{
-  u32 sa_index;
-} esp_no_crypto_trace_t;
-
-static u8 *
-format_esp_no_crypto_trace (u8 * s, va_list * args)
-{
-  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
-  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
-  esp_no_crypto_trace_t *t = va_arg (*args, esp_no_crypto_trace_t *);
-
-  s = format (s, "esp-no-crypto: sa-index %u", t->sa_index);
-
-  return s;
-}
-
-enum
-{
-  ESP_NO_CRYPTO_NEXT_DROP,
-  ESP_NO_CRYPTO_N_NEXT,
-};
-
-enum
-{
-  ESP_NO_CRYPTO_ERROR_RX_PKTS,
-};
-
-static char *esp_no_crypto_error_strings[] = {
-  "Outbound ESP packets received",
-};
-
-always_inline uword
-esp_no_crypto_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
-                     vlib_frame_t * frame)
-{
-  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
-  u32 *from = vlib_frame_vector_args (frame);
-  u32 n_left = frame->n_vectors;
-
-  vlib_get_buffers (vm, from, b, n_left);
-
-  while (n_left > 0)
-    {
-      u32 sa_index0;
-
-      /* packets are always going to be dropped, but get the sa_index */
-      sa_index0 = ipsec_tun_protect_get_sa_out
-       (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]);
-
-      if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
-       {
-         esp_no_crypto_trace_t *tr = vlib_add_trace (vm, node, b[0],
-                                                     sizeof (*tr));
-         tr->sa_index = sa_index0;
-       }
-
-      n_left -= 1;
-      b += 1;
-    }
-
-  vlib_node_increment_counter (vm, node->node_index,
-                              ESP_NO_CRYPTO_ERROR_RX_PKTS, frame->n_vectors);
-
-  vlib_buffer_enqueue_to_single_next (vm, node, from,
-                                     ESP_NO_CRYPTO_NEXT_DROP,
-                                     frame->n_vectors);
-
-  return frame->n_vectors;
-}
-
-VLIB_NODE_FN (esp4_no_crypto_tun_node) (vlib_main_t * vm,
-                                       vlib_node_runtime_t * node,
-                                       vlib_frame_t * from_frame)
-{
-  return esp_no_crypto_inline (vm, node, from_frame);
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (esp4_no_crypto_tun_node) =
-{
-  .name = "esp4-no-crypto",
-  .vector_size = sizeof (u32),
-  .format_trace = format_esp_no_crypto_trace,
-  .n_errors = ARRAY_LEN(esp_no_crypto_error_strings),
-  .error_strings = esp_no_crypto_error_strings,
-  .n_next_nodes = ESP_NO_CRYPTO_N_NEXT,
-  .next_nodes = {
-    [ESP_NO_CRYPTO_NEXT_DROP] = "ip4-drop",
-  },
-};
-
-VLIB_NODE_FN (esp6_no_crypto_tun_node) (vlib_main_t * vm,
-                                       vlib_node_runtime_t * node,
-                                       vlib_frame_t * from_frame)
-{
-  return esp_no_crypto_inline (vm, node, from_frame);
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (esp6_no_crypto_tun_node) =
-{
-  .name = "esp6-no-crypto",
-  .vector_size = sizeof (u32),
-  .format_trace = format_esp_no_crypto_trace,
-  .n_errors = ARRAY_LEN(esp_no_crypto_error_strings),
-  .error_strings = esp_no_crypto_error_strings,
-  .n_next_nodes = ESP_NO_CRYPTO_N_NEXT,
-  .next_nodes = {
-    [ESP_NO_CRYPTO_NEXT_DROP] = "ip6-drop",
-  },
-};
-/* *INDENT-ON* */
-
 #ifndef CLIB_MARCH_VARIANT
 
 static clib_error_t *
index 30774ec..5cc8044 100644 (file)
@@ -25,6 +25,7 @@
 #include <vnet/ipsec/esp.h>
 #include <vnet/ipsec/ah.h>
 #include <vnet/ipsec/ipsec_tun.h>
+#include <vnet/ipsec/ipsec_itf.h>
 
 /* Flow cache is sized for 1 million flows with a load factor of .25.
  */
@@ -254,6 +255,9 @@ ipsec_rsc_in_use (ipsec_main_t * im)
   if (pool_elts (ipsec_sa_pool) > 0)
     return clib_error_return (0, "%d SA entries configured",
                              pool_elts (ipsec_sa_pool));
+  if (ipsec_itf_count () > 0)
+    return clib_error_return (0, "%d IPSec interface configured",
+                             ipsec_itf_count ());
 
   return (NULL);
 }
index 968d377..38feaed 100644 (file)
@@ -181,14 +181,6 @@ typedef struct
   u32 ah6_encrypt_next_index;
   u32 ah6_decrypt_next_index;
 
-  /* tun nodes to drop packets when no crypto alg set on outbound SA */
-  u32 esp4_no_crypto_tun_node_index;
-  u32 esp6_no_crypto_tun_node_index;
-
-  /* tun nodes for encrypt on L2 interfaces */
-  u32 esp4_encrypt_l2_tun_node_index;
-  u32 esp6_encrypt_l2_tun_node_index;
-
   /* pool of ah backends */
   ipsec_ah_backend_t *ah_backends;
   /* pool of esp backends */
index 532d5be..fc0bf85 100644 (file)
@@ -36,6 +36,12 @@ ipsec_itf_get (index_t ii)
   return (pool_elt_at_index (ipsec_itf_pool, ii));
 }
 
+u32
+ipsec_itf_count (void)
+{
+  return (pool_elts (ipsec_itf_pool));
+}
+
 static ipsec_itf_t *
 ipsec_itf_find_by_sw_if_index (u32 sw_if_index)
 {
@@ -336,6 +342,8 @@ ipsec_itf_delete (u32 sw_if_index)
   if (ipsec_itf_instance_free (hw->dev_instance) < 0)
     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
 
+  vnet_reset_interface_l3_output_node (vnm->vlib_main, sw_if_index);
+
   vnet_delete_hw_interface (vnm, hw->hw_if_index);
   pool_put (ipsec_itf_pool, ipsec_itf);
 
index 4958d10..7de0274 100644 (file)
@@ -109,6 +109,7 @@ extern void ipsec_itf_adj_unstack (adj_index_t ai);
 extern u8 *format_ipsec_itf (u8 * s, va_list * a);
 
 extern ipsec_itf_t *ipsec_itf_get (index_t ii);
+extern u32 ipsec_itf_count (void);
 
 typedef walk_rc_t (*ipsec_itf_walk_cb_t) (ipsec_itf_t *itf, void *ctx);
 extern void ipsec_itf_walk (ipsec_itf_walk_cb_t cd, void *ctx);
index 2cc64e1..ec5ca11 100644 (file)
@@ -102,7 +102,8 @@ typedef struct ipsec_key_t_
   _ (64, IS_INBOUND, "inbound")                                               \
   _ (128, IS_AEAD, "aead")                                                    \
   _ (256, IS_CTR, "ctr")                                                      \
-  _ (512, IS_ASYNC, "async")
+  _ (512, IS_ASYNC, "async")                                                  \
+  _ (1024, NO_ALGO_NO_DROP, "no-algo-no-drop")
 
 typedef enum ipsec_sad_flags_t_
 {
index 1a9a257..ef84d13 100644 (file)
@@ -22,6 +22,7 @@
 #include <vnet/adj/adj_delegate.h>
 #include <vnet/adj/adj_midchain.h>
 #include <vnet/teib/teib.h>
+#include <vnet/mpls/mpls.h>
 
 /* instantiate the bihash functions */
 #include <vppinfra/bihash_8_16.h>
@@ -137,12 +138,14 @@ ipsec_tun_protect_from_const_base (const adj_delegate_t * ad)
 
 static u32
 ipsec_tun_protect_get_adj_next (vnet_link_t linkt,
-                               const ipsec_tun_protect_t * itp)
+                               const ipsec_tun_protect_t *itp)
 {
   ipsec_main_t *im;
-  ipsec_sa_t *sa;
   u32 next;
 
+  im = &ipsec_main;
+  next = 0;
+
   if (!(itp->itp_flags & IPSEC_PROTECT_ITF))
     {
       if (ip46_address_is_ip4 (&itp->itp_tun.src))
@@ -151,41 +154,47 @@ ipsec_tun_protect_get_adj_next (vnet_link_t linkt,
        linkt = VNET_LINK_IP6;
     }
 
-  sa = ipsec_sa_get (itp->itp_out_sa);
-  im = &ipsec_main;
-  next = 0;
-
-  if ((sa->crypto_alg == IPSEC_CRYPTO_ALG_NONE &&
-       sa->integ_alg == IPSEC_INTEG_ALG_NONE) &&
-      !(itp->itp_flags & IPSEC_PROTECT_ITF))
-    next = (VNET_LINK_IP4 == linkt ? im->esp4_no_crypto_tun_node_index :
-                                    im->esp6_no_crypto_tun_node_index);
-  else if (itp->itp_flags & IPSEC_PROTECT_L2)
-    next = (VNET_LINK_IP4 == linkt ? im->esp4_encrypt_l2_tun_node_index :
-                                    im->esp6_encrypt_l2_tun_node_index);
-  else
+  switch (linkt)
     {
-      switch (linkt)
-       {
-       case VNET_LINK_IP4:
-         next = im->esp4_encrypt_tun_node_index;
-         break;
-       case VNET_LINK_IP6:
-         next = im->esp6_encrypt_tun_node_index;
-         break;
-       case VNET_LINK_MPLS:
-         next = im->esp_mpls_encrypt_tun_node_index;
-         break;
-       case VNET_LINK_ARP:
-       case VNET_LINK_NSH:
-       case VNET_LINK_ETHERNET:
-         ASSERT (0);
-         break;
-       }
+    case VNET_LINK_IP4:
+      next = im->esp4_encrypt_tun_node_index;
+      break;
+    case VNET_LINK_IP6:
+      next = im->esp6_encrypt_tun_node_index;
+      break;
+    case VNET_LINK_MPLS:
+      next = im->esp_mpls_encrypt_tun_node_index;
+      break;
+    case VNET_LINK_ARP:
+    case VNET_LINK_NSH:
+    case VNET_LINK_ETHERNET:
+      ASSERT (0);
+      break;
     }
+
   return (next);
 }
 
+static void
+ipsec_tun_reset_tx_nodes (u32 sw_if_index)
+{
+  vnet_reset_interface_l3_output_node (vlib_get_main (), sw_if_index);
+}
+
+static void
+ipsec_tun_setup_tx_nodes (u32 sw_if_index, const ipsec_tun_protect_t *itp)
+{
+  vnet_feature_modify_end_node (
+    ip4_main.lookup_main.output_feature_arc_index, sw_if_index,
+    ipsec_tun_protect_get_adj_next (VNET_LINK_IP4, itp));
+  vnet_feature_modify_end_node (
+    ip6_main.lookup_main.output_feature_arc_index, sw_if_index,
+    ipsec_tun_protect_get_adj_next (VNET_LINK_IP6, itp));
+  vnet_feature_modify_end_node (
+    mpls_main.output_feature_arc_index, sw_if_index,
+    ipsec_tun_protect_get_adj_next (VNET_LINK_MPLS, itp));
+}
+
 static void
 ipsec_tun_protect_add_adj (adj_index_t ai, const ipsec_tun_protect_t * itp)
 {
@@ -200,8 +209,8 @@ ipsec_tun_protect_add_adj (adj_index_t ai, const ipsec_tun_protect_t * itp)
   else
     {
       ipsec_tun_protect_sa_by_adj_index[ai] = itp->itp_out_sa;
-      adj_nbr_midchain_update_next_node
-       (ai, ipsec_tun_protect_get_adj_next (adj_get_link_type (ai), itp));
+      adj_nbr_midchain_update_next_node (
+       ai, ipsec_tun_protect_get_adj_next (adj_get_link_type (ai), itp));
     }
 }
 
@@ -329,7 +338,7 @@ ipsec_tun_protect_tx_db_add (ipsec_tun_protect_t * itp)
     {
       if (INDEX_INVALID == idi->id_itp)
        {
-         // ipsec_tun_protect_feature_set (itp, 1);
+         ipsec_tun_setup_tx_nodes (itp->itp_sw_if_index, itp);
        }
       idi->id_itp = itp - ipsec_tun_protect_pool;
 
@@ -347,7 +356,7 @@ ipsec_tun_protect_tx_db_add (ipsec_tun_protect_t * itp)
           * enable the encrypt feature for egress if this is the first addition
           * on this interface
           */
-         // ipsec_tun_protect_feature_set (itp, 1);
+         ipsec_tun_setup_tx_nodes (itp->itp_sw_if_index, itp);
        }
 
       hash_set_mem (idi->id_hash, itp->itp_key, itp - ipsec_tun_protect_pool);
@@ -435,7 +444,7 @@ ipsec_tun_protect_tx_db_remove (ipsec_tun_protect_t * itp)
 
   if (vnet_sw_interface_is_p2p (vnet_get_main (), itp->itp_sw_if_index))
     {
-      // ipsec_tun_protect_feature_set (itp, 0);
+      ipsec_tun_reset_tx_nodes (itp->itp_sw_if_index);
       idi->id_itp = INDEX_INVALID;
 
       FOR_EACH_FIB_IP_PROTOCOL (nh_proto)
@@ -451,7 +460,7 @@ ipsec_tun_protect_tx_db_remove (ipsec_tun_protect_t * itp)
 
       if (0 == hash_elts (idi->id_hash))
        {
-         // ipsec_tun_protect_feature_set (itp, 0);
+         ipsec_tun_reset_tx_nodes (itp->itp_sw_if_index);
          hash_free (idi->id_hash);
          idi->id_hash = NULL;
        }
@@ -502,6 +511,9 @@ ipsec_tun_protect_config (ipsec_main_t * im,
 
   ipsec_sa_lock (itp->itp_out_sa);
 
+  if (itp->itp_flags & IPSEC_PROTECT_ITF)
+    ipsec_sa_set_NO_ALGO_NO_DROP (ipsec_sa_get (itp->itp_out_sa));
+
   /* *INDENT-OFF* */
   FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
   ({
@@ -534,6 +546,7 @@ ipsec_tun_protect_unconfig (ipsec_main_t * im, ipsec_tun_protect_t * itp)
   ipsec_tun_protect_rx_db_remove (im, itp);
   ipsec_tun_protect_tx_db_remove (itp);
 
+  ipsec_sa_unset_NO_ALGO_NO_DROP (ipsec_sa_get (itp->itp_out_sa));
   ipsec_sa_unlock(itp->itp_out_sa);
 
   FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
@@ -802,19 +815,27 @@ ipsec_tun_feature_update (u32 sw_if_index, u8 arc_index, u8 is_enable,
                          ipsec_main.esp4_decrypt_tun_node_index :
                          ipsec_main.esp6_decrypt_tun_node_index;
 
-      vnet_feature_modify_end_node (
-       feature_main.device_input_feature_arc_index, sw_if_index, decrypt_tun);
-      itp->itp_flags |= IPSEC_PROTECT_FEAT;
+      if (!(itp->itp_flags & IPSEC_PROTECT_FEAT))
+       {
+         itp->itp_flags |= IPSEC_PROTECT_FEAT;
+         vnet_feature_modify_end_node (
+           feature_main.device_input_feature_arc_index, sw_if_index,
+           decrypt_tun);
+       }
     }
   else
     {
-      u32 eth_in =
-       vlib_get_node_by_name (vlib_get_main (), (u8 *) "ethernet-input")
-         ->index;
+      if (itp->itp_flags & IPSEC_PROTECT_FEAT)
+       {
+         itp->itp_flags &= ~IPSEC_PROTECT_FEAT;
+
+         u32 eth_in =
+           vlib_get_node_by_name (vlib_get_main (), (u8 *) "ethernet-input")
+             ->index;
 
-      vnet_feature_modify_end_node (
-       feature_main.device_input_feature_arc_index, sw_if_index, eth_in);
-      itp->itp_flags &= ~IPSEC_PROTECT_FEAT;
+         vnet_feature_modify_end_node (
+           feature_main.device_input_feature_arc_index, sw_if_index, eth_in);
+       }
     }
 
   /* Propagate flag change into lookup entries */
@@ -848,6 +869,9 @@ ipsec_tun_protect_adj_delegate_adj_created (adj_index_t ai)
   if (!adj_is_midchain (ai))
     return;
 
+  vec_validate_init_empty (ipsec_tun_protect_sa_by_adj_index, ai,
+                          INDEX_INVALID);
+
   adj = adj_get (ai);
 
   ip_address_from_46 (&adj->sub_type.midchain.next_hop,
@@ -956,16 +980,6 @@ ipsec_tunnel_protect_init (vlib_main_t *vm)
                         IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
                         IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
 
-  /* set up feature nodes to drop outbound packets with no crypto alg set */
-  im->esp4_no_crypto_tun_node_index =
-    vlib_get_node_by_name (vm, (u8 *) "esp4-no-crypto")->index;
-  im->esp6_no_crypto_tun_node_index =
-    vlib_get_node_by_name (vm, (u8 *) "esp6-no-crypto")->index;
-  im->esp6_encrypt_l2_tun_node_index =
-    vlib_get_node_by_name (vm, (u8 *) "esp6-encrypt-tun")->index;
-  im->esp4_encrypt_l2_tun_node_index =
-    vlib_get_node_by_name (vm, (u8 *) "esp4-encrypt-tun")->index;
-
   ipsec_tun_adj_delegate_type =
     adj_delegate_register_new_type (&ipsec_tun_adj_delegate_vft);
 
index f452fa4..9d8a124 100644 (file)
@@ -182,7 +182,6 @@ always_inline index_t
 ipsec_tun_protect_get_sa_out (adj_index_t ai)
 {
   ASSERT (vec_len (ipsec_tun_protect_sa_by_adj_index) > ai);
-  ASSERT (INDEX_INVALID != ipsec_tun_protect_sa_by_adj_index[ai]);
 
   return (ipsec_tun_protect_sa_by_adj_index[ai]);
 }
index 54458ea..4715958 100644 (file)
@@ -638,6 +638,7 @@ vnet_mpls_tunnel_del (u32 sw_if_index)
                                    mt->mt_sibling_index);
     dpo_reset(&mt->mt_l2_lb);
 
+    vnet_reset_interface_l3_output_node (vlib_get_main (), mt->mt_sw_if_index);
     vnet_delete_hw_interface (vnet_get_main(), mt->mt_hw_if_index);
 
     pool_put(mpls_tunnel_pool, mt);
@@ -685,6 +686,9 @@ vnet_mpls_tunnel_create (u8 l2_only,
     if (mt->mt_flags & MPLS_TUNNEL_FLAG_L2)
         vnet_set_interface_output_node (vnm, mt->mt_hw_if_index,
                                         mpls_tunnel_tx.index);
+    else
+      vnet_set_interface_l3_output_node (vnm->vlib_main, hi->sw_if_index,
+                                        (u8 *) "tunnel-output");
 
     /* Standard default MPLS tunnel MTU. */
     vnet_sw_interface_set_mtu (vnm, hi->sw_if_index, 9000);
index 6534dd6..763aedd 100644 (file)
@@ -2668,6 +2668,7 @@ class TestIpsecItf4(TemplateIpsec,
                            self.pg0.remote_ip4)
         self.config_protect(p)
 
+        self.logger.error(self.vapi.cli("sh ipsec sa"))
         self.verify_tun_44(p, count=n_pkts)
 
         # teardown
@@ -3077,6 +3078,15 @@ class TestIpsecMIfEsp4(TemplateIpsec, IpsecTun4):
         self.pg0.generate_remote_hosts(N_NHS)
         self.pg0.configure_ipv4_neighbors()
 
+        r_all = AclRule(True,
+                        src_prefix="0.0.0.0/0",
+                        dst_prefix="0.0.0.0/0",
+                        proto=0)
+        a = VppAcl(self, [r_all]).add_vpp_config()
+
+        VppAclInterface(self, self.pg0.sw_if_index, [a]).add_vpp_config()
+        VppAclInterface(self, p.tun_if.sw_if_index, [a]).add_vpp_config()
+
         # setup some SAs for several next-hops on the interface
         self.multi_params = []
 
@@ -3128,9 +3138,10 @@ class TestIpsecMIfEsp4(TemplateIpsec, IpsecTun4):
                               self.pg0.remote_hosts[ii].ip4)
             self.multi_params.append(p)
 
-            VppIpRoute(self, p.remote_tun_if_host, 32,
-                       [VppRoutePath(p.tun_if.remote_hosts[ii].ip4,
-                                     p.tun_if.sw_if_index)]).add_vpp_config()
+            p.via_tun_route = VppIpRoute(
+                self, p.remote_tun_if_host, 32,
+                [VppRoutePath(p.tun_if.remote_hosts[ii].ip4,
+                              p.tun_if.sw_if_index)]).add_vpp_config()
 
             p.tun_dst = self.pg0.remote_hosts[ii].ip4
 
@@ -3145,6 +3156,21 @@ class TestIpsecMIfEsp4(TemplateIpsec, IpsecTun4):
         for p in self.multi_params:
             self.verify_tun_44(p, count=N_PKTS)
 
+        # remove one tunnel protect, the rest should still work
+        self.multi_params[0].tun_protect.remove_vpp_config()
+        self.verify_tun_dropped_44(self.multi_params[0], count=N_PKTS)
+        self.multi_params[0].via_tun_route.remove_vpp_config()
+        self.verify_tun_dropped_44(self.multi_params[0], count=N_PKTS)
+
+        for p in self.multi_params[1:]:
+            self.verify_tun_44(p, count=N_PKTS)
+
+        self.multi_params[0].tun_protect.add_vpp_config()
+        self.multi_params[0].via_tun_route.add_vpp_config()
+
+        for p in self.multi_params:
+            self.verify_tun_44(p, count=N_PKTS)
+
 
 class TestIpsecItf6MPLS(TemplateIpsec,
                         TemplateIpsecItf6,