Пример #1
0
/* withdraw a connected address */
static void
connected_withdraw (struct connected *ifc)
{
  if (! ifc)
    return;

  /* Update interface address information to protocol daemon. */
  if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
    {
      zebra_interface_address_delete_update (ifc->ifp, ifc);

      if_subnet_delete (ifc->ifp, ifc);
      
      if (ifc->address->family == AF_INET)
        connected_down_ipv4 (ifc->ifp, ifc);
#ifdef HAVE_IPV6
      else
        connected_down_ipv6 (ifc->ifp, ifc);
#endif

      UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
    }

  if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
    {
	  /*  
		router_id_del_address(ifc);
	    listnode_delete (ifc->ifp->connected, ifc);
	    connected_free (ifc);*/
		
	  if(ifc->address->family == AF_INET)
	  {
		  router_id_del_address(ifc);
		  listnode_delete (ifc->ifp->connected, ifc);
		  connected_free (ifc);
	  }
	  else
	  {
		 if(!CHECK_FLAG(ifc->ipv6_config, RTMD_IPV6_ADDR_CONFIG))
		  {
			 router_id_del_address(ifc);
			 listnode_delete (ifc->ifp->connected, ifc);
			 connected_free (ifc);
		  }
		 else
		  {
			 zlog_debug("%s: line %d, Cannot delete IPv6 config addr .\n",__func__,__LINE__);
		  }
	   }
		
    }
}
Пример #2
0
static int
ospf_interface_address_delete (int command, struct zclient *zclient,
                               zebra_size_t length)
{
  struct ospf *ospf;
  struct connected *c;
  struct interface *ifp;
  struct ospf_interface *oi;
  struct route_node *rn;
  struct prefix p;

  c = zebra_interface_address_read (command, zclient->ibuf);

  if (c == NULL)
    return 0;

  if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE))
    {
      char buf[128];
      prefix2str(c->address, buf, sizeof(buf));
      zlog_debug("Zebra: interface %s address delete %s", c->ifp->name, buf);
    }

  ifp = c->ifp;
  p = *c->address;
  p.prefixlen = IPV4_MAX_PREFIXLEN;

  rn = route_node_lookup (IF_OIFS (ifp), &p);
  if (!rn)
    {
      connected_free (c);
      return 0;
    }

  assert (rn->info);
  oi = rn->info;

  /* Call interface hook functions to clean up */
  ospf_if_free (oi);

#ifdef HAVE_SNMP
  ospf_snmp_if_update (c->ifp);
