/* 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; }