+ ipsec_main_t *im = &ipsec_main;
+ ipsec_tunnel_if_t *t = im->tunnel_interfaces + dev_instance;
+
+ return format (s, "ipsec%d", t->show_instance);
+}
+
+/* Statistics (not really errors) */
+#define foreach_ipsec_if_tx_error \
+_(TX, "good packets transmitted")
+
+static void
+ipsec_if_tunnel_stack (adj_index_t ai)
+{
+ ipsec_main_t *ipm = &ipsec_main;
+ ipsec_tunnel_if_t *it;
+ ip_adjacency_t *adj;
+ u32 sw_if_index;
+
+ adj = adj_get (ai);
+ sw_if_index = adj->rewrite_header.sw_if_index;
+
+ if ((vec_len (ipm->ipsec_if_by_sw_if_index) <= sw_if_index) ||
+ (~0 == ipm->ipsec_if_by_sw_if_index[sw_if_index]))
+ return;
+
+ it = pool_elt_at_index (ipm->tunnel_interfaces,
+ ipm->ipsec_if_by_sw_if_index[sw_if_index]);
+
+ if (!vnet_hw_interface_is_link_up (vnet_get_main (), it->hw_if_index))
+ {
+ adj_midchain_delegate_unstack (ai);
+ }
+ else
+ {
+ ipsec_sa_t *sa;
+
+ sa = ipsec_sa_get (it->output_sa_index);
+
+ /* *INDENT-OFF* */
+ fib_prefix_t pfx = {
+ .fp_addr = sa->tunnel_dst_addr,
+ .fp_len = (ipsec_sa_is_set_IS_TUNNEL_V6(sa) ? 128 : 32),
+ .fp_proto = (ipsec_sa_is_set_IS_TUNNEL_V6(sa) ?
+ FIB_PROTOCOL_IP6 :
+ FIB_PROTOCOL_IP4),
+ };
+ /* *INDENT-ON* */
+
+ adj_midchain_delegate_stack (ai, sa->tx_fib_index, &pfx);
+ }
+}
+
+/**
+ * @brief Call back when restacking all adjacencies on a GRE interface
+ */
+static adj_walk_rc_t
+ipsec_if_adj_walk_cb (adj_index_t ai, void *ctx)
+{
+ ipsec_if_tunnel_stack (ai);
+
+ return (ADJ_WALK_RC_CONTINUE);
+}
+
+static void
+ipsec_if_tunnel_restack (ipsec_tunnel_if_t * it)
+{
+ fib_protocol_t proto;
+
+ /*
+ * walk all the adjacencies on th GRE interface and restack them
+ */
+ FOR_EACH_FIB_IP_PROTOCOL (proto)
+ {
+ adj_nbr_walk (it->sw_if_index, proto, ipsec_if_adj_walk_cb, NULL);
+ }
+}
+
+static clib_error_t *
+ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
+{
+ ipsec_main_t *im = &ipsec_main;
+ clib_error_t *err = 0;
+ ipsec_tunnel_if_t *t;
+ vnet_hw_interface_t *hi;
+ ipsec_sa_t *sa;
+
+ hi = vnet_get_hw_interface (vnm, hw_if_index);
+ t = pool_elt_at_index (im->tunnel_interfaces, hi->hw_instance);
+ t->flags = flags;
+
+ if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
+ {
+ sa = pool_elt_at_index (im->sad, t->input_sa_index);
+
+ err = ipsec_check_support_cb (im, sa);
+ if (err)
+ return err;
+
+ err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 1);
+ if (err)
+ return err;
+
+ sa = pool_elt_at_index (im->sad, t->output_sa_index);
+
+ err = ipsec_check_support_cb (im, sa);
+ if (err)
+ return err;
+
+ err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 1);
+ if (err)
+ return err;
+
+ vnet_hw_interface_set_flags (vnm, hw_if_index,
+ VNET_HW_INTERFACE_FLAG_LINK_UP);
+ }
+ else
+ {
+ vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ );
+ sa = pool_elt_at_index (im->sad, t->input_sa_index);
+ err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 0);
+ if (err)
+ return err;
+ sa = pool_elt_at_index (im->sad, t->output_sa_index);
+ err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 0);
+ if (err)
+ return err;
+ }
+
+ ipsec_if_tunnel_restack (t);
+
+ return (NULL);