+ if (INDEX_INVALID != idi->id_itp)
+ fn (idi->id_itp, ctx);
+}
+
+static void
+ipsec_tun_feature_update (u32 sw_if_index, u8 arc_index, u8 is_enable,
+ void *data)
+{
+ ipsec_tun_protect_t *itp;
+ index_t itpi;
+
+ if (arc_index != feature_main.device_input_feature_arc_index)
+ return;
+
+ /* Only p2p tunnels supported */
+ itpi = ipsec_tun_protect_find (sw_if_index, &IP_ADDR_ALL_0);
+ if (itpi == INDEX_INVALID)
+ return;
+
+ itp = ipsec_tun_protect_get (itpi);
+
+ if (is_enable)
+ {
+ u32 decrypt_tun = ip46_address_is_ip4 (&itp->itp_crypto.dst) ?
+ ipsec_main.esp4_decrypt_tun_node_index :
+ ipsec_main.esp6_decrypt_tun_node_index;
+
+ 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
+ {
+ 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);
+ }
+ }
+
+ /* Propagate flag change into lookup entries */
+ ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
+ ipsec_tun_protect_rx_db_add (&ipsec_main, itp);
+}
+
+static void
+ipsec_tun_protect_adj_delegate_adj_deleted (adj_delegate_t * ad)
+{
+ /* remove our delegate */
+ ipsec_tun_protect_add_adj (ad->ad_adj_index, NULL);
+ adj_delegate_remove (ad->ad_adj_index, ipsec_tun_adj_delegate_type);
+}
+
+static void
+ipsec_tun_protect_adj_delegate_adj_modified (adj_delegate_t * ad)
+{
+ ipsec_tun_protect_add_adj (ad->ad_adj_index,
+ ipsec_tun_protect_get (ad->ad_index));
+}
+
+static void
+ipsec_tun_protect_adj_delegate_adj_created (adj_index_t ai)
+{
+ /* add our delegate if there is protection for this neighbour */
+ ip_address_t ip = IP_ADDRESS_V4_ALL_0S;
+ ip_adjacency_t *adj;
+ index_t itpi;
+
+ 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,
+ adj->ia_nh_proto, &ip);
+
+ itpi = ipsec_tun_protect_find (adj->rewrite_header.sw_if_index, &ip);
+
+ if (INDEX_INVALID != itpi)
+ ipsec_tun_protect_adj_add (ai, ipsec_tun_protect_get (itpi));
+}
+
+static u8 *
+ipsec_tun_protect_adj_delegate_format (const adj_delegate_t * aed, u8 * s)
+{
+ const ipsec_tun_protect_t *itp;
+
+ itp = ipsec_tun_protect_from_const_base (aed);
+ s = format (s, "ipsec-tun-protect:\n%U", format_ipsec_tun_protect, itp);
+
+ return (s);