#endif /* HAVE_SNMP */

  connected_free (c);

  ospf = ospf_lookup ();
  if (ospf != NULL)
    ospf_if_update (ospf);

  return 0;
}
Пример #3
0
/* communicate the withdrawal of a connected address */
static void connected_withdraw(struct connected *ifc)
{
	if (!ifc)
		return;

	/* Update interface address information to protocol daemon. */
	if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) {
		zebra_interface_address_delete_update(ifc->ifp, ifc);

		if (ifc->address->family == AF_INET)
			if_subnet_delete(ifc->ifp, ifc);

		if (ifc->address->family == AF_INET)
			connected_down_ipv4(ifc->ifp, ifc);
#ifdef HAVE_IPV6
		else
			connected_down_ipv6(ifc->ifp, ifc);
#endif

		UNSET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
	}

	/* The address is not in the kernel anymore, so clear the flag */
	UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);

	if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) {
		listnode_delete(ifc->ifp->connected, ifc);
		connected_free(ifc);
	}
}
Пример #4
0
int
ripng_interface_address_delete (int command, struct zclient *zclient,
				zebra_size_t length)
{
  struct connected *ifc;
  struct prefix *p;
  char buf[INET6_ADDRSTRLEN];

  ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, 
                                      zclient->ibuf);
  
  if (ifc)
    {
      p = ifc->address;

      if (p->family == AF_INET6)
	{
	  if (IS_RIPNG_DEBUG_ZEBRA)
	    zlog_debug ("RIPng connected address %s/%d delete",
		       inet_ntop (AF_INET6, &p->u.prefix6, buf,
				  INET6_ADDRSTRLEN),
		       p->prefixlen);

	  /* Check wether this prefix needs to be removed. */
	  ripng_apply_address_del(ifc);
	}
      connected_free (ifc);
    }

  return 0;
}
int
rip_interface_address_delete (int command, struct zclient *zclient,
			      zebra_size_t length)
{
  struct connected *ifc;
  struct prefix *p;

  ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE,
                                      zclient->ibuf);
  
  if (ifc)
    {
      p = ifc->address;
      if (p->family == AF_INET)
	{
	  if (IS_RIP_DEBUG_ZEBRA)
	    zlog_debug ("connected address %s/%d is deleted",
		       inet_ntoa (p->u.prefix4), p->prefixlen);

#ifdef HAVE_SNMP
	  rip_ifaddr_delete (ifc->ifp, ifc);
#endif /* HAVE_SNMP */

	  /* Chech wether this prefix needs to be removed */
          rip_apply_address_del(ifc);

	}

      connected_free (ifc);

    }

  return 0;
}
Пример #6
0
static int
bgp_interface_address_delete (int command, struct zclient *zclient,
			      zebra_size_t length)
{
  struct connected *ifc;

  ifc = zebra_interface_address_read (command, zclient->ibuf);

  if (ifc == NULL)
    return 0;

  if (BGP_DEBUG(zebra, ZEBRA))
    {
      char buf[128];
      prefix2str(ifc->address, buf, sizeof(buf));
      zlog_debug("Zebra rcvd: interface %s address delete %s",
		 ifc->ifp->name, buf);
    }

  if (if_is_operative (ifc->ifp))
    bgp_connected_delete (ifc);

  connected_free (ifc);

  return 0;
}
Пример #7
0
static int
rsvp_interface_address_delete (int command, struct zclient *zclient,
			       zebra_size_t length)
{
  struct connected *c;
  char buf[128];

  c = zebra_interface_address_read (command, zclient->ibuf);

  if (c == NULL)
    return 0;

  prefix2str (c->address, buf, sizeof (buf));
  zlog_debug ("Zebra: interface %s address delete %s", c->ifp->name, buf);

  if (IfIpAddrDel (c->address->u.prefix4.s_addr, c->address->prefixlen) !=
      E_OK)
    {
      zlog_err ("Cannot add IP address %s %d", __FILE__, __LINE__);
    }
  if (IpAddrSetByIfIndex (c->ifp->ifindex, 0) != E_OK)
    {
      zlog_err ("Cannot unset IP address %s %d", __FILE__, __LINE__);
    }
  DisableRsvpOnInterface (c->ifp->ifindex);

  connected_free (c);

  return 0;
}
Пример #8
0
/* Handle implicit withdrawals of addresses, where a system ADDs an address
 * to an interface which already has the same address configured.
 *
 * Returns the struct connected which must be announced to clients,
 * or NULL if nothing to do.
 */
static struct connected *
connected_implicit_withdraw (struct interface *ifp, struct connected *ifc)
{
  struct connected *current;
  
  /* Check same connected route. */
  if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
    {
      if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
        SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
	  
	  if (CHECK_FLAG (current->ipv6_config, RTMD_IPV6_ADDR_CONFIG))
		SET_FLAG (ifc->ipv6_config, RTMD_IPV6_ADDR_CONFIG);
	
      /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
       * back an address we have already added.
       */
      if (connected_same (current, ifc))
        {
          /* nothing to do */
          connected_free (ifc);
          return NULL;
        }
      
      UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
      UNSET_FLAG(current->ipv6_config, RTMD_IPV6_ADDR_CONFIG);
      connected_withdraw (current); /* implicit withdraw - freebsd does this */
    }
  return ifc;
}
Пример #9
0
/* Handle changes to addresses and send the neccesary announcements
 * to clients. */
