+void
+ipsec_tun_protect_walk_itf (u32 sw_if_index,
+ ipsec_tun_protect_walk_cb_t fn, void *ctx)
+{
+ ipsec_tun_protect_itf_db_t *idi;
+ ip_address_t *key;
+ index_t itpi;
+
+ if (vec_len (itp_db.id_itf) <= sw_if_index)
+ return;
+
+ idi = &itp_db.id_itf[sw_if_index];
+
+ /* *INDENT-OFF* */
+ hash_foreach(key, itpi, idi->id_hash,
+ ({
+ fn (itpi, ctx);
+ }));
+ /* *INDENT-ON* */
+ if (INDEX_INVALID != idi->id_itp)
+ fn (idi->id_itp, ctx);
+}
+
+static void
+ipsec_tun_protect_adj_delegate_adj_deleted (adj_delegate_t * ad)
+{
+ /* remove our delegate */
+ adj_delegate_remove (ad->ad_adj_index, ipsec_tun_adj_delegate_type);
+ ipsec_tun_protect_add_adj (ad->ad_adj_index, INDEX_INVALID);
+}
+
+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;
+
+ adj = adj_get (ai);
+
+ if (adj->lookup_next_index != IP_LOOKUP_NEXT_MIDCHAIN)
+ return;
+
+ 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)
+ {
+ const ipsec_tun_protect_t *itp;
+
+ itp = ipsec_tun_protect_get (itpi);
+ adj_delegate_add (adj_get (ai), ipsec_tun_adj_delegate_type, itpi);
+ ipsec_tun_protect_add_adj (ai, itp->itp_out_sa);
+ }
+}
+
+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);
+}
+
+static void
+ipsec_tun_teib_entry_added (const teib_entry_t * ne)
+{
+ const ip46_address_t *peer46;
+ ipsec_tun_protect_t *itp;
+ ip_address_t peer;
+ index_t itpi;
+
+ peer46 = teib_entry_get_peer (ne);
+ ip_address_from_46 (peer46,
+ (ip46_address_is_ip4 (peer46) ?
+ FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6), &peer);
+
+ itpi = ipsec_tun_protect_find (teib_entry_get_sw_if_index (ne), &peer);
+
+ if (INDEX_INVALID == itpi)
+ return;
+
+ itp = ipsec_tun_protect_get (itpi);
+ ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
+ ipsec_tun_protect_update_from_teib (itp, ne);
+ ipsec_tun_protect_set_crypto_addr (itp);
+ ipsec_tun_protect_rx_db_add (&ipsec_main, itp);
+
+ ITP_DBG (itp, "teib-added");
+}
+
+static void
+ipsec_tun_teib_entry_deleted (const teib_entry_t * ne)
+{
+ const ip46_address_t *peer46;
+ ipsec_tun_protect_t *itp;
+ ip_address_t peer;
+ index_t itpi;
+
+ peer46 = teib_entry_get_peer (ne);
+ ip_address_from_46 (peer46,
+ (ip46_address_is_ip4 (peer46) ?
+ FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6), &peer);
+
+ itpi = ipsec_tun_protect_find (teib_entry_get_sw_if_index (ne), &peer);
+
+ if (INDEX_INVALID == itpi)
+ return;
+
+ itp = ipsec_tun_protect_get (itpi);
+ ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
+ ipsec_tun_protect_update_from_teib (itp, NULL);
+ ipsec_tun_protect_set_crypto_addr (itp);
+
+ ITP_DBG (itp, "teib-removed");
+}
+
+/**
+ * VFT registered with the adjacency delegate
+ */
+const static adj_delegate_vft_t ipsec_tun_adj_delegate_vft = {
+ .adv_adj_deleted = ipsec_tun_protect_adj_delegate_adj_deleted,
+ .adv_adj_created = ipsec_tun_protect_adj_delegate_adj_created,
+ .adv_format = ipsec_tun_protect_adj_delegate_format,
+};
+
+const static teib_vft_t ipsec_tun_teib_vft = {
+ .nv_added = ipsec_tun_teib_entry_added,
+ .nv_deleted = ipsec_tun_teib_entry_deleted,
+};
+