Ejemplo n.º 1
0
/**
 * @fn eigrp_nbr_hard_restart
 *
 * @param[in]		nbr	Neighbor who would receive hard restart
 * @param[in]		vty Virtual terminal for log output
 * @return void
 *
 * @par
 * Function used for executing hard restart for neighbor:
 * Send Hello packet with Peer Termination TLV with
 * neighbor's address, set it's state to DOWN and delete the neighbor
 */
void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty)
{
	if(nbr == NULL)
	{
		zlog_err("Nbr Hard restart: Neighbor not specified.");
		return;
	}

	zlog_debug ("Neighbor %s (%s) is down: manually cleared",
			inet_ntoa (nbr->src),
			ifindex2ifname (nbr->ei->ifp->ifindex));
	if(vty != NULL)
	{
		vty_time_print (vty, 0);
		vty_out (vty, "Neighbor %s (%s) is down: manually cleared%s",
				inet_ntoa (nbr->src),
				ifindex2ifname (nbr->ei->ifp->ifindex),
				VTY_NEWLINE);
	}

	/* send Hello with Peer Termination TLV */
	eigrp_hello_send(nbr->ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR, &(nbr->src));
	/* set neighbor to DOWN */
	nbr->state = EIGRP_NEIGHBOR_DOWN;
	/* delete neighbor */
	eigrp_nbr_delete (nbr);
}
Ejemplo n.º 2
0
static int
bfd_ioctl_peer_info (struct bfd_nl_peerinfo *peer, struct vty *vty)
{
	char buf1[BUFSIZ], buf2[BUFSIZ];

	vty_out (vty, "%s",
	    inet_ntop (peer->dst.sa.sa_family,
		peer->dst.sa.sa_family == AF_INET ?
		(char *) &peer->dst.sin.sin_addr
		: (char *) &peer->dst.sin6.sin6_addr, buf1, BUFSIZ));
	vty_out (vty, "  %u %u  %s %s%s",
	    ntohl (peer->my_disc),
	    ntohl (peer->your_disc),
	    bfd_state_string[peer->state],
	    ifindex2ifname (peer->ifindex), VTY_NEWLINE);

	vty_out (vty, "  SrcIP: %s%s",
	    inet_ntop (peer->src.sa.sa_family,
		peer->src.sa.sa_family == AF_INET ?
		(char *) &peer->src.sin.sin_addr
		: (char *) &peer->src.sin6.sin6_addr, buf2, BUFSIZ),
	    VTY_NEWLINE);

	vty_out (vty, "  Packet Rcvd: %llu%s", peer->pkt_in, VTY_NEWLINE);
	vty_out (vty, "  Packet Send: %llu%s", peer->pkt_out, VTY_NEWLINE);
	vty_out (vty, "  Last UpTime(sysUptime): %u%s", peer->last_up, VTY_NEWLINE);
	vty_out (vty, "  Last DownTime(sysUptime): %u%s",
	    peer->last_down, VTY_NEWLINE);
	vty_out (vty, "  Up Count: %u%s", peer->up_cnt, VTY_NEWLINE);

	return 0;
}
Ejemplo n.º 3
0
/**
 * @fn eigrp_update_send_GR
 *
 * @param[in]		nbr			Neighbor who would receive Graceful restart
 * @param[in]		gr_type 	Who executed Graceful restart
 * @param[in]		vty 		Virtual terminal for log output
 *
 * @return void
 *
 * @par
 * Function used for sending Graceful restart Update packet:
 * Creates Update packet with INIT, RS, EOT flags and include
 * all route except those filtered
 */