static void connected_update(struct interface *ifp, struct connected *ifc)
{
	struct connected *current;

	/* Check same connected route. */
	if ((current = connected_check(ifp, (struct prefix *)ifc->address))) {
		if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
			SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);

		/* Avoid spurious withdraws, this might be just the kernel 'reflecting'
		 * back an address we have already added.
		 */
		if (connected_same(current, ifc)) {
			/* nothing to do */
			connected_free(ifc);
			return;
		}

		/* Clear the configured flag on the old ifc, so it will be freed by
		 * connected withdraw. */
		UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
		connected_withdraw(current);	/* implicit withdraw - freebsd does this */
	}

	/* If the connected is new or has changed, announce it, if it is usable */
	if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
		connected_announce(ifp, ifc);
}
Пример #10
0
/* Handle implicit withdrawals of addresses, where a system ADDs an address
 * to an interface which already has the same address configured.
 *
 * Returns the struct connected which must be announced to clients,
 * or NULL if nothing to do.
 */
static struct connected *
connected_implicit_withdraw (struct interface *ifp, struct connected *ifc)
{
  struct connected *current;
  
  /* Check same connected route. */
  if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
    {
      if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
        SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
	
      /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
       * back an address we have already added.
       */
      if (connected_same (current, ifc) && CHECK_FLAG(current->conf, ZEBRA_IFC_REAL))
        {
          /* nothing to do */
          connected_free (ifc);
          return NULL;
        }
      
      UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);

      if(CHECK_FLAG (current->flags, ZEBRA_IFA_EXPIRES))
      {
        SET_FLAG (ifc->flags, ZEBRA_IFA_EXPIRES);
      }
      ifc->expires = current->expires; // HSA - need to copy over address expiration info if we are to explicitly withdraw a route

      connected_withdraw (current); /* implicit withdraw - freebsd does this */
    }
  return ifc;
}
Пример #11
0
static int interface_address_delete(ZAPI_CALLBACK_ARGS)
{
	struct connected *c;

	c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);

	if (!c)
		return 0;

	connected_free(c);
	return 0;
}
Пример #12
0
/* Handle an interface delete event */
void 
if_delete_update (struct interface *ifp)
{
  struct listnode *node;
  struct listnode *next;
  struct connected *ifc;
  struct prefix *p;

  if (if_is_up(ifp))
    {
      zlog_err ("interface %s index %d is still up while being deleted.",
	    ifp->name, ifp->ifindex);
      return;
    }

  /* Mark interface as inactive */
  UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
  
  if (IS_ZEBRA_DEBUG_KERNEL)
    zlog_info ("interface %s index %d is now inactive.",
	       ifp->name, ifp->ifindex);

  /* Delete connected routes from the kernel. */
  if (ifp->connected)
    {
      for (node = listhead (ifp->connected); node; node = next)
	{
	  next = node->next;
	  ifc = getdata (node);
	  p = ifc->address;

	  if (p->family == AF_INET)
	    connected_down_ipv4 (ifp, ifc);
#ifdef HAVE_IPV6
	  else if (p->family == AF_INET6)
	    connected_down_ipv6 (ifp, ifc);
#endif /* HAVE_IPV6 */

	  zebra_interface_address_delete_update (ifp, ifc);

	  UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
	  
	  if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
	    {      
	      listnode_delete (ifp->connected, ifc);
	      connected_free (ifc);
	    }
	}
    }
  zebra_interface_delete_update (ifp);
}
Пример #13
0
int nhrp_interface_address_delete(int cmd, struct zclient *client,
				  zebra_size_t length, vrf_id_t vrf_id)
{
	struct connected *ifc;
	char buf[PREFIX_STRLEN];

	ifc = zebra_interface_address_read(cmd, client->ibuf, vrf_id);
	if (ifc == NULL)
		return 0;

	debugf(NHRP_DEBUG_IF, "if-addr-del: %s: %s",
		ifc->ifp->name,
		prefix2str(ifc->address, buf, sizeof buf));

	nhrp_interface_update_address(ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0);
	connected_free(ifc);

	return 0;
}
Пример #14
0
int
isis_zebra_if_address_del (int command, struct zclient *client,
                           zebra_size_t length)
{
    struct connected *c;
    struct interface *ifp;
#ifdef EXTREME_DEBUG
    struct prefix *p;
    u_char buf[BUFSIZ];
#endif /* EXTREME_DEBUG */

    c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE,
                                      zclient->ibuf);

    if (c == NULL)
        return 0;

    ifp = c->ifp;

