From 718e3744195351130f4ce7dbe0613f4b3e23df93 Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 13 Dec 2002 20:15:29 +0000 Subject: Initial revision --- zebra/kernel_socket.c | 811 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 811 insertions(+) create mode 100644 zebra/kernel_socket.c (limited to 'zebra/kernel_socket.c') diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c new file mode 100644 index 00000000..a47f4f63 --- /dev/null +++ b/zebra/kernel_socket.c @@ -0,0 +1,811 @@ +/* Kernel communication using routing socket. + * Copyright (C) 1999 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "if.h" +#include "prefix.h" +#include "sockunion.h" +#include "connected.h" +#include "memory.h" +#include "ioctl.h" +#include "log.h" +#include "str.h" +#include "table.h" +#include "rib.h" + +#include "zebra/interface.h" +#include "zebra/zserv.h" +#include "zebra/debug.h" + +/* Socket length roundup function. */ +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +/* And this macro is wrapper for handling sa_len. */ +#ifdef HAVE_SA_LEN +#define WRAPUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len) +#else +#define WRAPUP(X) ROUNDUP(sizeof (struct sockaddr)) +#endif /* HAVE_SA_LEN */ + +/* Routing socket message types. */ +struct message rtm_type_str[] = +{ + {RTM_ADD, "RTM_ADD"}, + {RTM_DELETE, "RTM_DELETE"}, + {RTM_CHANGE, "RTM_CHANGE"}, + {RTM_GET, "RTM_GET"}, + {RTM_LOSING, "RTM_LOSING"}, + {RTM_REDIRECT, "RTM_REDIRECT"}, + {RTM_MISS, "RTM_MISS"}, + {RTM_LOCK, "RTM_LOCK"}, + {RTM_OLDADD, "RTM_OLDADD"}, + {RTM_OLDDEL, "RTM_OLDDEL"}, + {RTM_RESOLVE, "RTM_RESOLVE"}, + {RTM_NEWADDR, "RTM_NEWADDR"}, + {RTM_DELADDR, "RTM_DELADDR"}, + {RTM_IFINFO, "RTM_IFINFO"}, +#ifdef RTM_OIFINFO + {RTM_OIFINFO, "RTM_OIFINFO"}, +#endif /* RTM_OIFINFO */ +#ifdef RTM_NEWMADDR + {RTM_NEWMADDR, "RTM_NEWMADDR"}, +#endif /* RTM_NEWMADDR */ +#ifdef RTM_DELMADDR + {RTM_DELMADDR, "RTM_DELMADDR"}, +#endif /* RTM_DELMADDR */ +#ifdef RTM_IFANNOUNCE + {RTM_IFANNOUNCE, "RTM_IFANNOUNCE"}, +#endif /* RTM_IFANNOUNCE */ + {0, NULL} +}; + +struct message rtm_flag_str[] = +{ + {RTF_UP, "UP"}, + {RTF_GATEWAY, "GATEWAY"}, + {RTF_HOST, "HOST"}, + {RTF_REJECT, "REJECT"}, + {RTF_DYNAMIC, "DYNAMIC"}, + {RTF_MODIFIED, "MODIFIED"}, + {RTF_DONE, "DONE"}, +#ifdef RTF_MASK + {RTF_MASK, "MASK"}, +#endif /* RTF_MASK */ + {RTF_CLONING, "CLONING"}, + {RTF_XRESOLVE, "XRESOLVE"}, + {RTF_LLINFO, "LLINFO"}, + {RTF_STATIC, "STATIC"}, + {RTF_BLACKHOLE, "BLACKHOLE"}, + {RTF_PROTO1, "PROTO1"}, + {RTF_PROTO2, "PROTO2"}, +#ifdef RTF_PRCLONING + {RTF_PRCLONING, "PRCLONING"}, +#endif /* RTF_PRCLONING */ +#ifdef RTF_WASCLONED + {RTF_WASCLONED, "WASCLONED"}, +#endif /* RTF_WASCLONED */ +#ifdef RTF_PROTO3 + {RTF_PROTO3, "PROTO3"}, +#endif /* RTF_PROTO3 */ +#ifdef RTF_PINNED + {RTF_PINNED, "PINNED"}, +#endif /* RTF_PINNED */ +#ifdef RTF_LOCAL + {RTF_LOCAL, "LOCAL"}, +#endif /* RTF_LOCAL */ +#ifdef RTF_BROADCAST + {RTF_BROADCAST, "BROADCAST"}, +#endif /* RTF_BROADCAST */ +#ifdef RTF_MULTICAST + {RTF_MULTICAST, "MULTICAST"}, +#endif /* RTF_MULTICAST */ + {0, NULL} +}; + +/* Kernel routing update socket. */ +int routing_sock = -1; + +/* Yes I'm checking ugly routing socket behavior. */ +/* #define DEBUG */ + +/* Supported address family check. */ +static int +af_check (int family) +{ + if (family == AF_INET) + return 1; +#ifdef HAVE_IPV6 + if (family == AF_INET6) + return 1; +#endif /* HAVE_IPV6 */ + return 0; +} + +/* Dump routing table flag for debug purpose. */ +void +rtm_flag_dump (int flag) +{ + struct message *mes; + static char buf[BUFSIZ]; + + for (mes = rtm_flag_str; mes->key != 0; mes++) + { + if (mes->key & flag) + { + strlcat (buf, mes->str, BUFSIZ); + strlcat (buf, " ", BUFSIZ); + } + } + zlog_info ("Kernel: %s", buf); +} + +#ifdef RTM_IFANNOUNCE +/* Interface adding function */ +int +ifan_read (struct if_announcemsghdr *ifan) +{ + struct interface *ifp; + + ifp = if_lookup_by_index (ifan->ifan_index); + if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL) + { + /* Create Interface */ + ifp = if_get_by_name (ifan->ifan_name); + ifp->ifindex = ifan->ifan_index; + + if_add_update (ifp); + } + else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE) + { + if_delete_update (ifp); + if_delete (ifp); + } + + if_get_flags (ifp); + if_get_mtu (ifp); + if_get_metric (ifp); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d", ifp->name, ifp->ifindex); + + return 0; +} +#endif /* RTM_IFANNOUNCE */ + +/* Interface adding function called from interface_list. */ +int +ifm_read (struct if_msghdr *ifm) +{ + struct interface *ifp; + struct sockaddr_dl *sdl = NULL; + + sdl = (struct sockaddr_dl *)(ifm + 1); + + /* Use sdl index. */ + ifp = if_lookup_by_index (ifm->ifm_index); + + if (ifp == NULL) + { + /* Check interface's address.*/ + if (! (ifm->ifm_addrs & RTA_IFP)) + { + zlog_warn ("There must be RTA_IFP address for ifindex %d\n", + ifm->ifm_index); + return -1; + } + + ifp = if_create (); + + strncpy (ifp->name, sdl->sdl_data, sdl->sdl_nlen); + ifp->ifindex = ifm->ifm_index; + ifp->flags = ifm->ifm_flags; +#if defined(__bsdi__) + if_kvm_get_mtu (ifp); +#else + if_get_mtu (ifp); +#endif /* __bsdi__ */ + if_get_metric (ifp); + + /* Fetch hardware address. */ + if (sdl->sdl_family != AF_LINK) + { + zlog_warn ("sockaddr_dl->sdl_family is not AF_LINK"); + return -1; + } + memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); + + if_add_update (ifp); + } + else + { + /* There is a case of promisc, allmulti flag modification. */ + if (if_is_up (ifp)) + { + ifp->flags = ifm->ifm_flags; + if (! if_is_up (ifp)) + if_down (ifp); + } + else + { + ifp->flags = ifm->ifm_flags; + if (if_is_up (ifp)) + if_up (ifp); + } + } + +#ifdef HAVE_NET_RT_IFLIST + ifp->stats = ifm->ifm_data; +#endif /* HAVE_NET_RT_IFLIST */ + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_info ("interface %s index %d", ifp->name, ifp->ifindex); + + return 0; +} + +/* Address read from struct ifa_msghdr. */ +void +ifam_read_mesg (struct ifa_msghdr *ifm, + union sockunion *addr, + union sockunion *mask, + union sockunion *dest) +{ + caddr_t pnt, end; + + pnt = (caddr_t)(ifm + 1); + end = ((caddr_t)ifm) + ifm->ifam_msglen; + +#define IFAMADDRGET(X,R) \ + if (ifm->ifam_addrs & (R)) \ + { \ + int len = WRAPUP(pnt); \ + if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \ + memcpy ((caddr_t)(X), pnt, len); \ + pnt += len; \ + } +#define IFAMMASKGET(X,R) \ + if (ifm->ifam_addrs & (R)) \ + { \ + int len = WRAPUP(pnt); \ + if ((X) != NULL) \ + memcpy ((caddr_t)(X), pnt, len); \ + pnt += len; \ + } + + /* Be sure structure is cleared */ + memset (mask, 0, sizeof (union sockunion)); + memset (addr, 0, sizeof (union sockunion)); + memset (dest, 0, sizeof (union sockunion)); + + /* We fetch each socket variable into sockunion. */ + IFAMADDRGET (NULL, RTA_DST); + IFAMADDRGET (NULL, RTA_GATEWAY); + IFAMMASKGET (mask, RTA_NETMASK); + IFAMADDRGET (NULL, RTA_GENMASK); + IFAMADDRGET (NULL, RTA_IFP); + IFAMADDRGET (addr, RTA_IFA); + IFAMADDRGET (NULL, RTA_AUTHOR); + IFAMADDRGET (dest, RTA_BRD); + + /* Assert read up end point matches to end point */ + if (pnt != end) + zlog_warn ("ifam_read() does't read all socket data"); +} + +/* Interface's address information get. */ +int +ifam_read (struct ifa_msghdr *ifam) +{ + struct interface *ifp; + union sockunion addr, mask, gate; + + /* Check does this interface exist or not. */ + ifp = if_lookup_by_index (ifam->ifam_index); + if (ifp == NULL) + { + zlog_warn ("no interface for index %d", ifam->ifam_index); + return -1; + } + + /* Allocate and read address information. */ + ifam_read_mesg (ifam, &addr, &mask, &gate); + + /* Check interface flag for implicit up of the interface. */ + if_refresh (ifp); + + /* Add connected address. */ + switch (sockunion_family (&addr)) + { + case AF_INET: + if (ifam->ifam_type == RTM_NEWADDR) + connected_add_ipv4 (ifp, 0, &addr.sin.sin_addr, + ip_masklen (mask.sin.sin_addr), + &gate.sin.sin_addr, NULL); + else + connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr, + ip_masklen (mask.sin.sin_addr), + &gate.sin.sin_addr, NULL); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + /* Unset interface index from link-local address when IPv6 stack + is KAME. */ + if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr)) + SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0); + + if (ifam->ifam_type == RTM_NEWADDR) + connected_add_ipv6 (ifp, + &addr.sin6.sin6_addr, + ip6_masklen (mask.sin6.sin6_addr), + &gate.sin6.sin6_addr); + else + connected_delete_ipv6 (ifp, + &addr.sin6.sin6_addr, + ip6_masklen (mask.sin6.sin6_addr), + &gate.sin6.sin6_addr); + break; +#endif /* HAVE_IPV6 */ + default: + /* Unsupported family silently ignore... */ + break; + } + return 0; +} + +/* Interface function for reading kernel routing table information. */ +int +rtm_read_mesg (struct rt_msghdr *rtm, + union sockunion *dest, + union sockunion *mask, + union sockunion *gate) +{ + caddr_t pnt, end; + + /* Pnt points out socket data start point. */ + pnt = (caddr_t)(rtm + 1); + end = ((caddr_t)rtm) + rtm->rtm_msglen; + + /* rt_msghdr version check. */ + if (rtm->rtm_version != RTM_VERSION) + zlog (NULL, LOG_WARNING, + "Routing message version different %d should be %d." + "This may cause problem\n", rtm->rtm_version, RTM_VERSION); + +#define RTMADDRGET(X,R) \ + if (rtm->rtm_addrs & (R)) \ + { \ + int len = WRAPUP (pnt); \ + if (((X) != NULL) && af_check (((struct sockaddr *)pnt)->sa_family)) \ + memcpy ((caddr_t)(X), pnt, len); \ + pnt += len; \ + } +#define RTMMASKGET(X,R) \ + if (rtm->rtm_addrs & (R)) \ + { \ + int len = WRAPUP (pnt); \ + if ((X) != NULL) \ + memcpy ((caddr_t)(X), pnt, len); \ + pnt += len; \ + } + + /* Be sure structure is cleared */ + memset (dest, 0, sizeof (union sockunion)); + memset (gate, 0, sizeof (union sockunion)); + memset (mask, 0, sizeof (union sockunion)); + + /* We fetch each socket variable into sockunion. */ + RTMADDRGET (dest, RTA_DST); + RTMADDRGET (gate, RTA_GATEWAY); + RTMMASKGET (mask, RTA_NETMASK); + RTMADDRGET (NULL, RTA_GENMASK); + RTMADDRGET (NULL, RTA_IFP); + RTMADDRGET (NULL, RTA_IFA); + RTMADDRGET (NULL, RTA_AUTHOR); + RTMADDRGET (NULL, RTA_BRD); + + /* If there is netmask information set it's family same as + destination family*/ + if (rtm->rtm_addrs & RTA_NETMASK) + mask->sa.sa_family = dest->sa.sa_family; + + /* Assert read up to the end of pointer. */ + if (pnt != end) + zlog (NULL, LOG_WARNING, "rtm_read() does't read all socket data."); + + return rtm->rtm_flags; +} + +void +rtm_read (struct rt_msghdr *rtm) +{ + int flags; + u_char zebra_flags; + union sockunion dest, mask, gate; + + zebra_flags = 0; + + /* Discard self send message. */ + if (rtm->rtm_type != RTM_GET + && (rtm->rtm_pid == pid || rtm->rtm_pid == old_pid)) + return; + + /* Read destination and netmask and gateway from rtm message + structure. */ + flags = rtm_read_mesg (rtm, &dest, &mask, &gate); + +#ifdef RTF_CLONED /*bsdi, netbsd 1.6*/ + if (flags & RTF_CLONED) + return; +#endif +#ifdef RTF_WASCLONED /*freebsd*/ + if (flags & RTF_WASCLONED) + return; +#endif + + if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP)) + return; + + /* This is connected route. */ + if (! (flags & RTF_GATEWAY)) + return; + + if (flags & RTF_PROTO1) + SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE); + + /* This is persistent route. */ + if (flags & RTF_STATIC) + SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC); + + if (dest.sa.sa_family == AF_INET) + { + struct prefix_ipv4 p; + + p.family = AF_INET; + p.prefix = dest.sin.sin_addr; + if (flags & RTF_HOST) + p.prefixlen = IPV4_MAX_PREFIXLEN; + else + p.prefixlen = ip_masklen (mask.sin.sin_addr); + + if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD) + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, + &p, &gate.sin.sin_addr, 0, 0, 0, 0); + else + rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, + &p, &gate.sin.sin_addr, 0, 0); + } +#ifdef HAVE_IPV6 + if (dest.sa.sa_family == AF_INET6) + { + struct prefix_ipv6 p; + unsigned int ifindex = 0; + + p.family = AF_INET6; + p.prefix = dest.sin6.sin6_addr; + if (flags & RTF_HOST) + p.prefixlen = IPV6_MAX_PREFIXLEN; + else + p.prefixlen = ip6_masklen (mask.sin6.sin6_addr); + +#ifdef KAME + if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr)) + { + ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr); + SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0); + } +#endif /* KAME */ + + if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD) + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, + &p, &gate.sin6.sin6_addr, ifindex, 0); + else + rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, + &p, &gate.sin6.sin6_addr, ifindex, 0); + } +#endif /* HAVE_IPV6 */ +} + +/* Interface function for the kernel routing table updates. Support + for RTM_CHANGE will be needed. */ +int +rtm_write (int message, + union sockunion *dest, + union sockunion *mask, + union sockunion *gate, + unsigned int index, + int zebra_flags, + int metric) +{ + int ret; + caddr_t pnt; + struct interface *ifp; + struct sockaddr_in tmp_gate; +#ifdef HAVE_IPV6 + struct sockaddr_in6 tmp_gate6; +#endif /* HAVE_IPV6 */ + + /* Sequencial number of routing message. */ + static int msg_seq = 0; + + /* Struct of rt_msghdr and buffer for storing socket's data. */ + struct + { + struct rt_msghdr rtm; + char buf[512]; + } msg; + + memset (&tmp_gate, 0, sizeof (struct sockaddr_in)); + tmp_gate.sin_family = AF_INET; +#ifdef HAVE_SIN_LEN + tmp_gate.sin_len = sizeof (struct sockaddr_in); +#endif /* HAVE_SIN_LEN */ + +#ifdef HAVE_IPV6 + memset (&tmp_gate6, 0, sizeof (struct sockaddr_in6)); + tmp_gate6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + tmp_gate6.sin6_len = sizeof (struct sockaddr_in6); +#endif /* SIN6_LEN */ +#endif /* HAVE_IPV6 */ + + if (routing_sock < 0) + return ZEBRA_ERR_EPERM; + + /* Clear and set rt_msghdr values */ + memset (&msg, 0, sizeof (struct rt_msghdr)); + msg.rtm.rtm_version = RTM_VERSION; + msg.rtm.rtm_type = message; + msg.rtm.rtm_seq = msg_seq++; + msg.rtm.rtm_addrs = RTA_DST; + msg.rtm.rtm_addrs |= RTA_GATEWAY; + msg.rtm.rtm_flags = RTF_UP; + msg.rtm.rtm_index = index; + + if (metric != 0) + { + msg.rtm.rtm_rmx.rmx_hopcount = metric; + msg.rtm.rtm_inits |= RTV_HOPCOUNT; + } + + ifp = if_lookup_by_index (index); + + if (gate && message == RTM_ADD) + msg.rtm.rtm_flags |= RTF_GATEWAY; + + if (! gate && message == RTM_ADD && ifp && + (ifp->flags & IFF_POINTOPOINT) == 0) + msg.rtm.rtm_flags |= RTF_CLONING; + + /* If no protocol specific gateway is specified, use link + address for gateway. */ + if (! gate) + { + if (!ifp) + { + zlog_warn ("no gateway found for interface index %d", index); + return -1; + } + gate = (union sockunion *) & ifp->sdl; + } + + if (mask) + msg.rtm.rtm_addrs |= RTA_NETMASK; + else if (message == RTM_ADD) + msg.rtm.rtm_flags |= RTF_HOST; + + /* Tagging route with flags */ + msg.rtm.rtm_flags |= (RTF_PROTO1); + + /* Additional flags. */ + if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) + msg.rtm.rtm_flags |= RTF_BLACKHOLE; + +#ifdef HAVE_SIN_LEN +#define SOCKADDRSET(X,R) \ + if (msg.rtm.rtm_addrs & (R)) \ + { \ + int len = ROUNDUP ((X)->sa.sa_len); \ + memcpy (pnt, (caddr_t)(X), len); \ + pnt += len; \ + } +#else +#define SOCKADDRSET(X,R) \ + if (msg.rtm.rtm_addrs & (R)) \ + { \ + int len = ROUNDUP (sizeof((X)->sa)); \ + memcpy (pnt, (caddr_t)(X), len); \ + pnt += len; \ + } +#endif /* HAVE_SIN_LEN */ + + pnt = (caddr_t) msg.buf; + + /* Write each socket data into rtm message buffer */ + SOCKADDRSET (dest, RTA_DST); + SOCKADDRSET (gate, RTA_GATEWAY); + SOCKADDRSET (mask, RTA_NETMASK); + + msg.rtm.rtm_msglen = pnt - (caddr_t) &msg; + + ret = write (routing_sock, &msg, msg.rtm.rtm_msglen); + + if (ret != msg.rtm.rtm_msglen) + { + if (errno == EEXIST) + return ZEBRA_ERR_RTEXIST; + if (errno == ENETUNREACH) + return ZEBRA_ERR_RTUNREACH; + + zlog_warn ("write : %s (%d)", strerror (errno), errno); + return -1; + } + return 0; +} + + +#include "thread.h" +#include "zebra/zserv.h" + +extern struct thread_master *master; + +/* For debug purpose. */ +void +rtmsg_debug (struct rt_msghdr *rtm) +{ + char *type = "Unknown"; + struct message *mes; + + for (mes = rtm_type_str; mes->str; mes++) + if (mes->key == rtm->rtm_type) + { + type = mes->str; + break; + } + + zlog_info ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, type); + rtm_flag_dump (rtm->rtm_flags); + zlog_info ("Kernel: message seq %d", rtm->rtm_seq); + zlog_info ("Kernel: pid %d", rtm->rtm_pid); +} + +/* This is pretty gross, better suggestions welcome -- mhandler */ +#ifndef RTAX_MAX +#ifdef RTA_NUMBITS +#define RTAX_MAX RTA_NUMBITS +#else +#define RTAX_MAX 8 +#endif /* RTA_NUMBITS */ +#endif /* RTAX_MAX */ + +/* 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 && errno != EAGAIN) + 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; +} + +/* Make routing socket. */ +void +routing_socket () +{ + routing_sock = socket (AF_ROUTE, SOCK_RAW, 0); + + if (routing_sock < 0) + { + zlog_warn ("Can't init kernel routing socket"); + return; + } + + if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0) + zlog_warn ("Can't set O_NONBLOCK to routing socket"); + + /* kernel_read needs rewrite. */ + thread_add_read (master, kernel_read, NULL, routing_sock); +} + +/* Exported interface function. This function simply calls + routing_socket (). */ +void +kernel_init () +{ + routing_socket (); +} -- cgit v1.2.1