void
eigrp_update_send_GR (struct eigrp_neighbor *nbr, enum GR_type gr_type, struct vty *vty)
{
	struct eigrp_prefix_entry *pe2;
	struct listnode *node2, *nnode2;
	struct list *prefixes;

	if(gr_type == EIGRP_GR_FILTER)
	{
		/* function was called after applying filtration */
		zlog_info("Neighbor %s (%s) is resync: route configuration changed",
				  inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
	}
	else if(gr_type == EIGRP_GR_MANUAL)
	{
		/* Graceful restart was called manually */
		zlog_info("Neighbor %s (%s) is resync: manually cleared",
				  inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));

		if(vty != NULL)
		{
			vty_time_print (vty, 0);
			vty_out (vty, "Neighbor %s (%s) is resync: manually cleared%s",
					inet_ntoa (nbr->src),
					ifindex2ifname (nbr->ei->ifp->ifindex),
					VTY_NEWLINE);
		}
	}

	prefixes = list_new();
	/* add all prefixes from topology table to list */
	for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node2, nnode2, pe2))
	{
		listnode_add(prefixes, pe2);
	}

	/* save prefixes to neighbor */
	nbr->nbr_gr_prefixes_send = prefixes;
	/* indicate, that this is first GR Update packet chunk */
	nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_FIRST;
	/* execute packet sending in thread */
	nbr->t_nbr_send_gr = thread_execute(master, eigrp_update_send_GR_thread, nbr, 0);
}
Ejemplo n.º 4
0
static void
print_nh (struct nexthop *nexthop, struct vty *vty)
{
  char buf[BUFSIZ];

  switch (nexthop->type)
    {
    case NEXTHOP_TYPE_IPV4:
    case NEXTHOP_TYPE_IPV4_IFINDEX:
      vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
      if (nexthop->ifindex)
	vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
      break;
    case NEXTHOP_TYPE_IPV6:
    case NEXTHOP_TYPE_IPV6_IFINDEX:
    case NEXTHOP_TYPE_IPV6_IFNAME:
      vty_out (vty, " %s",
	       inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
      if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
	vty_out (vty, ", %s", nexthop->ifname);
      else if (nexthop->ifindex)
	vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
      break;
    case NEXTHOP_TYPE_IFINDEX:
      vty_out (vty, " is directly connected, %s",
	       ifindex2ifname (nexthop->ifindex));
      break;
    case NEXTHOP_TYPE_IFNAME:
      vty_out (vty, " is directly connected, %s", nexthop->ifname);
      break;
    case NEXTHOP_TYPE_BLACKHOLE:
      vty_out (vty, " is directly connected, Null0");
      break;
    default:
      break;
    }
  vty_out(vty, "%s", VTY_NEWLINE);
}
Ejemplo n.º 5
0
int
holddown_timer_expired (struct thread *thread)
{
  struct eigrp_neighbor *nbr;

  nbr = THREAD_ARG (thread);

  zlog_info ("Neighbor %s (%s) is down: holding time expired",
	     inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
  nbr->state = EIGRP_NEIGHBOR_DOWN;
  eigrp_nbr_delete (nbr);

  return 0;
}
Ejemplo n.º 6
0
/*
 * EIGRP UPDATE read function
 */
void
eigrp_update_receive (struct eigrp *eigrp, struct ip *iph, struct eigrp_header *eigrph,
                      struct stream * s, struct eigrp_interface *ei, int size)
{
  struct eigrp_neighbor *nbr;
  struct TLV_IPv4_Internal_type *tlv;
  struct eigrp_prefix_entry *pe;
  struct eigrp_neighbor_entry *ne;
  u_int32_t flags;
  u_int16_t type;
  uint16_t  length;
  u_char same;
  struct access_list *alist;
  struct prefix_list *plist;
  struct eigrp *e;
  u_char graceful_restart;
  u_char graceful_restart_final;
  struct list *nbr_prefixes;
  int ret;

  /* increment statistics. */
  ei->update_in++;

  /* get neighbor struct */
  nbr = eigrp_nbr_get(ei, eigrph, iph);

  /* neighbor must be valid, eigrp_nbr_get creates if none existed */
  assert(nbr);

  flags = ntohl(eigrph->flags);

  if (flags & EIGRP_CR_FLAG)
    {
      return;
    }

  same = 0;
  graceful_restart = 0;
  graceful_restart_final = 0;
  if((nbr->recv_sequence_number) == (ntohl(eigrph->sequence)))
      same = 1;

  nbr->recv_sequence_number = ntohl(eigrph->sequence);
  if (IS_DEBUG_EIGRP_PACKET(0, RECV))
    zlog_debug("Processing Update size[%u] int(%s) nbr(%s) seq [%u] flags [%0x]",
               size, ifindex2ifname(nbr->ei->ifp->ifindex),
               inet_ntoa(nbr->src),
               nbr->recv_sequence_number, flags);


    if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG+EIGRP_EOT_FLAG)) && (!same))
    {
    	/* Graceful restart Update received with all routes */

		zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
				  inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));

		/* get all prefixes from neighbor from topology table */
    	nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
    	graceful_restart = 1;
    	graceful_restart_final = 1;
    }
    else if((flags == (EIGRP_INIT_FLAG+EIGRP_RS_FLAG)) && (!same))
    {
    	/* Graceful restart Update received, routes also in next packet */

		zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
				  inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));

		/* get all prefixes from neighbor from topology table */
    	nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
    	/* save prefixes to neighbor for later use */
    	nbr->nbr_gr_prefixes = nbr_prefixes;
    	graceful_restart = 1;
    	graceful_restart_final = 0;
    }
    else if((flags == (EIGRP_EOT_FLAG)) && (!same))
	{
		/* If there was INIT+RS Update packet before,
		 *  consider this as GR EOT */

		if(nbr->nbr_gr_prefixes != NULL)
		{
			/* this is final packet of GR */
			nbr_prefixes = nbr->nbr_gr_prefixes;
			nbr->nbr_gr_prefixes = NULL;

			graceful_restart = 1;
			graceful_restart_final = 1;
		}

	}
    else if((flags == (0)) && (!same))
	{
		/* If there was INIT+RS Update packet before,
		 *  consider this as GR not final packet */

		if(nbr->nbr_gr_prefixes != NULL)
		{
			/* this is GR not final route packet */
			nbr_prefixes = nbr->nbr_gr_prefixes;

			graceful_restart = 1;
			graceful_restart_final = 0;
		}

	}
    else if((flags & EIGRP_INIT_FLAG) && (!same))
    {   /* When in pending state, send INIT update only if it wasn't
        already sent before (only if init_sequence is 0) */
        if((nbr->state == EIGRP_NEIGHBOR_PENDING) && (nbr->init_sequence_number == 0))
          eigrp_update_send_init(nbr);

        if (nbr->state == EIGRP_NEIGHBOR_UP)
          {
            eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
            eigrp_topology_neighbor_down(nbr->ei->eigrp,nbr);
            nbr->recv_sequence_number = ntohl(eigrph->sequence);
            zlog_info("Neighbor %s (%s) is down: peer restarted",
                      inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
            eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING);
            zlog_info("Neighbor %s (%s) is pending: new adjacency",
                      inet_ntoa(nbr->src), ifindex2ifname(nbr->ei->ifp->ifindex));
            eigrp_update_send_init(nbr);
          }
    }

  /*If there is topology information*/
  while (s->endp > s->getp)
    {
      type = stream_getw(s);
      if (type == EIGRP_TLV_IPv4_INT)
        {
          stream_set_getp(s, s->getp - sizeof(u_int16_t));

          tlv = eigrp_read_ipv4_tlv(s);

          /*searching if destination exists */
          struct prefix_ipv4 *dest_addr;
          dest_addr = prefix_ipv4_new();
          dest_addr->prefix = tlv->destination;
          dest_addr->prefixlen = tlv->prefix_length;
          struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4(
              eigrp->topology_table, dest_addr);

          /*if exists it comes to DUAL*/
          if (dest != NULL)
            {
        	  /* remove received prefix from neighbor prefix list if in GR */
        	  if(graceful_restart)
        		  remove_received_prefix_gr(nbr_prefixes, dest);

              struct eigrp_fsm_action_message *msg;
              msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
                  sizeof(struct eigrp_fsm_action_message));
              struct eigrp_neighbor_entry *entry =
                  eigrp_prefix_entry_lookup(dest->entries, nbr);

              msg->packet_type = EIGRP_OPC_UPDATE;
              msg->eigrp = eigrp;
              msg->data_type = EIGRP_TLV_IPv4_INT;
              msg->adv_router = nbr;
              msg->data.ipv4_int_type = tlv;
              msg->entry = entry;
              msg->prefix = dest;
              int event = eigrp_get_fsm_event(msg);
              eigrp_fsm_event(msg, event);
            }
          else
            {
              /*Here comes topology information save*/
              pe = eigrp_prefix_entry_new();
              pe->serno = eigrp->serno;
              pe->destination_ipv4 = dest_addr;
              pe->af = AF_INET;
              pe->state = EIGRP_FSM_STATE_PASSIVE;
              pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE;

              ne = eigrp_neighbor_entry_new();
              ne->ei = ei;
              ne->adv_router = nbr;
              ne->reported_metric = tlv->metric;
              ne->reported_distance = eigrp_calculate_metrics(eigrp,
                  &tlv->metric);

              //TODO: Work in progress
              /*
               * Filtering
               */
        	  e = eigrp_lookup();
        	  /* get access-list from eigrp process */
        	  alist = e->list[EIGRP_FILTER_IN];
			  zlog_info("PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix));
			  if (alist) {
				  zlog_info ("ALIST PROC IN: %s", alist->name);
			  } else {
				  zlog_info("ALIST PROC IN je prazdny");
			  }

			  /* Check if access-list fits */
			  if (alist && access_list_apply (alist,
						 (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
				  zlog_info("PROC alist IN: Skipping");
				  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
				  zlog_info("PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix));
				  eigrp_IPv4_InternalTLV_free (tlv);
				  continue;
			  } else {
				  zlog_info("PROC alist IN: NENastavujem metriku ");
			  }

			  plist = e->prefix[EIGRP_FILTER_IN];

			  if (plist) {
				  zlog_info ("PLIST PROC IN: %s", plist->name);
			  } else {
				  zlog_info("PLIST PROC IN je prazdny");
			  }

			  /* Check if prefix-list fits */
			  if (plist && prefix_list_apply (plist,
						 (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
				  zlog_info("PLIST PROC IN: Skipping");
				  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
				  zlog_info("PLIST PROC IN Prefix: %s", inet_ntoa(dest_addr->prefix));
				  eigrp_IPv4_InternalTLV_free (tlv);
				  continue;
			  } else {
				  zlog_info("PLIST PROC IN: NENastavujem metriku ");
			  }

			  //Check route-map

			  /*if (e->routemap[EIGRP_FILTER_IN])
			  {
			  	 ret = route_map_apply (e->routemap[EIGRP_FILTER_IN],
			  				   (struct prefix *)dest_addr, RMAP_EIGRP, NULL);

			  	 if (ret == RMAP_DENYMATCH)
			  	 {
			  	    zlog_debug ("%s is filtered by route-map",inet_ntoa (dest_addr->prefix));
			  	    continue;
			  	 }
			  }*/

			  /*Get access-list from current interface */
			  zlog_info("Checking access_list on interface: %s",ei->ifp->name);
			  alist = ei->list[EIGRP_FILTER_IN];
			  if (alist) {
			  	  zlog_info ("ALIST INT IN: %s", alist->name);
			  } else {
			  	  zlog_info("ALIST INT IN je prazdny");
			  	}

			  /* Check if access-list fits */
			  if (alist && access_list_apply (alist, (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
			  	  zlog_info("INT alist IN: Skipping");
			  	  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
			  	  zlog_info("INT IN Prefix: %s", inet_ntoa(dest_addr->prefix));
			  	  eigrp_IPv4_InternalTLV_free (tlv);
			  	  continue;
			  	} else {
			  	  zlog_info("INT IN: NENastavujem metriku ");
			  }

			  plist = ei->prefix[EIGRP_FILTER_IN];

			  if (plist) {
				  zlog_info ("PLIST INT IN: %s", plist->name);
			  } else {
				  zlog_info("PLIST INT IN je prazdny");
			  }

			  /* Check if prefix-list fits */
			  if (plist && prefix_list_apply (plist,
						 (struct prefix *) dest_addr) == FILTER_DENY)
			  {
				  /* If yes, set reported metric to Max */
				  zlog_info("PLIST INT IN: Skipping");
				  //ne->reported_metric.delay = EIGRP_MAX_METRIC;
				  zlog_info("PLIST INT IN Prefix: %s", inet_ntoa(dest_addr->prefix));
				  eigrp_IPv4_InternalTLV_free (tlv);
				  continue;
			  } else {
				  zlog_info("PLIST INT IN: NENastavujem metriku ");
			  }

			  //Check route-map

			  /*if (ei->routemap[EIGRP_FILTER_IN])
			  {
				 ret = route_map_apply (ei->routemap[EIGRP_FILTER_IN],
							   (struct prefix *)dest_addr, RMAP_EIGRP, NULL);

				 if (ret == RMAP_DENYMATCH)
				 {
					zlog_debug ("%s is filtered by route-map",inet_ntoa (dest_addr->prefix));
					continue;
				 }
			  }*/
			  /*
			   * End of filtering
			   */

			  ne->distance = eigrp_calculate_total_metrics(eigrp, ne);

			  zlog_info("<DEBUG PROC IN Distance: %x", ne->distance);
			  zlog_info("<DEBUG PROC IN Delay: %x", ne->total_metric.delay);

              pe->fdistance = pe->distance = pe->rdistance =
                  ne->distance;
              ne->prefix = pe;
              ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;

              eigrp_prefix_entry_add(eigrp->topology_table, pe);
              eigrp_neighbor_entry_add(pe, ne);
              pe->distance = pe->fdistance = pe->rdistance = ne->distance;
              pe->reported_metric = ne->total_metric;
              eigrp_topology_update_node_flags(pe);

              pe->req_action |= EIGRP_FSM_NEED_UPDATE;
              listnode_add(eigrp->topology_changes_internalIPV4, pe);
            }
          eigrp_IPv4_InternalTLV_free (tlv);
        }
    }

    /* ask about prefixes not present in GR update,
     * if this is final GR packet */
    if(graceful_restart_final)
    {
    	eigrp_update_receive_GR_ask(eigrp, nbr, nbr_prefixes);
    }

  /*
   * We don't need to send separate Ack for INIT Update. INIT will be acked in EOT Update.
   */
  if ((nbr->state == EIGRP_NEIGHBOR_UP) && !(flags == EIGRP_INIT_FLAG))
    {
      eigrp_hello_send_ack(nbr);
    }

  eigrp_query_send_all(eigrp);
  eigrp_update_send_all(eigrp, ei);
}
Ejemplo n.º 7
0
static int
show_ip_bgp_nexthop_table (struct vty *vty, int detail)
{
  struct bgp_node *rn;
  struct bgp_nexthop_cache *bnc;
  char buf[INET6_ADDRSTRLEN];
  struct nexthop *nexthop;
  time_t tbuf;
  afi_t afi;

  vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE);
  for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
    {
      if (!bgp_nexthop_cache_table[afi])
        continue;
      
      for (rn = bgp_table_top (bgp_nexthop_cache_table[afi]); rn; rn = bgp_route_next (rn))
	{
	  if ((bnc = rn->info) != NULL)
	    {
	      if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID))
		{
		  vty_out (vty, " %s valid [IGP metric %d], #paths %d%s",
			   inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)),
			   bnc->metric, bnc->path_count, VTY_NEWLINE);
		  if (detail)
		    for (nexthop = bnc->nexthop ; nexthop; nexthop = nexthop->next)
		      switch (nexthop->type)
			{
			case NEXTHOP_TYPE_IPV6:
			  vty_out (vty, "  gate %s%s",
				   inet_ntop (AF_INET6, &nexthop->gate.ipv6,
					      buf, INET6_ADDRSTRLEN), VTY_NEWLINE);
			  break;
			case NEXTHOP_TYPE_IPV6_IFINDEX:
			  vty_out(vty, "  gate %s, if %s%s",
				  inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
					    INET6_ADDRSTRLEN),
				  ifindex2ifname(nexthop->ifindex),
				  VTY_NEWLINE);
			  break;
			case NEXTHOP_TYPE_IPV4:
			  vty_out (vty, "  gate %s%s",
				   inet_ntop (AF_INET, &nexthop->gate.ipv4, buf,
					      INET6_ADDRSTRLEN), VTY_NEWLINE);
			  break;
			case NEXTHOP_TYPE_IFINDEX:
			  vty_out (vty, "  if %s%s",
				   ifindex2ifname(nexthop->ifindex), VTY_NEWLINE);
			  break;
			case NEXTHOP_TYPE_IPV4_IFINDEX:
			  vty_out (vty, "  gate %s, if %s%s",
				   inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
					     INET6_ADDRSTRLEN),
				   ifindex2ifname(nexthop->ifindex), VTY_NEWLINE);
			  break;
			default:
			  vty_out (vty, "  invalid nexthop type %u%s",
				   nexthop->type, VTY_NEWLINE);
			}
		}
	      else
		vty_out (vty, " %s invalid%s",
			 inet_ntop (AF_INET, &rn->p.u.prefix, buf, sizeof (buf)), VTY_NEWLINE);
#ifdef HAVE_CLOCK_MONOTONIC
	      tbuf = time(NULL) - (bgp_clock() - bnc->last_update);
	      vty_out (vty, "  Last update: %s", ctime(&tbuf));
#else
	      vty_out (vty, "  Last update: %s", ctime(&bnc->uptime));
#endif /* HAVE_CLOCK_MONOTONIC */
	      vty_out(vty, "%s", VTY_NEWLINE);
	    }
	}
    }
  return CMD_SUCCESS;
}
Ejemplo n.º 8
0
static int fib_lookup_if_vif_index(struct in_addr addr)
{
  struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
  int num_ifindex;
  int vif_index;
  int first_ifindex;

  num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
				       PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
				       PIM_NEXTHOP_LOOKUP_MAX);
  if (num_ifindex < 1) {
    char addr_str[100];
    pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
    zlog_warn("%s %s: could not find nexthop ifindex for address %s",
	      __FILE__, __PRETTY_FUNCTION__,
	      addr_str);
    return -1;
  }
  
  first_ifindex = nexthop_tab[0].ifindex;
  
  if (num_ifindex > 1) {
    char addr_str[100];
    pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
    zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
	       __FILE__, __PRETTY_FUNCTION__,
	       num_ifindex, addr_str, first_ifindex);
    /* debug warning only, do not return */
  }
  
  if (PIM_DEBUG_ZEBRA) {
    char addr_str[100];
    pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
    zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
	       __FILE__, __PRETTY_FUNCTION__,
	       first_ifindex, ifindex2ifname(first_ifindex), addr_str);
  }

  vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);

  if (vif_index < 1) {
    char addr_str[100];
    pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
    zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
	      __FILE__, __PRETTY_FUNCTION__,
	      vif_index, addr_str);
    return -2;
  }

  zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);

  if (vif_index > qpim_mroute_oif_highest_vif_index) {
    char addr_str[100];
    pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
    zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
	      __FILE__, __PRETTY_FUNCTION__,
	      vif_index, qpim_mroute_oif_highest_vif_index, addr_str);

    zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
	      __FILE__, __PRETTY_FUNCTION__,
	      ifindex2ifname(vif_index),
	      vif_index);

    return -3;
  }

  return vif_index;
}