#ifdef EXTREME_DEBUG
    p = c->address;
    prefix2str (p, buf, BUFSIZ);

    if (p->family == AF_INET)
        zlog_debug ("disconnected IP address %s", buf);
#ifdef HAVE_IPV6
    if (p->family == AF_INET6)
        zlog_debug ("disconnected IPv6 address %s", buf);
#endif /* HAVE_IPV6 */
#endif /* EXTREME_DEBUG */

    if (if_is_operative (ifp))
        isis_circuit_del_addr (circuit_scan_by_ifp (ifp), c);
    connected_free (c);

    return 0;
}
Пример #15
0
static int ldp_interface_address_delete(int command, struct zclient *zclient,
    zebra_size_t length) {
    struct ldp *ldp = ldp_get();
    struct connected *c;
    struct interface *ifp;
    struct prefix *p;
    struct ldp_addr addr;
    struct ldp_if iff;
    struct ldp_interface *li;

    c = zebra_interface_address_read(command, zclient->ibuf);
    if (c == NULL || c->address->family != AF_INET) {
	return 0;
    }

    ifp = c->ifp;
    p = c->address;

    zlog_info("address delete %s from interface %s",
	inet_ntoa(p->u.prefix4), ifp->name);

    if (ldp) {
	prefix2mpls_inet_addr(p, &addr.address);
	iff.handle = ifp;
	ldp_cfg_if_addr_set(ldp->h, &iff, &addr, LDP_CFG_DEL);

	li = ifp->info;
	if (ldp->trans_addr == LDP_TRANS_ADDR_STATIC_INTERFACE &&
	    !strncmp(ldp->trans_addr_ifname,ifp->name,IFNAMSIZ + 1)) {
	    ldp_global g;

	    zlog_info("updating global transport address");
	    g.transport_address.u.ipv4 = ntohl(if_ipv4_src_address (ifp));
	    g.transport_address.type =
		(g.transport_address.u.ipv4)?MPLS_FAMILY_IPV4:MPLS_FAMILY_NONE;
	    ldp_admin_state_start(ldp);
	    ldp_cfg_global_set(ldp->h,&g, LDP_GLOBAL_CFG_TRANS_ADDR);
	    ldp_admin_state_finish(ldp);
	}
	if (ldp->trans_addr == LDP_TRANS_ADDR_INTERFACE) {
	    zlog_info("updating entity transport address");
	    li->entity.transport_address.u.ipv4 =
		ntohl(if_ipv4_src_address (ifp));

	    li->entity.transport_address.type =
		li->entity.transport_address.u.ipv4 ?
		MPLS_FAMILY_IPV4 : MPLS_FAMILY_NONE;

	    if (li->entity.index) {
		ldp_interface_admin_state_start(li);
		ldp_cfg_entity_set(ldp->h, &li->entity,
		    LDP_ENTITY_CFG_TRANS_ADDR);
		ldp_interface_admin_state_finish(li);
	    }
	}
    }

    connected_free(c);

    return 0;
}
Пример #16
0
void eigrp_zebra_init(void)
{
	struct zclient_options opt = {.receive_notify = false};

	zclient = zclient_new_notify(master, &opt);

	zclient_init(zclient, ZEBRA_ROUTE_EIGRP, 0, &eigrpd_privs);
	zclient->zebra_connected = eigrp_zebra_connected;
	zclient->router_id_update = eigrp_router_id_update_zebra;
	zclient->interface_add = eigrp_interface_add;
	zclient->interface_delete = eigrp_interface_delete;
	zclient->interface_up = eigrp_interface_state_up;
	zclient->interface_down = eigrp_interface_state_down;
	zclient->interface_address_add = eigrp_interface_address_add;
	zclient->interface_address_delete = eigrp_interface_address_delete;
	zclient->redistribute_route_add = eigrp_zebra_read_route;
	zclient->redistribute_route_del = eigrp_zebra_read_route;
	zclient->route_notify_owner = eigrp_zebra_route_notify_owner;
}


