/* Kernel routing table read up by sysctl function. */
void
route_read (void)
{
  caddr_t buf, end, ref;
  size_t bufsiz;
  struct rt_msghdr *rtm;
  
#define MIBSIZ 6
  int mib[MIBSIZ] = 
  {
    CTL_NET,
    PF_ROUTE,
    0,
    0,
    NET_RT_DUMP,
    0
  };
		      
  /* Get buffer size. */
  if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) 
    {
      zlog_warn ("sysctl fail: %s", safe_strerror (errno));
      return;
    }

  /* Allocate buffer. */
  ref = buf = XMALLOC (MTYPE_TMP, bufsiz);
  
  /* Read routing table information by calling sysctl(). */
  if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) 
    {
      zlog_warn ("sysctl() fail by %s", safe_strerror (errno));
      return;
    }

  for (end = buf + bufsiz; buf < end; buf += rtm->rtm_msglen) 
    {
      rtm = (struct rt_msghdr *) buf;
      rtm_read (rtm);
    }

  /* Free buffer. */
  XFREE (MTYPE_TMP, ref);

  return;
}
/* Kernel routing table and interface updates via routing socket. */
int
kernel_read (struct thread *thread)
{
  int sock;
  int nbytes;
  struct rt_msghdr *rtm;

  union 
  {
    /* Routing information. */
    struct 
    {
      struct rt_msghdr rtm;
      struct sockaddr addr[RTAX_MAX];
    } r;

    /* Interface information. */
    struct
    {
      struct if_msghdr ifm;
      struct sockaddr addr[RTAX_MAX];
    } im;

    /* Interface address information. */
    struct
    {
      struct ifa_msghdr ifa;
      struct sockaddr addr[RTAX_MAX];
    } ia;

#ifdef RTM_IFANNOUNCE
    /* Interface arrival/departure */
    struct
    {
      struct if_announcemsghdr ifan;
      struct sockaddr addr[RTAX_MAX];
    } ian;
#endif /* RTM_IFANNOUNCE */

  } buf;

  /* Fetch routing socket. */
  sock = THREAD_FD (thread);

  nbytes= read (sock, &buf, sizeof buf);

  if (nbytes <= 0)
    {
      if (nbytes < 0 && errno != EWOULDBLOCK)
	zlog_warn ("routing socket error: %s", strerror (errno));
      return 0;
    }

  thread_add_read (master, kernel_read, NULL, sock);

#ifdef DEBUG
  rtmsg_debug (&buf.r.rtm);
#endif /* DEBUG */

  rtm = &buf.r.rtm;

  switch (rtm->rtm_type)
    {
    case RTM_ADD:
    case RTM_DELETE:
      rtm_read (rtm);
      break;
    case RTM_IFINFO:
      ifm_read (&buf.im.ifm);
      break;
    case RTM_NEWADDR:
    case RTM_DELADDR:
      ifam_read (&buf.ia.ifa);
      break;
#ifdef RTM_IFANNOUNCE
    case RTM_IFANNOUNCE:
      ifan_read (&buf.ian.ifan);
      break;
#endif /* RTM_IFANNOUNCE */
    default:
      break;
    }
  return 0;
}
/* Kernel routing table and interface updates via routing socket. */
static int
kernel_read (struct thread *thread)
{
  int sock;
  int nbytes;
  struct rt_msghdr *rtm;

  /*
   * This must be big enough for any message the kernel might send.
   * Rather than determining how many sockaddrs of what size might be
   * in each particular message, just use RTAX_MAX of sockaddr_storage
   * for each.  Note that the sockaddrs must be after each message
   * definition, or rather after whichever happens to be the largest,
   * since the buffer needs to be big enough for a message and the
   * sockaddrs together.
   */
  union 
  {
    /* Routing information. */
    struct 
    {
      struct rt_msghdr rtm;
      struct sockaddr_storage addr[RTAX_MAX];
    } r;

    /* Interface information. */
    struct
    {
      struct if_msghdr ifm;
      struct sockaddr_storage addr[RTAX_MAX];
    } im;

    /* Interface address information. */
    struct
    {
      struct ifa_msghdr ifa;
      struct sockaddr_storage addr[RTAX_MAX];
    } ia;

#ifdef RTM_IFANNOUNCE
    /* Interface arrival/departure */
    struct
    {
      struct if_announcemsghdr ifan;
      struct sockaddr_storage addr[RTAX_MAX];
    } ian;
#endif /* RTM_IFANNOUNCE */

  } buf;

  /* Fetch routing socket. */
  sock = THREAD_FD (thread);

  nbytes= read (sock, &buf, sizeof buf);

  if (nbytes <= 0)
    {
      if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
	zlog_warn ("routing socket error: %s", safe_strerror (errno));
      return 0;
    }

  thread_add_read (zebrad.master, kernel_read, NULL, sock);

  if (IS_ZEBRA_DEBUG_KERNEL)
    rtmsg_debug (&buf.r.rtm);

  rtm = &buf.r.rtm;

  /*
   * Ensure that we didn't drop any data, so that processing routines
   * can assume they have the whole message.
   */
  if (rtm->rtm_msglen != nbytes)
    {
      zlog_warn ("kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d\n",
		 rtm->rtm_msglen, nbytes, rtm->rtm_type);
      return -1;
    }

  switch (rtm->rtm_type)
    {
    case RTM_ADD:
    case RTM_DELETE:
    case RTM_CHANGE:
      rtm_read (rtm);
      break;
    case RTM_IFINFO:
      ifm_read (&buf.im.ifm);
      break;
    case RTM_NEWADDR:
    case RTM_DELADDR:
      ifam_read (&buf.ia.ifa);
      break;
#ifdef RTM_IFANNOUNCE
    case RTM_IFANNOUNCE:
      ifan_read (&buf.ian.ifan);
      break;
#endif /* RTM_IFANNOUNCE */
    default:
      if (IS_ZEBRA_DEBUG_KERNEL)
        zlog_debug("Unprocessed RTM_type: %d", rtm->rtm_type);
      break;
    }
  return 0;
}