/* Zebra route add and delete treatment. */
static int eigrp_zebra_read_route(int command, struct zclient *zclient,
				  zebra_size_t length, vrf_id_t vrf_id)
{
	struct zapi_route api;
	struct eigrp *eigrp;

	if (zapi_route_decode(zclient->ibuf, &api) < 0)
		return -1;

	if (IPV4_NET127(ntohl(api.prefix.u.prefix4.s_addr)))
		return 0;

	eigrp = eigrp_lookup();
	if (eigrp == NULL)
		return 0;

	if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) {

	} else /* if (command == ZEBRA_REDISTRIBUTE_ROUTE_DEL) */
	{
	}

	return 0;
}

/* Inteface addition message from zebra. */
static int eigrp_interface_add(int command, struct zclient *zclient,
			       zebra_size_t length, vrf_id_t vrf_id)
{
	struct interface *ifp;
	struct eigrp_interface *ei;

	ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);

	if (!ifp->info)
		return 0;

	ei = ifp->info;

	ei->params.type = eigrp_default_iftype(ifp);

	eigrp_if_update(ifp);

	return 0;
}

static int eigrp_interface_delete(int command, struct zclient *zclient,
				  zebra_size_t length, vrf_id_t vrf_id)
{
	struct interface *ifp;
	struct stream *s;

	s = zclient->ibuf;
	/* zebra_interface_state_read () updates interface structure in iflist
	 */
	ifp = zebra_interface_state_read(s, vrf_id);

	if (ifp == NULL)
		return 0;

	if (if_is_up(ifp))
		zlog_warn("Zebra: got delete of %s, but interface is still up",
			  ifp->name);

	if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
		zlog_debug(
			"Zebra: interface delete %s index %d flags %llx metric %d mtu %d",
			ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
			ifp->metric, ifp->mtu);

	if (ifp->info)
		eigrp_if_free(ifp->info, INTERFACE_DOWN_BY_ZEBRA);

	if_set_index(ifp, IFINDEX_INTERNAL);
	return 0;
}

static int eigrp_interface_address_add(int command, struct zclient *zclient,
				       zebra_size_t length, vrf_id_t vrf_id)
{
	struct connected *c;

	c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);

	if (c == NULL)
		return 0;

	if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) {
		char buf[128];
		prefix2str(c->address, buf, sizeof(buf));
		zlog_debug("Zebra: interface %s address add %s", c->ifp->name,
			   buf);
	}

	eigrp_if_update(c->ifp);

	return 0;
}

static int eigrp_interface_address_delete(int command, struct zclient *zclient,
					  zebra_size_t length, vrf_id_t vrf_id)
{
	struct connected *c;
	struct interface *ifp;
	struct eigrp_interface *ei;

	c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);

	if (c == NULL)
		return 0;

	if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) {
		char buf[128];
		prefix2str(c->address, buf, sizeof(buf));
		zlog_debug("Zebra: interface %s address delete %s",
			   c->ifp->name, buf);
	}

	ifp = c->ifp;
	ei = ifp->info;
	if (!ei)
		return 0;

	/* Call interface hook functions to clean up */
	eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA);

	connected_free(c);

	return 0;
}

static int eigrp_interface_state_up(int command, struct zclient *zclient,
				    zebra_size_t length, vrf_id_t vrf_id)
{
	struct interface *ifp;

	ifp = zebra_interface_if_lookup(zclient->ibuf);

	if (ifp == NULL)
		return 0;

	/* Interface is already up. */
	if (if_is_operative(ifp)) {
		/* Temporarily keep ifp values. */
		struct interface if_tmp;
		memcpy(&if_tmp, ifp, sizeof(struct interface));

		zebra_interface_if_set_value(zclient->ibuf, ifp);

		if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
			zlog_debug("Zebra: Interface[%s] state update.",
				   ifp->name);

		if (if_tmp.bandwidth != ifp->bandwidth) {
			if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
				zlog_debug(
					"Zebra: Interface[%s] bandwidth change %d -> %d.",
					ifp->name, if_tmp.bandwidth,
					ifp->bandwidth);

			//          eigrp_if_recalculate_output_cost (ifp);
		}

		if (if_tmp.mtu != ifp->mtu) {
			if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
				zlog_debug(
					"Zebra: Interface[%s] MTU change %u -> %u.",
					ifp->name, if_tmp.mtu, ifp->mtu);

			/* Must reset the interface (simulate down/up) when MTU
			 * changes. */
			eigrp_if_reset(ifp);
		}
		return 0;
	}

	zebra_interface_if_set_value(zclient->ibuf, ifp);

	if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
		zlog_debug("Zebra: Interface[%s] state change to up.",
			   ifp->name);

	if (ifp->info)
		eigrp_if_up(ifp->info);

	return 0;
}

static int eigrp_interface_state_down(int command, struct zclient *zclient,
				      zebra_size_t length, vrf_id_t vrf_id)
{
	struct interface *ifp;

	ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);

	if (ifp == NULL)
		return 0;

	if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE))
		zlog_debug("Zebra: Interface[%s] state change to down.",
			   ifp->name);

	if (ifp->info)
		eigrp_if_down(ifp->info);

	return 0;
}

static struct interface *zebra_interface_if_lookup(struct stream *s)
{
	char ifname_tmp[INTERFACE_NAMSIZ];

	/* Read interface name. */
	stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);

	/* And look it up. */
	return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
}
Пример #17
0
/* Handle an interface delete event */
void 
if_delete_update (struct interface *ifp)
{
  struct connected *ifc;
  struct prefix *p;
  struct route_node *rn;
  struct zebra_if *zebra_if;

  zebra_if = ifp->info;

  if (if_is_up(ifp))
    {
      zlog_err ("interface %s index %d is still up while being deleted.",
	    ifp->name, ifp->ifindex);
      return;
    }

  /* Mark interface as inactive */
  UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
  
  if (IS_ZEBRA_DEBUG_KERNEL)
    zlog_debug ("interface %s index %d is now inactive.",
	       ifp->name, ifp->ifindex);

  /* Delete connected routes from the kernel. */
  if (ifp->connected)
    {
      struct listnode *node;
      struct listnode *last = NULL;

      while ((node = (last ? last->next : listhead (ifp->connected))))
	{
	  ifc = listgetdata (node);
	  p = ifc->address;
	  
	  if (p->family == AF_INET
	      && (rn = route_node_lookup (zebra_if->ipv4_subnets, p)))
	    {
	      struct listnode *anode;
	      struct listnode *next;
	      struct listnode *first;
	      struct list *addr_list;
	      
	      route_unlock_node (rn);
	      addr_list = (struct list *) rn->info;
	      
	      /* Remove addresses, secondaries first. */
	      first = listhead (addr_list);
	      for (anode = first->next; anode || first; anode = next)
		{
		  if (!anode)
		    {
		      anode = first;
		      first = NULL;
		    }
		  next = anode->next;

		  ifc = listgetdata (anode);
		  p = ifc->address;

		  connected_down_ipv4 (ifp, ifc);

		  zebra_interface_address_delete_update (ifp, ifc);

		  UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);

		  /* Remove from subnet chain. */
		  list_delete_node (addr_list, anode);
		  route_unlock_node (rn);
		  
		  /* Remove from interface address list (unconditionally). */
		  if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
		    {
		      listnode_delete (ifp->connected, ifc);
		      connected_free (ifc);
                    }
                  else
                    last = node;
		}

	      /* Free chain list and respective route node. */
	      list_delete (addr_list);
	      rn->info = NULL;
	      route_unlock_node (rn);
	    }
#ifdef HAVE_IPV6
	  else if (p->family == AF_INET6)
	    {
	      connected_down_ipv6 (ifp, ifc);

	      zebra_interface_address_delete_update (ifp, ifc);

	      UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);

	      if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
		last = node;
	      else
		{
		  listnode_delete (ifp->connected, ifc);
		  connected_free (ifc);
		}
	    }
#endif /* HAVE_IPV6 */
	  else
	    {
	      last = node;
	    }
	}
    }
  zebra_interface_delete_update (ifp);

  /* Update ifindex after distributing the delete message.  This is in
     case any client needs to have the old value of ifindex available
     while processing the deletion.  Each client daemon is responsible
     for setting ifindex to IFINDEX_INTERNAL after processing the
     interface deletion message. */
  ifp->ifindex = IFINDEX_INTERNAL;
}