Annotation of embedaddon/quagga/zebra/rt_netlink.c, revision 1.1

1.1     ! misho       1: /* Kernel routing table updates using netlink over GNU/Linux system.
        !             2:  * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
        !             3:  *
        !             4:  * This file is part of GNU Zebra.
        !             5:  *
        !             6:  * GNU Zebra is free software; you can redistribute it and/or modify it
        !             7:  * under the terms of the GNU General Public License as published by the
        !             8:  * Free Software Foundation; either version 2, or (at your option) any
        !             9:  * later version.
        !            10:  *
        !            11:  * GNU Zebra is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            14:  * General Public License for more details.
        !            15:  *
        !            16:  * You should have received a copy of the GNU General Public License
        !            17:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
        !            18:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
        !            19:  * 02111-1307, USA.  
        !            20:  */
        !            21: 
        !            22: #include <zebra.h>
        !            23: 
        !            24: /* Hack for GNU libc version 2. */
        !            25: #ifndef MSG_TRUNC
        !            26: #define MSG_TRUNC      0x20
        !            27: #endif /* MSG_TRUNC */
        !            28: 
        !            29: #include "linklist.h"
        !            30: #include "if.h"
        !            31: #include "log.h"
        !            32: #include "prefix.h"
        !            33: #include "connected.h"
        !            34: #include "table.h"
        !            35: #include "rib.h"
        !            36: #include "thread.h"
        !            37: #include "privs.h"
        !            38: 
        !            39: #include "zebra/zserv.h"
        !            40: #include "zebra/rt.h"
        !            41: #include "zebra/redistribute.h"
        !            42: #include "zebra/interface.h"
        !            43: #include "zebra/debug.h"
        !            44: 
        !            45: /* Socket interface to kernel */
        !            46: struct nlsock
        !            47: {
        !            48:   int sock;
        !            49:   int seq;
        !            50:   struct sockaddr_nl snl;
        !            51:   const char *name;
        !            52: } netlink      = { -1, 0, {0}, "netlink-listen"},     /* kernel messages */
        !            53:   netlink_cmd  = { -1, 0, {0}, "netlink-cmd"};        /* command channel */
        !            54: 
        !            55: static const struct message nlmsg_str[] = {
        !            56:   {RTM_NEWROUTE, "RTM_NEWROUTE"},
        !            57:   {RTM_DELROUTE, "RTM_DELROUTE"},
        !            58:   {RTM_GETROUTE, "RTM_GETROUTE"},
        !            59:   {RTM_NEWLINK,  "RTM_NEWLINK"},
        !            60:   {RTM_DELLINK,  "RTM_DELLINK"},
        !            61:   {RTM_GETLINK,  "RTM_GETLINK"},
        !            62:   {RTM_NEWADDR,  "RTM_NEWADDR"},
        !            63:   {RTM_DELADDR,  "RTM_DELADDR"},
        !            64:   {RTM_GETADDR,  "RTM_GETADDR"},
        !            65:   {0, NULL}
        !            66: };
        !            67: 
        !            68: static const char *nexthop_types_desc[] =
        !            69: {
        !            70:   "none",
        !            71:   "Directly connected",
        !            72:   "Interface route",
        !            73:   "IPv4 nexthop",
        !            74:   "IPv4 nexthop with ifindex",
        !            75:   "IPv4 nexthop with ifname",
        !            76:   "IPv6 nexthop",
        !            77:   "IPv6 nexthop with ifindex",
        !            78:   "IPv6 nexthop with ifname",
        !            79:   "Null0 nexthop",
        !            80: };
        !            81: 
        !            82: extern struct zebra_t zebrad;
        !            83: 
        !            84: extern struct zebra_privs_t zserv_privs;
        !            85: 
        !            86: extern u_int32_t nl_rcvbufsize;
        !            87: 
        !            88: /* Note: on netlink systems, there should be a 1-to-1 mapping between interface
        !            89:    names and ifindex values. */
        !            90: static void
        !            91: set_ifindex(struct interface *ifp, unsigned int ifi_index)
        !            92: {
        !            93:   struct interface *oifp;
        !            94: 
        !            95:   if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
        !            96:     {
        !            97:       if (ifi_index == IFINDEX_INTERNAL)
        !            98:         zlog_err("Netlink is setting interface %s ifindex to reserved "
        !            99:                 "internal value %u", ifp->name, ifi_index);
        !           100:       else
        !           101:         {
        !           102:          if (IS_ZEBRA_DEBUG_KERNEL)
        !           103:            zlog_debug("interface index %d was renamed from %s to %s",
        !           104:                       ifi_index, oifp->name, ifp->name);
        !           105:          if (if_is_up(oifp))
        !           106:            zlog_err("interface rename detected on up interface: index %d "
        !           107:                     "was renamed from %s to %s, results are uncertain!", 
        !           108:                     ifi_index, oifp->name, ifp->name);
        !           109:          if_delete_update(oifp);
        !           110:         }
        !           111:     }
        !           112:   ifp->ifindex = ifi_index;
        !           113: }
        !           114: 
        !           115: static int
        !           116: netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
        !           117: {
        !           118:   u_int32_t oldsize;
        !           119:   socklen_t newlen = sizeof(newsize);
        !           120:   socklen_t oldlen = sizeof(oldsize);
        !           121:   int ret;
        !           122: 
        !           123:   ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
        !           124:   if (ret < 0)
        !           125:     {
        !           126:       zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
        !           127:            safe_strerror (errno));
        !           128:       return -1;
        !           129:     }
        !           130: 
        !           131:   ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
        !           132:                   sizeof(nl_rcvbufsize));
        !           133:   if (ret < 0)
        !           134:     {
        !           135:       zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
        !           136:            safe_strerror (errno));
        !           137:       return -1;
        !           138:     }
        !           139: 
        !           140:   ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
        !           141:   if (ret < 0)
        !           142:     {
        !           143:       zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
        !           144:            safe_strerror (errno));
        !           145:       return -1;
        !           146:     }
        !           147: 
        !           148:   zlog (NULL, LOG_INFO,
        !           149:        "Setting netlink socket receive buffer size: %u -> %u",
        !           150:        oldsize, newsize);
        !           151:   return 0;
        !           152: }
        !           153: 
        !           154: /* Make socket for Linux netlink interface. */
        !           155: static int
        !           156: netlink_socket (struct nlsock *nl, unsigned long groups)
        !           157: {
        !           158:   int ret;
        !           159:   struct sockaddr_nl snl;
        !           160:   int sock;
        !           161:   int namelen;
        !           162:   int save_errno;
        !           163: 
        !           164:   sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        !           165:   if (sock < 0)
        !           166:     {
        !           167:       zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
        !           168:             safe_strerror (errno));
        !           169:       return -1;
        !           170:     }
        !           171: 
        !           172:   memset (&snl, 0, sizeof snl);
        !           173:   snl.nl_family = AF_NETLINK;
        !           174:   snl.nl_groups = groups;
        !           175: 
        !           176:   /* Bind the socket to the netlink structure for anything. */
        !           177:   if (zserv_privs.change (ZPRIVS_RAISE))
        !           178:     {
        !           179:       zlog (NULL, LOG_ERR, "Can't raise privileges");
        !           180:       return -1;
        !           181:     }
        !           182: 
        !           183:   ret = bind (sock, (struct sockaddr *) &snl, sizeof snl);
        !           184:   save_errno = errno;
        !           185:   if (zserv_privs.change (ZPRIVS_LOWER))
        !           186:     zlog (NULL, LOG_ERR, "Can't lower privileges");
        !           187: 
        !           188:   if (ret < 0)
        !           189:     {
        !           190:       zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s",
        !           191:             nl->name, snl.nl_groups, safe_strerror (save_errno));
        !           192:       close (sock);
        !           193:       return -1;
        !           194:     }
        !           195: 
        !           196:   /* multiple netlink sockets will have different nl_pid */
        !           197:   namelen = sizeof snl;
        !           198:   ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen);
        !           199:   if (ret < 0 || namelen != sizeof snl)
        !           200:     {
        !           201:       zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name,
        !           202:             safe_strerror (errno));
        !           203:       close (sock);
        !           204:       return -1;
        !           205:     }
        !           206: 
        !           207:   nl->snl = snl;
        !           208:   nl->sock = sock;
        !           209:   return ret;
        !           210: }
        !           211: 
        !           212: /* Get type specified information from netlink. */
        !           213: static int
        !           214: netlink_request (int family, int type, struct nlsock *nl)
        !           215: {
        !           216:   int ret;
        !           217:   struct sockaddr_nl snl;
        !           218:   int save_errno;
        !           219: 
        !           220:   struct
        !           221:   {
        !           222:     struct nlmsghdr nlh;
        !           223:     struct rtgenmsg g;
        !           224:   } req;
        !           225: 
        !           226: 
        !           227:   /* Check netlink socket. */
        !           228:   if (nl->sock < 0)
        !           229:     {
        !           230:       zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name);
        !           231:       return -1;
        !           232:     }
        !           233: 
        !           234:   memset (&snl, 0, sizeof snl);
        !           235:   snl.nl_family = AF_NETLINK;
        !           236: 
        !           237:   memset (&req, 0, sizeof req);
        !           238:   req.nlh.nlmsg_len = sizeof req;
        !           239:   req.nlh.nlmsg_type = type;
        !           240:   req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
        !           241:   req.nlh.nlmsg_pid = nl->snl.nl_pid;
        !           242:   req.nlh.nlmsg_seq = ++nl->seq;
        !           243:   req.g.rtgen_family = family;
        !           244: 
        !           245:   /* linux appears to check capabilities on every message 
        !           246:    * have to raise caps for every message sent
        !           247:    */
        !           248:   if (zserv_privs.change (ZPRIVS_RAISE))
        !           249:     {
        !           250:       zlog (NULL, LOG_ERR, "Can't raise privileges");
        !           251:       return -1;
        !           252:     }
        !           253: 
        !           254:   ret = sendto (nl->sock, (void *) &req, sizeof req, 0,
        !           255:                 (struct sockaddr *) &snl, sizeof snl);
        !           256:   save_errno = errno;
        !           257: 
        !           258:   if (zserv_privs.change (ZPRIVS_LOWER))
        !           259:     zlog (NULL, LOG_ERR, "Can't lower privileges");
        !           260: 
        !           261:   if (ret < 0)
        !           262:     {
        !           263:       zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name,
        !           264:             safe_strerror (save_errno));
        !           265:       return -1;
        !           266:     }
        !           267: 
        !           268:   return 0;
        !           269: }
        !           270: 
        !           271: /* Receive message from netlink interface and pass those information
        !           272:    to the given function. */
        !           273: static int
        !           274: netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
        !           275:                     struct nlsock *nl)
        !           276: {
        !           277:   int status;
        !           278:   int ret = 0;
        !           279:   int error;
        !           280: 
        !           281:   while (1)
        !           282:     {
        !           283:       char buf[4096];
        !           284:       struct iovec iov = { buf, sizeof buf };
        !           285:       struct sockaddr_nl snl;
        !           286:       struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
        !           287:       struct nlmsghdr *h;
        !           288: 
        !           289:       status = recvmsg (nl->sock, &msg, 0);
        !           290:       if (status < 0)
        !           291:         {
        !           292:           if (errno == EINTR)
        !           293:             continue;
        !           294:           if (errno == EWOULDBLOCK || errno == EAGAIN)
        !           295:             break;
        !           296:           zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
        !           297:                nl->name, safe_strerror(errno));
        !           298:           continue;
        !           299:         }
        !           300: 
        !           301:       if (status == 0)
        !           302:         {
        !           303:           zlog (NULL, LOG_ERR, "%s EOF", nl->name);
        !           304:           return -1;
        !           305:         }
        !           306: 
        !           307:       if (msg.msg_namelen != sizeof snl)
        !           308:         {
        !           309:           zlog (NULL, LOG_ERR, "%s sender address length error: length %d",
        !           310:                 nl->name, msg.msg_namelen);
        !           311:           return -1;
        !           312:         }
        !           313:       
        !           314:       for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
        !           315:            h = NLMSG_NEXT (h, status))
        !           316:         {
        !           317:           /* Finish of reading. */
        !           318:           if (h->nlmsg_type == NLMSG_DONE)
        !           319:             return ret;
        !           320: 
        !           321:           /* Error handling. */
        !           322:           if (h->nlmsg_type == NLMSG_ERROR)
        !           323:             {
        !           324:               struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
        !           325:              int errnum = err->error;
        !           326:              int msg_type = err->msg.nlmsg_type;
        !           327: 
        !           328:               /* If the error field is zero, then this is an ACK */
        !           329:               if (err->error == 0)
        !           330:                 {
        !           331:                   if (IS_ZEBRA_DEBUG_KERNEL)
        !           332:                     {
        !           333:                       zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u",
        !           334:                                  __FUNCTION__, nl->name,
        !           335:                                  lookup (nlmsg_str, err->msg.nlmsg_type),
        !           336:                                  err->msg.nlmsg_type, err->msg.nlmsg_seq,
        !           337:                                  err->msg.nlmsg_pid);
        !           338:                     }
        !           339: 
        !           340:                   /* return if not a multipart message, otherwise continue */
        !           341:                   if (!(h->nlmsg_flags & NLM_F_MULTI))
        !           342:                     {
        !           343:                       return 0;
        !           344:                     }
        !           345:                   continue;
        !           346:                 }
        !           347: 
        !           348:               if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
        !           349:                 {
        !           350:                   zlog (NULL, LOG_ERR, "%s error: message truncated",
        !           351:                         nl->name);
        !           352:                   return -1;
        !           353:                 }
        !           354: 
        !           355:               /* Deal with errors that occur because of races in link handling */
        !           356:              if (nl == &netlink_cmd
        !           357:                  && ((msg_type == RTM_DELROUTE &&
        !           358:                       (-errnum == ENODEV || -errnum == ESRCH))
        !           359:                      || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
        !           360:                {
        !           361:                  if (IS_ZEBRA_DEBUG_KERNEL)
        !           362:                    zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
        !           363:                                nl->name, safe_strerror (-errnum),
        !           364:                                lookup (nlmsg_str, msg_type),
        !           365:                                msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
        !           366:                  return 0;
        !           367:                }
        !           368: 
        !           369:              zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
        !           370:                        nl->name, safe_strerror (-errnum),
        !           371:                        lookup (nlmsg_str, msg_type),
        !           372:                        msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
        !           373:               return -1;
        !           374:             }
        !           375: 
        !           376:           /* OK we got netlink message. */
        !           377:           if (IS_ZEBRA_DEBUG_KERNEL)
        !           378:             zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u",
        !           379:                        nl->name,
        !           380:                        lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type,
        !           381:                        h->nlmsg_seq, h->nlmsg_pid);
        !           382: 
        !           383:           /* skip unsolicited messages originating from command socket */
        !           384:           if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid)
        !           385:             {
        !           386:               if (IS_ZEBRA_DEBUG_KERNEL)
        !           387:                 zlog_debug ("netlink_parse_info: %s packet comes from %s",
        !           388:                             netlink_cmd.name, nl->name);
        !           389:               continue;
        !           390:             }
        !           391: 
        !           392:           error = (*filter) (&snl, h);
        !           393:           if (error < 0)
        !           394:             {
        !           395:               zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
        !           396:               ret = error;
        !           397:             }
        !           398:         }
        !           399: 
        !           400:       /* After error care. */
        !           401:       if (msg.msg_flags & MSG_TRUNC)
        !           402:         {
        !           403:           zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name);
        !           404:           continue;
        !           405:         }
        !           406:       if (status)
        !           407:         {
        !           408:           zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name,
        !           409:                 status);
        !           410:           return -1;
        !           411:         }
        !           412:     }
        !           413:   return ret;
        !           414: }
        !           415: 
        !           416: /* Utility function for parse rtattr. */
        !           417: static void
        !           418: netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta,
        !           419:                       int len)
        !           420: {
        !           421:   while (RTA_OK (rta, len))
        !           422:     {
        !           423:       if (rta->rta_type <= max)
        !           424:         tb[rta->rta_type] = rta;
        !           425:       rta = RTA_NEXT (rta, len);
        !           426:     }
        !           427: }
        !           428: 
        !           429: /* Called from interface_lookup_netlink().  This function is only used
        !           430:    during bootstrap. */
        !           431: static int
        !           432: netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
        !           433: {
        !           434:   int len;
        !           435:   struct ifinfomsg *ifi;
        !           436:   struct rtattr *tb[IFLA_MAX + 1];
        !           437:   struct interface *ifp;
        !           438:   char *name;
        !           439:   int i;
        !           440: 
        !           441:   ifi = NLMSG_DATA (h);
        !           442: 
        !           443:   if (h->nlmsg_type != RTM_NEWLINK)
        !           444:     return 0;
        !           445: 
        !           446:   len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
        !           447:   if (len < 0)
        !           448:     return -1;
        !           449: 
        !           450:   /* Looking up interface name. */
        !           451:   memset (tb, 0, sizeof tb);
        !           452:   netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
        !           453:   
        !           454: #ifdef IFLA_WIRELESS
        !           455:   /* check for wireless messages to ignore */
        !           456:   if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
        !           457:     {
        !           458:       if (IS_ZEBRA_DEBUG_KERNEL)
        !           459:         zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
        !           460:       return 0;
        !           461:     }
        !           462: #endif /* IFLA_WIRELESS */
        !           463: 
        !           464:   if (tb[IFLA_IFNAME] == NULL)
        !           465:     return -1;
        !           466:   name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
        !           467: 
        !           468:   /* Add interface. */
        !           469:   ifp = if_get_by_name (name);
        !           470:   set_ifindex(ifp, ifi->ifi_index);
        !           471:   ifp->flags = ifi->ifi_flags & 0x0000fffff;
        !           472:   ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
        !           473:   ifp->metric = 1;
        !           474: 
        !           475:   /* Hardware type and address. */
        !           476:   ifp->hw_type = ifi->ifi_type;
        !           477: 
        !           478:   if (tb[IFLA_ADDRESS])
        !           479:     {
        !           480:       int hw_addr_len;
        !           481: 
        !           482:       hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
        !           483: 
        !           484:       if (hw_addr_len > INTERFACE_HWADDR_MAX)
        !           485:         zlog_warn ("Hardware address is too large: %d", hw_addr_len);
        !           486:       else
        !           487:         {
        !           488:           ifp->hw_addr_len = hw_addr_len;
        !           489:           memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
        !           490: 
        !           491:           for (i = 0; i < hw_addr_len; i++)
        !           492:             if (ifp->hw_addr[i] != 0)
        !           493:               break;
        !           494: 
        !           495:           if (i == hw_addr_len)
        !           496:             ifp->hw_addr_len = 0;
        !           497:           else
        !           498:             ifp->hw_addr_len = hw_addr_len;
        !           499:         }
        !           500:     }
        !           501: 
        !           502:   if_add_update (ifp);
        !           503: 
        !           504:   return 0;
        !           505: }
        !           506: 
        !           507: /* Lookup interface IPv4/IPv6 address. */
        !           508: static int
        !           509: netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
        !           510: {
        !           511:   int len;
        !           512:   struct ifaddrmsg *ifa;
        !           513:   struct rtattr *tb[IFA_MAX + 1];
        !           514:   struct interface *ifp;
        !           515:   void *addr;
        !           516:   void *broad;
        !           517:   u_char flags = 0;
        !           518:   char *label = NULL;
        !           519: 
        !           520:   ifa = NLMSG_DATA (h);
        !           521: 
        !           522:   if (ifa->ifa_family != AF_INET
        !           523: #ifdef HAVE_IPV6
        !           524:       && ifa->ifa_family != AF_INET6
        !           525: #endif /* HAVE_IPV6 */
        !           526:     )
        !           527:     return 0;
        !           528: 
        !           529:   if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
        !           530:     return 0;
        !           531: 
        !           532:   len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg));
        !           533:   if (len < 0)
        !           534:     return -1;
        !           535: 
        !           536:   memset (tb, 0, sizeof tb);
        !           537:   netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
        !           538: 
        !           539:   ifp = if_lookup_by_index (ifa->ifa_index);
        !           540:   if (ifp == NULL)
        !           541:     {
        !           542:       zlog_err ("netlink_interface_addr can't find interface by index %d",
        !           543:                 ifa->ifa_index);
        !           544:       return -1;
        !           545:     }
        !           546: 
        !           547:   if (IS_ZEBRA_DEBUG_KERNEL)    /* remove this line to see initial ifcfg */
        !           548:     {
        !           549:       char buf[BUFSIZ];
        !           550:       zlog_debug ("netlink_interface_addr %s %s:",
        !           551:                  lookup (nlmsg_str, h->nlmsg_type), ifp->name);
        !           552:       if (tb[IFA_LOCAL])
        !           553:         zlog_debug ("  IFA_LOCAL     %s/%d",
        !           554:                    inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
        !           555:                               buf, BUFSIZ), ifa->ifa_prefixlen);
        !           556:       if (tb[IFA_ADDRESS])
        !           557:         zlog_debug ("  IFA_ADDRESS   %s/%d",
        !           558:                    inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]),
        !           559:                                buf, BUFSIZ), ifa->ifa_prefixlen);
        !           560:       if (tb[IFA_BROADCAST])
        !           561:         zlog_debug ("  IFA_BROADCAST %s/%d",
        !           562:                    inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]),
        !           563:                               buf, BUFSIZ), ifa->ifa_prefixlen);
        !           564:       if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
        !           565:         zlog_debug ("  IFA_LABEL     %s", (char *)RTA_DATA (tb[IFA_LABEL]));
        !           566:       
        !           567:       if (tb[IFA_CACHEINFO])
        !           568:         {
        !           569:           struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]);
        !           570:           zlog_debug ("  IFA_CACHEINFO pref %d, valid %d",
        !           571:                       ci->ifa_prefered, ci->ifa_valid);
        !           572:         }
        !           573:     }
        !           574:   
        !           575:   /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
        !           576:   if (tb[IFA_LOCAL] == NULL)
        !           577:     tb[IFA_LOCAL] = tb[IFA_ADDRESS];
        !           578:   if (tb[IFA_ADDRESS] == NULL)
        !           579:     tb[IFA_ADDRESS] = tb[IFA_LOCAL];
        !           580:   
        !           581:   /* local interface address */
        !           582:   addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
        !           583: 
        !           584:   /* is there a peer address? */
        !           585:   if (tb[IFA_ADDRESS] &&
        !           586:       memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS])))
        !           587:     {
        !           588:       broad = RTA_DATA(tb[IFA_ADDRESS]);
        !           589:       SET_FLAG (flags, ZEBRA_IFA_PEER);
        !           590:     }
        !           591:   else
        !           592:     /* seeking a broadcast address */
        !           593:     broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL);
        !           594: 
        !           595:   /* addr is primary key, SOL if we don't have one */
        !           596:   if (addr == NULL)
        !           597:     {
        !           598:       zlog_debug ("%s: NULL address", __func__);
        !           599:       return -1;
        !           600:     }
        !           601: 
        !           602:   /* Flags. */
        !           603:   if (ifa->ifa_flags & IFA_F_SECONDARY)
        !           604:     SET_FLAG (flags, ZEBRA_IFA_SECONDARY);
        !           605: 
        !           606:   /* Label */
        !           607:   if (tb[IFA_LABEL])
        !           608:     label = (char *) RTA_DATA (tb[IFA_LABEL]);
        !           609: 
        !           610:   if (ifp && label && strcmp (ifp->name, label) == 0)
        !           611:     label = NULL;
        !           612: 
        !           613:   /* Register interface address to the interface. */
        !           614:   if (ifa->ifa_family == AF_INET)
        !           615:     {
        !           616:       if (h->nlmsg_type == RTM_NEWADDR)
        !           617:         connected_add_ipv4 (ifp, flags,
        !           618:                             (struct in_addr *) addr, ifa->ifa_prefixlen,
        !           619:                             (struct in_addr *) broad, label);
        !           620:       else
        !           621:         connected_delete_ipv4 (ifp, flags,
        !           622:                                (struct in_addr *) addr, ifa->ifa_prefixlen,
        !           623:                                (struct in_addr *) broad);
        !           624:     }
        !           625: #ifdef HAVE_IPV6
        !           626:   if (ifa->ifa_family == AF_INET6)
        !           627:     {
        !           628:       if (h->nlmsg_type == RTM_NEWADDR)
        !           629:         connected_add_ipv6 (ifp, flags,
        !           630:                             (struct in6_addr *) addr, ifa->ifa_prefixlen,
        !           631:                             (struct in6_addr *) broad, label);
        !           632:       else
        !           633:         connected_delete_ipv6 (ifp,
        !           634:                                (struct in6_addr *) addr, ifa->ifa_prefixlen,
        !           635:                                (struct in6_addr *) broad);
        !           636:     }
        !           637: #endif /* HAVE_IPV6 */
        !           638: 
        !           639:   return 0;
        !           640: }
        !           641: 
        !           642: /* Looking up routing table by netlink interface. */
        !           643: static int
        !           644: netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
        !           645: {
        !           646:   int len;
        !           647:   struct rtmsg *rtm;
        !           648:   struct rtattr *tb[RTA_MAX + 1];
        !           649:   u_char flags = 0;
        !           650: 
        !           651:   char anyaddr[16] = { 0 };
        !           652: 
        !           653:   int index;
        !           654:   int table;
        !           655:   int metric;
        !           656: 
        !           657:   void *dest;
        !           658:   void *gate;
        !           659:   void *src;
        !           660: 
        !           661:   rtm = NLMSG_DATA (h);
        !           662: 
        !           663:   if (h->nlmsg_type != RTM_NEWROUTE)
        !           664:     return 0;
        !           665:   if (rtm->rtm_type != RTN_UNICAST)
        !           666:     return 0;
        !           667: 
        !           668:   table = rtm->rtm_table;
        !           669: #if 0                           /* we weed them out later in rib_weed_tables () */
        !           670:   if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
        !           671:     return 0;
        !           672: #endif
        !           673: 
        !           674:   len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
        !           675:   if (len < 0)
        !           676:     return -1;
        !           677: 
        !           678:   memset (tb, 0, sizeof tb);
        !           679:   netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
        !           680: 
        !           681:   if (rtm->rtm_flags & RTM_F_CLONED)
        !           682:     return 0;
        !           683:   if (rtm->rtm_protocol == RTPROT_REDIRECT)
        !           684:     return 0;
        !           685:   if (rtm->rtm_protocol == RTPROT_KERNEL)
        !           686:     return 0;
        !           687: 
        !           688:   if (rtm->rtm_src_len != 0)
        !           689:     return 0;
        !           690: 
        !           691:   /* Route which inserted by Zebra. */
        !           692:   if (rtm->rtm_protocol == RTPROT_ZEBRA)
        !           693:     flags |= ZEBRA_FLAG_SELFROUTE;
        !           694: 
        !           695:   index = 0;
        !           696:   metric = 0;
        !           697:   dest = NULL;
        !           698:   gate = NULL;
        !           699:   src = NULL;
        !           700: 
        !           701:   if (tb[RTA_OIF])
        !           702:     index = *(int *) RTA_DATA (tb[RTA_OIF]);
        !           703: 
        !           704:   if (tb[RTA_DST])
        !           705:     dest = RTA_DATA (tb[RTA_DST]);
        !           706:   else
        !           707:     dest = anyaddr;
        !           708: 
        !           709:   if (tb[RTA_PREFSRC])
        !           710:     src = RTA_DATA (tb[RTA_PREFSRC]);
        !           711: 
        !           712:   /* Multipath treatment is needed. */
        !           713:   if (tb[RTA_GATEWAY])
        !           714:     gate = RTA_DATA (tb[RTA_GATEWAY]);
        !           715: 
        !           716:   if (tb[RTA_PRIORITY])
        !           717:     metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
        !           718: 
        !           719:   if (rtm->rtm_family == AF_INET)
        !           720:     {
        !           721:       struct prefix_ipv4 p;
        !           722:       p.family = AF_INET;
        !           723:       memcpy (&p.prefix, dest, 4);
        !           724:       p.prefixlen = rtm->rtm_dst_len;
        !           725: 
        !           726:       rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
        !           727:     }
        !           728: #ifdef HAVE_IPV6
        !           729:   if (rtm->rtm_family == AF_INET6)
        !           730:     {
        !           731:       struct prefix_ipv6 p;
        !           732:       p.family = AF_INET6;
        !           733:       memcpy (&p.prefix, dest, 16);
        !           734:       p.prefixlen = rtm->rtm_dst_len;
        !           735: 
        !           736:       rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table,
        !           737:                    metric, 0);
        !           738:     }
        !           739: #endif /* HAVE_IPV6 */
        !           740: 
        !           741:   return 0;
        !           742: }
        !           743: 
        !           744: static const struct message rtproto_str[] = {
        !           745:   {RTPROT_REDIRECT, "redirect"},
        !           746:   {RTPROT_KERNEL,   "kernel"},
        !           747:   {RTPROT_BOOT,     "boot"},
        !           748:   {RTPROT_STATIC,   "static"},
        !           749:   {RTPROT_GATED,    "GateD"},
        !           750:   {RTPROT_RA,       "router advertisement"},
        !           751:   {RTPROT_MRT,      "MRT"},
        !           752:   {RTPROT_ZEBRA,    "Zebra"},
        !           753: #ifdef RTPROT_BIRD
        !           754:   {RTPROT_BIRD,     "BIRD"},
        !           755: #endif /* RTPROT_BIRD */
        !           756:   {0,               NULL}
        !           757: };
        !           758: 
        !           759: /* Routing information change from the kernel. */
        !           760: static int
        !           761: netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
        !           762: {
        !           763:   int len;
        !           764:   struct rtmsg *rtm;
        !           765:   struct rtattr *tb[RTA_MAX + 1];
        !           766: 
        !           767:   char anyaddr[16] = { 0 };
        !           768: 
        !           769:   int index;
        !           770:   int table;
        !           771:   int metric;
        !           772: 
        !           773:   void *dest;
        !           774:   void *gate;
        !           775:   void *src;
        !           776: 
        !           777:   rtm = NLMSG_DATA (h);
        !           778: 
        !           779:   if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
        !           780:     {
        !           781:       /* If this is not route add/delete message print warning. */
        !           782:       zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
        !           783:       return 0;
        !           784:     }
        !           785: 
        !           786:   /* Connected route. */
        !           787:   if (IS_ZEBRA_DEBUG_KERNEL)
        !           788:     zlog_debug ("%s %s %s proto %s",
        !           789:                h->nlmsg_type ==
        !           790:                RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
        !           791:                rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
        !           792:                rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
        !           793:                lookup (rtproto_str, rtm->rtm_protocol));
        !           794: 
        !           795:   if (rtm->rtm_type != RTN_UNICAST)
        !           796:     {
        !           797:       return 0;
        !           798:     }
        !           799: 
        !           800:   table = rtm->rtm_table;
        !           801:   if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default)
        !           802:     {
        !           803:       return 0;
        !           804:     }
        !           805: 
        !           806:   len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
        !           807:   if (len < 0)
        !           808:     return -1;
        !           809: 
        !           810:   memset (tb, 0, sizeof tb);
        !           811:   netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
        !           812: 
        !           813:   if (rtm->rtm_flags & RTM_F_CLONED)
        !           814:     return 0;
        !           815:   if (rtm->rtm_protocol == RTPROT_REDIRECT)
        !           816:     return 0;
        !           817:   if (rtm->rtm_protocol == RTPROT_KERNEL)
        !           818:     return 0;
        !           819: 
        !           820:   if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
        !           821:     return 0;
        !           822: 
        !           823:   if (rtm->rtm_src_len != 0)
        !           824:     {
        !           825:       zlog_warn ("netlink_route_change(): no src len");
        !           826:       return 0;
        !           827:     }
        !           828: 
        !           829:   index = 0;
        !           830:   metric = 0;
        !           831:   dest = NULL;
        !           832:   gate = NULL;
        !           833:   src = NULL;
        !           834: 
        !           835:   if (tb[RTA_OIF])
        !           836:     index = *(int *) RTA_DATA (tb[RTA_OIF]);
        !           837: 
        !           838:   if (tb[RTA_DST])
        !           839:     dest = RTA_DATA (tb[RTA_DST]);
        !           840:   else
        !           841:     dest = anyaddr;
        !           842: 
        !           843:   if (tb[RTA_GATEWAY])
        !           844:     gate = RTA_DATA (tb[RTA_GATEWAY]);
        !           845: 
        !           846:   if (tb[RTA_PREFSRC])
        !           847:     src = RTA_DATA (tb[RTA_PREFSRC]);
        !           848: 
        !           849:   if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
        !           850:     metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
        !           851: 
        !           852:   if (rtm->rtm_family == AF_INET)
        !           853:     {
        !           854:       struct prefix_ipv4 p;
        !           855:       p.family = AF_INET;
        !           856:       memcpy (&p.prefix, dest, 4);
        !           857:       p.prefixlen = rtm->rtm_dst_len;
        !           858: 
        !           859:       if (IS_ZEBRA_DEBUG_KERNEL)
        !           860:         {
        !           861:           if (h->nlmsg_type == RTM_NEWROUTE)
        !           862:             zlog_debug ("RTM_NEWROUTE %s/%d",
        !           863:                        inet_ntoa (p.prefix), p.prefixlen);
        !           864:           else
        !           865:             zlog_debug ("RTM_DELROUTE %s/%d",
        !           866:                        inet_ntoa (p.prefix), p.prefixlen);
        !           867:         }
        !           868: 
        !           869:       if (h->nlmsg_type == RTM_NEWROUTE)
        !           870:         rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 0);
        !           871:       else
        !           872:         rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
        !           873:     }
        !           874: 
        !           875: #ifdef HAVE_IPV6
        !           876:   if (rtm->rtm_family == AF_INET6)
        !           877:     {
        !           878:       struct prefix_ipv6 p;
        !           879:       char buf[BUFSIZ];
        !           880: 
        !           881:       p.family = AF_INET6;
        !           882:       memcpy (&p.prefix, dest, 16);
        !           883:       p.prefixlen = rtm->rtm_dst_len;
        !           884: 
        !           885:       if (IS_ZEBRA_DEBUG_KERNEL)
        !           886:         {
        !           887:           if (h->nlmsg_type == RTM_NEWROUTE)
        !           888:             zlog_debug ("RTM_NEWROUTE %s/%d",
        !           889:                        inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
        !           890:                        p.prefixlen);
        !           891:           else
        !           892:             zlog_debug ("RTM_DELROUTE %s/%d",
        !           893:                        inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ),
        !           894:                        p.prefixlen);
        !           895:         }
        !           896: 
        !           897:       if (h->nlmsg_type == RTM_NEWROUTE)
        !           898:         rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0);
        !           899:       else
        !           900:         rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
        !           901:     }
        !           902: #endif /* HAVE_IPV6 */
        !           903: 
        !           904:   return 0;
        !           905: }
        !           906: 
        !           907: static int
        !           908: netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
        !           909: {
        !           910:   int len;
        !           911:   struct ifinfomsg *ifi;
        !           912:   struct rtattr *tb[IFLA_MAX + 1];
        !           913:   struct interface *ifp;
        !           914:   char *name;
        !           915: 
        !           916:   ifi = NLMSG_DATA (h);
        !           917: 
        !           918:   if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
        !           919:     {
        !           920:       /* If this is not link add/delete message so print warning. */
        !           921:       zlog_warn ("netlink_link_change: wrong kernel message %d\n",
        !           922:                  h->nlmsg_type);
        !           923:       return 0;
        !           924:     }
        !           925: 
        !           926:   len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg));
        !           927:   if (len < 0)
        !           928:     return -1;
        !           929: 
        !           930:   /* Looking up interface name. */
        !           931:   memset (tb, 0, sizeof tb);
        !           932:   netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len);
        !           933: 
        !           934: #ifdef IFLA_WIRELESS
        !           935:   /* check for wireless messages to ignore */
        !           936:   if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
        !           937:     {
        !           938:       if (IS_ZEBRA_DEBUG_KERNEL)
        !           939:         zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
        !           940:       return 0;
        !           941:     }
        !           942: #endif /* IFLA_WIRELESS */
        !           943:   
        !           944:   if (tb[IFLA_IFNAME] == NULL)
        !           945:     return -1;
        !           946:   name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
        !           947: 
        !           948:   /* Add interface. */
        !           949:   if (h->nlmsg_type == RTM_NEWLINK)
        !           950:     {
        !           951:       ifp = if_lookup_by_name (name);
        !           952: 
        !           953:       if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
        !           954:         {
        !           955:           if (ifp == NULL)
        !           956:             ifp = if_get_by_name (name);
        !           957: 
        !           958:           set_ifindex(ifp, ifi->ifi_index);
        !           959:           ifp->flags = ifi->ifi_flags & 0x0000fffff;
        !           960:           ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
        !           961:           ifp->metric = 1;
        !           962: 
        !           963:           /* If new link is added. */
        !           964:           if_add_update (ifp);
        !           965:         }
        !           966:       else
        !           967:         {
        !           968:           /* Interface status change. */
        !           969:           set_ifindex(ifp, ifi->ifi_index);
        !           970:           ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
        !           971:           ifp->metric = 1;
        !           972: 
        !           973:           if (if_is_operative (ifp))
        !           974:             {
        !           975:               ifp->flags = ifi->ifi_flags & 0x0000fffff;
        !           976:               if (!if_is_operative (ifp))
        !           977:                 if_down (ifp);
        !           978:              else
        !           979:                /* Must notify client daemons of new interface status. */
        !           980:                zebra_interface_up_update (ifp);
        !           981:             }
        !           982:           else
        !           983:             {
        !           984:               ifp->flags = ifi->ifi_flags & 0x0000fffff;
        !           985:               if (if_is_operative (ifp))
        !           986:                 if_up (ifp);
        !           987:             }
        !           988:         }
        !           989:     }
        !           990:   else
        !           991:     {
        !           992:       /* RTM_DELLINK. */
        !           993:       ifp = if_lookup_by_name (name);
        !           994: 
        !           995:       if (ifp == NULL)
        !           996:         {
        !           997:           zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
        !           998:                 name);
        !           999:           return 0;
        !          1000:         }
        !          1001: 
        !          1002:       if_delete_update (ifp);
        !          1003:     }
        !          1004: 
        !          1005:   return 0;
        !          1006: }
        !          1007: 
        !          1008: static int
        !          1009: netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
        !          1010: {
        !          1011:   /* JF: Ignore messages that aren't from the kernel */
        !          1012:   if ( snl->nl_pid != 0 )
        !          1013:     {
        !          1014:       zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid );
        !          1015:       return 0;
        !          1016:     }
        !          1017: 
        !          1018:   switch (h->nlmsg_type)
        !          1019:     {
        !          1020:     case RTM_NEWROUTE:
        !          1021:       return netlink_route_change (snl, h);
        !          1022:       break;
        !          1023:     case RTM_DELROUTE:
        !          1024:       return netlink_route_change (snl, h);
        !          1025:       break;
        !          1026:     case RTM_NEWLINK:
        !          1027:       return netlink_link_change (snl, h);
        !          1028:       break;
        !          1029:     case RTM_DELLINK:
        !          1030:       return netlink_link_change (snl, h);
        !          1031:       break;
        !          1032:     case RTM_NEWADDR:
        !          1033:       return netlink_interface_addr (snl, h);
        !          1034:       break;
        !          1035:     case RTM_DELADDR:
        !          1036:       return netlink_interface_addr (snl, h);
        !          1037:       break;
        !          1038:     default:
        !          1039:       zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
        !          1040:       break;
        !          1041:     }
        !          1042:   return 0;
        !          1043: }
        !          1044: 
        !          1045: /* Interface lookup by netlink socket. */
        !          1046: int
        !          1047: interface_lookup_netlink (void)
        !          1048: {
        !          1049:   int ret;
        !          1050: 
        !          1051:   /* Get interface information. */
        !          1052:   ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
        !          1053:   if (ret < 0)
        !          1054:     return ret;
        !          1055:   ret = netlink_parse_info (netlink_interface, &netlink_cmd);
        !          1056:   if (ret < 0)
        !          1057:     return ret;
        !          1058: 
        !          1059:   /* Get IPv4 address of the interfaces. */
        !          1060:   ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
        !          1061:   if (ret < 0)
        !          1062:     return ret;
        !          1063:   ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
        !          1064:   if (ret < 0)
        !          1065:     return ret;
        !          1066: 
        !          1067: #ifdef HAVE_IPV6
        !          1068:   /* Get IPv6 address of the interfaces. */
        !          1069:   ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
        !          1070:   if (ret < 0)
        !          1071:     return ret;
        !          1072:   ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
        !          1073:   if (ret < 0)
        !          1074:     return ret;
        !          1075: #endif /* HAVE_IPV6 */
        !          1076: 
        !          1077:   return 0;
        !          1078: }
        !          1079: 
        !          1080: /* Routing table read function using netlink interface.  Only called
        !          1081:    bootstrap time. */
        !          1082: int
        !          1083: netlink_route_read (void)
        !          1084: {
        !          1085:   int ret;
        !          1086: 
        !          1087:   /* Get IPv4 routing table. */
        !          1088:   ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
        !          1089:   if (ret < 0)
        !          1090:     return ret;
        !          1091:   ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
        !          1092:   if (ret < 0)
        !          1093:     return ret;
        !          1094: 
        !          1095: #ifdef HAVE_IPV6
        !          1096:   /* Get IPv6 routing table. */
        !          1097:   ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
        !          1098:   if (ret < 0)
        !          1099:     return ret;
        !          1100:   ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
        !          1101:   if (ret < 0)
        !          1102:     return ret;
        !          1103: #endif /* HAVE_IPV6 */
        !          1104: 
        !          1105:   return 0;
        !          1106: }
        !          1107: 
        !          1108: /* Utility function  comes from iproute2. 
        !          1109:    Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
        !          1110: static int
        !          1111: addattr_l (struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
        !          1112: {
        !          1113:   int len;
        !          1114:   struct rtattr *rta;
        !          1115: 
        !          1116:   len = RTA_LENGTH (alen);
        !          1117: 
        !          1118:   if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
        !          1119:     return -1;
        !          1120: 
        !          1121:   rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
        !          1122:   rta->rta_type = type;
        !          1123:   rta->rta_len = len;
        !          1124:   memcpy (RTA_DATA (rta), data, alen);
        !          1125:   n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
        !          1126: 
        !          1127:   return 0;
        !          1128: }
        !          1129: 
        !          1130: static int
        !          1131: rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen)
        !          1132: {
        !          1133:   int len;
        !          1134:   struct rtattr *subrta;
        !          1135: 
        !          1136:   len = RTA_LENGTH (alen);
        !          1137: 
        !          1138:   if (RTA_ALIGN (rta->rta_len) + len > maxlen)
        !          1139:     return -1;
        !          1140: 
        !          1141:   subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len));
        !          1142:   subrta->rta_type = type;
        !          1143:   subrta->rta_len = len;
        !          1144:   memcpy (RTA_DATA (subrta), data, alen);
        !          1145:   rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len;
        !          1146: 
        !          1147:   return 0;
        !          1148: }
        !          1149: 
        !          1150: /* Utility function comes from iproute2. 
        !          1151:    Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> */
        !          1152: static int
        !          1153: addattr32 (struct nlmsghdr *n, int maxlen, int type, int data)
        !          1154: {
        !          1155:   int len;
        !          1156:   struct rtattr *rta;
        !          1157: 
        !          1158:   len = RTA_LENGTH (4);
        !          1159: 
        !          1160:   if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen)
        !          1161:     return -1;
        !          1162: 
        !          1163:   rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len));
        !          1164:   rta->rta_type = type;
        !          1165:   rta->rta_len = len;
        !          1166:   memcpy (RTA_DATA (rta), &data, 4);
        !          1167:   n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len;
        !          1168: 
        !          1169:   return 0;
        !          1170: }
        !          1171: 
        !          1172: static int
        !          1173: netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
        !          1174: {
        !          1175:   zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
        !          1176:   return 0;
        !          1177: }
        !          1178: 
        !          1179: /* sendmsg() to netlink socket then recvmsg(). */
        !          1180: static int
        !          1181: netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
        !          1182: {
        !          1183:   int status;
        !          1184:   struct sockaddr_nl snl;
        !          1185:   struct iovec iov = { (void *) n, n->nlmsg_len };
        !          1186:   struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
        !          1187:   int save_errno;
        !          1188: 
        !          1189:   memset (&snl, 0, sizeof snl);
        !          1190:   snl.nl_family = AF_NETLINK;
        !          1191: 
        !          1192:   n->nlmsg_seq = ++nl->seq;
        !          1193: 
        !          1194:   /* Request an acknowledgement by setting NLM_F_ACK */
        !          1195:   n->nlmsg_flags |= NLM_F_ACK;
        !          1196: 
        !          1197:   if (IS_ZEBRA_DEBUG_KERNEL)
        !          1198:     zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name,
        !          1199:                lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type,
        !          1200:                n->nlmsg_seq);
        !          1201: 
        !          1202:   /* Send message to netlink interface. */
        !          1203:   if (zserv_privs.change (ZPRIVS_RAISE))
        !          1204:     zlog (NULL, LOG_ERR, "Can't raise privileges");
        !          1205:   status = sendmsg (nl->sock, &msg, 0);
        !          1206:   save_errno = errno;
        !          1207:   if (zserv_privs.change (ZPRIVS_LOWER))
        !          1208:     zlog (NULL, LOG_ERR, "Can't lower privileges");
        !          1209: 
        !          1210:   if (status < 0)
        !          1211:     {
        !          1212:       zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s",
        !          1213:             safe_strerror (save_errno));
        !          1214:       return -1;
        !          1215:     }
        !          1216: 
        !          1217: 
        !          1218:   /* 
        !          1219:    * Get reply from netlink socket. 
        !          1220:    * The reply should either be an acknowlegement or an error.
        !          1221:    */
        !          1222:   return netlink_parse_info (netlink_talk_filter, nl);
        !          1223: }
        !          1224: 
        !          1225: /* Routing table change via netlink interface. */
        !          1226: static int
        !          1227: netlink_route (int cmd, int family, void *dest, int length, void *gate,
        !          1228:                int index, int zebra_flags, int table)
        !          1229: {
        !          1230:   int ret;
        !          1231:   int bytelen;
        !          1232:   struct sockaddr_nl snl;
        !          1233:   int discard;
        !          1234: 
        !          1235:   struct
        !          1236:   {
        !          1237:     struct nlmsghdr n;
        !          1238:     struct rtmsg r;
        !          1239:     char buf[1024];
        !          1240:   } req;
        !          1241: 
        !          1242:   memset (&req, 0, sizeof req);
        !          1243: 
        !          1244:   bytelen = (family == AF_INET ? 4 : 16);
        !          1245: 
        !          1246:   req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
        !          1247:   req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
        !          1248:   req.n.nlmsg_type = cmd;
        !          1249:   req.r.rtm_family = family;
        !          1250:   req.r.rtm_table = table;
        !          1251:   req.r.rtm_dst_len = length;
        !          1252:   req.r.rtm_protocol = RTPROT_ZEBRA;
        !          1253:   req.r.rtm_scope = RT_SCOPE_UNIVERSE;
        !          1254: 
        !          1255:   if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE)
        !          1256:       || (zebra_flags & ZEBRA_FLAG_REJECT))
        !          1257:     discard = 1;
        !          1258:   else
        !          1259:     discard = 0;
        !          1260: 
        !          1261:   if (cmd == RTM_NEWROUTE)
        !          1262:     {
        !          1263:       if (discard)
        !          1264:         {
        !          1265:           if (zebra_flags & ZEBRA_FLAG_BLACKHOLE)
        !          1266:             req.r.rtm_type = RTN_BLACKHOLE;
        !          1267:           else if (zebra_flags & ZEBRA_FLAG_REJECT)
        !          1268:             req.r.rtm_type = RTN_UNREACHABLE;
        !          1269:           else
        !          1270:             assert (RTN_BLACKHOLE != RTN_UNREACHABLE);  /* false */
        !          1271:         }
        !          1272:       else
        !          1273:         req.r.rtm_type = RTN_UNICAST;
        !          1274:     }
        !          1275: 
        !          1276:   if (dest)
        !          1277:     addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen);
        !          1278: 
        !          1279:   if (!discard)
        !          1280:     {
        !          1281:       if (gate)
        !          1282:         addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen);
        !          1283:       if (index > 0)
        !          1284:         addattr32 (&req.n, sizeof req, RTA_OIF, index);
        !          1285:     }
        !          1286: 
        !          1287:   /* Destination netlink address. */
        !          1288:   memset (&snl, 0, sizeof snl);
        !          1289:   snl.nl_family = AF_NETLINK;
        !          1290: 
        !          1291:   /* Talk to netlink socket. */
        !          1292:   ret = netlink_talk (&req.n, &netlink_cmd);
        !          1293:   if (ret < 0)
        !          1294:     return -1;
        !          1295: 
        !          1296:   return 0;
        !          1297: }
        !          1298: 
        !          1299: /* Routing table change via netlink interface. */
        !          1300: static int
        !          1301: netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib,
        !          1302:                          int family)
        !          1303: {
        !          1304:   int bytelen;
        !          1305:   struct sockaddr_nl snl;
        !          1306:   struct nexthop *nexthop = NULL;
        !          1307:   int nexthop_num = 0;
        !          1308:   int discard;
        !          1309: 
        !          1310:   struct
        !          1311:   {
        !          1312:     struct nlmsghdr n;
        !          1313:     struct rtmsg r;
        !          1314:     char buf[1024];
        !          1315:   } req;
        !          1316: 
        !          1317:   memset (&req, 0, sizeof req);
        !          1318: 
        !          1319:   bytelen = (family == AF_INET ? 4 : 16);
        !          1320: 
        !          1321:   req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
        !          1322:   req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
        !          1323:   req.n.nlmsg_type = cmd;
        !          1324:   req.r.rtm_family = family;
        !          1325:   req.r.rtm_table = rib->table;
        !          1326:   req.r.rtm_dst_len = p->prefixlen;
        !          1327:   req.r.rtm_protocol = RTPROT_ZEBRA;
        !          1328:   req.r.rtm_scope = RT_SCOPE_UNIVERSE;
        !          1329: 
        !          1330:   if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
        !          1331:     discard = 1;
        !          1332:   else
        !          1333:     discard = 0;
        !          1334: 
        !          1335:   if (cmd == RTM_NEWROUTE)
        !          1336:     {
        !          1337:       if (discard)
        !          1338:         {
        !          1339:           if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
        !          1340:             req.r.rtm_type = RTN_BLACKHOLE;
        !          1341:           else if (rib->flags & ZEBRA_FLAG_REJECT)
        !          1342:             req.r.rtm_type = RTN_UNREACHABLE;
        !          1343:           else
        !          1344:             assert (RTN_BLACKHOLE != RTN_UNREACHABLE);  /* false */
        !          1345:         }
        !          1346:       else
        !          1347:         req.r.rtm_type = RTN_UNICAST;
        !          1348:     }
        !          1349: 
        !          1350:   addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
        !          1351: 
        !          1352:   /* Metric. */
        !          1353:   addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric);
        !          1354: 
        !          1355:   if (discard)
        !          1356:     {
        !          1357:       if (cmd == RTM_NEWROUTE)
        !          1358:         for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
        !          1359:           SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
        !          1360:       goto skip;
        !          1361:     }
        !          1362: 
        !          1363:   /* Multipath case. */
        !          1364:   if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
        !          1365:     {
        !          1366:       for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
        !          1367:         {
        !          1368: 
        !          1369:           if ((cmd == RTM_NEWROUTE
        !          1370:                && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
        !          1371:               || (cmd == RTM_DELROUTE
        !          1372:                   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
        !          1373:             {
        !          1374: 
        !          1375:               if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
        !          1376:                 {
        !          1377:                   if (IS_ZEBRA_DEBUG_KERNEL)
        !          1378:                     {
        !          1379:                       zlog_debug
        !          1380:                         ("netlink_route_multipath() (recursive, 1 hop): "
        !          1381:                          "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
        !          1382: #ifdef HAVE_IPV6
        !          1383:                         (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
        !          1384:                         inet6_ntoa (p->u.prefix6),
        !          1385: #else
        !          1386:                         inet_ntoa (p->u.prefix4),
        !          1387: #endif /* HAVE_IPV6 */
        !          1388:                         
        !          1389:                         p->prefixlen, nexthop_types_desc[nexthop->rtype]);
        !          1390:                     }
        !          1391: 
        !          1392:                   if (nexthop->rtype == NEXTHOP_TYPE_IPV4
        !          1393:                       || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
        !          1394:                    {
        !          1395:                      addattr_l (&req.n, sizeof req, RTA_GATEWAY,
        !          1396:                                 &nexthop->rgate.ipv4, bytelen);
        !          1397:                       if (nexthop->src.ipv4.s_addr)
        !          1398:                          addattr_l(&req.n, sizeof req, RTA_PREFSRC,
        !          1399:                                     &nexthop->src.ipv4, bytelen);
        !          1400:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1401:                        zlog_debug("netlink_route_multipath() (recursive, "
        !          1402:                                   "1 hop): nexthop via %s if %u",
        !          1403:                                   inet_ntoa (nexthop->rgate.ipv4),
        !          1404:                                   nexthop->rifindex);
        !          1405:                    }
        !          1406: #ifdef HAVE_IPV6
        !          1407:                   if (nexthop->rtype == NEXTHOP_TYPE_IPV6
        !          1408:                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
        !          1409:                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
        !          1410:                    {
        !          1411:                      addattr_l (&req.n, sizeof req, RTA_GATEWAY,
        !          1412:                                 &nexthop->rgate.ipv6, bytelen);
        !          1413: 
        !          1414:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1415:                        zlog_debug("netlink_route_multipath() (recursive, "
        !          1416:                                   "1 hop): nexthop via %s if %u",
        !          1417:                                   inet6_ntoa (nexthop->rgate.ipv6),
        !          1418:                                   nexthop->rifindex);
        !          1419:                    }
        !          1420: #endif /* HAVE_IPV6 */
        !          1421:                   if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
        !          1422:                       || nexthop->rtype == NEXTHOP_TYPE_IFNAME
        !          1423:                       || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
        !          1424:                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
        !          1425:                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
        !          1426:                    {
        !          1427:                      addattr32 (&req.n, sizeof req, RTA_OIF,
        !          1428:                                 nexthop->rifindex);
        !          1429:                       if ((nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
        !          1430:                            || nexthop->rtype == NEXTHOP_TYPE_IFINDEX)
        !          1431:                           && nexthop->src.ipv4.s_addr)
        !          1432:                         addattr_l (&req.n, sizeof req, RTA_PREFSRC,
        !          1433:                                 &nexthop->src.ipv4, bytelen);
        !          1434: 
        !          1435:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1436:                        zlog_debug("netlink_route_multipath() (recursive, "
        !          1437:                                   "1 hop): nexthop via if %u",
        !          1438:                                   nexthop->rifindex);
        !          1439:                    }
        !          1440:                 }
        !          1441:               else
        !          1442:                 {
        !          1443:                   if (IS_ZEBRA_DEBUG_KERNEL)
        !          1444:                     {
        !          1445:                       zlog_debug
        !          1446:                         ("netlink_route_multipath() (single hop): "
        !          1447:                          "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
        !          1448: #ifdef HAVE_IPV6
        !          1449:                         (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
        !          1450:                         inet6_ntoa (p->u.prefix6),
        !          1451: #else
        !          1452:                         inet_ntoa (p->u.prefix4),
        !          1453: #endif /* HAVE_IPV6 */
        !          1454:                         p->prefixlen, nexthop_types_desc[nexthop->type]);
        !          1455:                     }
        !          1456: 
        !          1457:                   if (nexthop->type == NEXTHOP_TYPE_IPV4
        !          1458:                       || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
        !          1459:                    {
        !          1460:                      addattr_l (&req.n, sizeof req, RTA_GATEWAY,
        !          1461:                                 &nexthop->gate.ipv4, bytelen);
        !          1462:                      if (nexthop->src.ipv4.s_addr)
        !          1463:                         addattr_l (&req.n, sizeof req, RTA_PREFSRC,
        !          1464:                                 &nexthop->src.ipv4, bytelen);
        !          1465: 
        !          1466:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1467:                        zlog_debug("netlink_route_multipath() (single hop): "
        !          1468:                                   "nexthop via %s if %u",
        !          1469:                                   inet_ntoa (nexthop->gate.ipv4),
        !          1470:                                   nexthop->ifindex);
        !          1471:                    }
        !          1472: #ifdef HAVE_IPV6
        !          1473:                   if (nexthop->type == NEXTHOP_TYPE_IPV6
        !          1474:                       || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
        !          1475:                       || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
        !          1476:                    {
        !          1477:                      addattr_l (&req.n, sizeof req, RTA_GATEWAY,
        !          1478:                                 &nexthop->gate.ipv6, bytelen);
        !          1479: 
        !          1480:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1481:                        zlog_debug("netlink_route_multipath() (single hop): "
        !          1482:                                   "nexthop via %s if %u",
        !          1483:                                   inet6_ntoa (nexthop->gate.ipv6),
        !          1484:                                   nexthop->ifindex);
        !          1485:                    }
        !          1486: #endif /* HAVE_IPV6 */
        !          1487:                   if (nexthop->type == NEXTHOP_TYPE_IFINDEX
        !          1488:                       || nexthop->type == NEXTHOP_TYPE_IFNAME
        !          1489:                       || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
        !          1490:                    {
        !          1491:                      addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
        !          1492: 
        !          1493:                      if (nexthop->src.ipv4.s_addr)
        !          1494:                         addattr_l (&req.n, sizeof req, RTA_PREFSRC,
        !          1495:                                 &nexthop->src.ipv4, bytelen);
        !          1496: 
        !          1497:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1498:                        zlog_debug("netlink_route_multipath() (single hop): "
        !          1499:                                   "nexthop via if %u", nexthop->ifindex);
        !          1500:                    }
        !          1501:                   else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
        !          1502:                       || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
        !          1503:                    {
        !          1504:                      addattr32 (&req.n, sizeof req, RTA_OIF, nexthop->ifindex);
        !          1505: 
        !          1506:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1507:                        zlog_debug("netlink_route_multipath() (single hop): "
        !          1508:                                   "nexthop via if %u", nexthop->ifindex);
        !          1509:                    }
        !          1510:                 }
        !          1511: 
        !          1512:               if (cmd == RTM_NEWROUTE)
        !          1513:                 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
        !          1514: 
        !          1515:               nexthop_num++;
        !          1516:               break;
        !          1517:             }
        !          1518:         }
        !          1519:     }
        !          1520:   else
        !          1521:     {
        !          1522:       char buf[1024];
        !          1523:       struct rtattr *rta = (void *) buf;
        !          1524:       struct rtnexthop *rtnh;
        !          1525:       union g_addr *src = NULL;
        !          1526: 
        !          1527:       rta->rta_type = RTA_MULTIPATH;
        !          1528:       rta->rta_len = RTA_LENGTH (0);
        !          1529:       rtnh = RTA_DATA (rta);
        !          1530: 
        !          1531:       nexthop_num = 0;
        !          1532:       for (nexthop = rib->nexthop;
        !          1533:            nexthop && (MULTIPATH_NUM == 0 || nexthop_num < MULTIPATH_NUM);
        !          1534:            nexthop = nexthop->next)
        !          1535:         {
        !          1536:           if ((cmd == RTM_NEWROUTE
        !          1537:                && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
        !          1538:               || (cmd == RTM_DELROUTE
        !          1539:                   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
        !          1540:             {
        !          1541:               nexthop_num++;
        !          1542: 
        !          1543:               rtnh->rtnh_len = sizeof (*rtnh);
        !          1544:               rtnh->rtnh_flags = 0;
        !          1545:               rtnh->rtnh_hops = 0;
        !          1546:               rta->rta_len += rtnh->rtnh_len;
        !          1547: 
        !          1548:               if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
        !          1549:                 {
        !          1550:                   if (IS_ZEBRA_DEBUG_KERNEL)
        !          1551:                     {
        !          1552:                       zlog_debug ("netlink_route_multipath() "
        !          1553:                          "(recursive, multihop): %s %s/%d type %s",
        !          1554:                         lookup (nlmsg_str, cmd),
        !          1555: #ifdef HAVE_IPV6
        !          1556:                         (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
        !          1557:                         inet6_ntoa (p->u.prefix6),
        !          1558: #else
        !          1559:                         inet_ntoa (p->u.prefix4),
        !          1560: #endif /* HAVE_IPV6 */
        !          1561:                          p->prefixlen, nexthop_types_desc[nexthop->rtype]);
        !          1562:                     }
        !          1563:                   if (nexthop->rtype == NEXTHOP_TYPE_IPV4
        !          1564:                       || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
        !          1565:                     {
        !          1566:                       rta_addattr_l (rta, 4096, RTA_GATEWAY,
        !          1567:                                      &nexthop->rgate.ipv4, bytelen);
        !          1568:                       rtnh->rtnh_len += sizeof (struct rtattr) + 4;
        !          1569: 
        !          1570:                      if (nexthop->src.ipv4.s_addr)
        !          1571:                         src = &nexthop->src;
        !          1572: 
        !          1573:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1574:                        zlog_debug("netlink_route_multipath() (recursive, "
        !          1575:                                   "multihop): nexthop via %s if %u",
        !          1576:                                   inet_ntoa (nexthop->rgate.ipv4),
        !          1577:                                   nexthop->rifindex);
        !          1578:                     }
        !          1579: #ifdef HAVE_IPV6
        !          1580:                   if (nexthop->rtype == NEXTHOP_TYPE_IPV6
        !          1581:                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
        !          1582:                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
        !          1583:                    {
        !          1584:                      rta_addattr_l (rta, 4096, RTA_GATEWAY,
        !          1585:                                     &nexthop->rgate.ipv6, bytelen);
        !          1586: 
        !          1587:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1588:                        zlog_debug("netlink_route_multipath() (recursive, "
        !          1589:                                   "multihop): nexthop via %s if %u",
        !          1590:                                   inet6_ntoa (nexthop->rgate.ipv6),
        !          1591:                                   nexthop->rifindex);
        !          1592:                    }
        !          1593: #endif /* HAVE_IPV6 */
        !          1594:                   /* ifindex */
        !          1595:                   if (nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX
        !          1596:                      || nexthop->rtype == NEXTHOP_TYPE_IFINDEX
        !          1597:                       || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
        !          1598:                    {
        !          1599:                      rtnh->rtnh_ifindex = nexthop->rifindex;
        !          1600:                       if (nexthop->src.ipv4.s_addr)
        !          1601:                         src = &nexthop->src;
        !          1602: 
        !          1603:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1604:                        zlog_debug("netlink_route_multipath() (recursive, "
        !          1605:                                   "multihop): nexthop via if %u",
        !          1606:                                   nexthop->rifindex);
        !          1607:                    }
        !          1608:                  else if (nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
        !          1609:                       || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
        !          1610:                    {
        !          1611:                      rtnh->rtnh_ifindex = nexthop->rifindex;
        !          1612: 
        !          1613:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1614:                        zlog_debug("netlink_route_multipath() (recursive, "
        !          1615:                                   "multihop): nexthop via if %u",
        !          1616:                                   nexthop->rifindex);
        !          1617:                    }
        !          1618:                   else
        !          1619:                    {
        !          1620:                      rtnh->rtnh_ifindex = 0;
        !          1621:                    }
        !          1622:                 }
        !          1623:               else
        !          1624:                 {
        !          1625:                   if (IS_ZEBRA_DEBUG_KERNEL)
        !          1626:                     {
        !          1627:                       zlog_debug ("netlink_route_multipath() (multihop): "
        !          1628:                          "%s %s/%d, type %s", lookup (nlmsg_str, cmd),
        !          1629: #ifdef HAVE_IPV6
        !          1630:                         (family == AF_INET) ? inet_ntoa (p->u.prefix4) :
        !          1631:                         inet6_ntoa (p->u.prefix6),
        !          1632: #else
        !          1633:                         inet_ntoa (p->u.prefix4),
        !          1634: #endif /* HAVE_IPV6 */
        !          1635:                         p->prefixlen, nexthop_types_desc[nexthop->type]);
        !          1636:                     }
        !          1637:                   if (nexthop->type == NEXTHOP_TYPE_IPV4
        !          1638:                       || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
        !          1639:                     {
        !          1640:                      rta_addattr_l (rta, 4096, RTA_GATEWAY,
        !          1641:                                     &nexthop->gate.ipv4, bytelen);
        !          1642:                      rtnh->rtnh_len += sizeof (struct rtattr) + 4;
        !          1643: 
        !          1644:                      if (nexthop->src.ipv4.s_addr)
        !          1645:                         src = &nexthop->src;
        !          1646: 
        !          1647:                       if (IS_ZEBRA_DEBUG_KERNEL)
        !          1648:                        zlog_debug("netlink_route_multipath() (multihop): "
        !          1649:                                   "nexthop via %s if %u",
        !          1650:                                   inet_ntoa (nexthop->gate.ipv4),
        !          1651:                                   nexthop->ifindex);
        !          1652:                     }
        !          1653: #ifdef HAVE_IPV6
        !          1654:                   if (nexthop->type == NEXTHOP_TYPE_IPV6
        !          1655:                       || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
        !          1656:                       || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
        !          1657:                    { 
        !          1658:                      rta_addattr_l (rta, 4096, RTA_GATEWAY,
        !          1659:                                     &nexthop->gate.ipv6, bytelen);
        !          1660: 
        !          1661:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1662:                        zlog_debug("netlink_route_multipath() (multihop): "
        !          1663:                                   "nexthop via %s if %u",
        !          1664:                                   inet6_ntoa (nexthop->gate.ipv6),
        !          1665:                                   nexthop->ifindex);
        !          1666:                    }
        !          1667: #endif /* HAVE_IPV6 */
        !          1668:                   /* ifindex */
        !          1669:                   if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
        !          1670:                      || nexthop->type == NEXTHOP_TYPE_IFINDEX
        !          1671:                       || nexthop->type == NEXTHOP_TYPE_IFNAME)
        !          1672:                     {
        !          1673:                      rtnh->rtnh_ifindex = nexthop->ifindex;
        !          1674:                      if (nexthop->src.ipv4.s_addr)
        !          1675:                        src = &nexthop->src;
        !          1676:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1677:                        zlog_debug("netlink_route_multipath() (multihop): "
        !          1678:                                   "nexthop via if %u", nexthop->ifindex);
        !          1679:                    }
        !          1680:                   else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
        !          1681:                       || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
        !          1682:                    {
        !          1683:                      rtnh->rtnh_ifindex = nexthop->ifindex;
        !          1684: 
        !          1685:                      if (IS_ZEBRA_DEBUG_KERNEL)
        !          1686:                        zlog_debug("netlink_route_multipath() (multihop): "
        !          1687:                                   "nexthop via if %u", nexthop->ifindex);
        !          1688:                    }
        !          1689:                   else
        !          1690:                    {
        !          1691:                      rtnh->rtnh_ifindex = 0;
        !          1692:                    }
        !          1693:                 }
        !          1694:               rtnh = RTNH_NEXT (rtnh);
        !          1695: 
        !          1696:               if (cmd == RTM_NEWROUTE)
        !          1697:                 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
        !          1698:             }
        !          1699:         }
        !          1700:       if (src)
        !          1701:         addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen);
        !          1702: 
        !          1703:       if (rta->rta_len > RTA_LENGTH (0))
        !          1704:         addattr_l (&req.n, 1024, RTA_MULTIPATH, RTA_DATA (rta),
        !          1705:                    RTA_PAYLOAD (rta));
        !          1706:     }
        !          1707: 
        !          1708:   /* If there is no useful nexthop then return. */
        !          1709:   if (nexthop_num == 0)
        !          1710:     {
        !          1711:       if (IS_ZEBRA_DEBUG_KERNEL)
        !          1712:         zlog_debug ("netlink_route_multipath(): No useful nexthop.");
        !          1713:       return 0;
        !          1714:     }
        !          1715: 
        !          1716: skip:
        !          1717: 
        !          1718:   /* Destination netlink address. */
        !          1719:   memset (&snl, 0, sizeof snl);
        !          1720:   snl.nl_family = AF_NETLINK;
        !          1721: 
        !          1722:   /* Talk to netlink socket. */
        !          1723:   return netlink_talk (&req.n, &netlink_cmd);
        !          1724: }
        !          1725: 
        !          1726: int
        !          1727: kernel_add_ipv4 (struct prefix *p, struct rib *rib)
        !          1728: {
        !          1729:   return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET);
        !          1730: }
        !          1731: 
        !          1732: int
        !          1733: kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
        !          1734: {
        !          1735:   return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET);
        !          1736: }
        !          1737: 
        !          1738: #ifdef HAVE_IPV6
        !          1739: int
        !          1740: kernel_add_ipv6 (struct prefix *p, struct rib *rib)
        !          1741: {
        !          1742:   return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6);
        !          1743: }
        !          1744: 
        !          1745: int
        !          1746: kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
        !          1747: {
        !          1748:   return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6);
        !          1749: }
        !          1750: 
        !          1751: /* Delete IPv6 route from the kernel. */
        !          1752: int
        !          1753: kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
        !          1754:                         unsigned int index, int flags, int table)
        !          1755: {
        !          1756:   return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix,
        !          1757:                         dest->prefixlen, gate, index, flags, table);
        !          1758: }
        !          1759: #endif /* HAVE_IPV6 */
        !          1760: 
        !          1761: /* Interface address modification. */
        !          1762: static int
        !          1763: netlink_address (int cmd, int family, struct interface *ifp,
        !          1764:                  struct connected *ifc)
        !          1765: {
        !          1766:   int bytelen;
        !          1767:   struct prefix *p;
        !          1768: 
        !          1769:   struct
        !          1770:   {
        !          1771:     struct nlmsghdr n;
        !          1772:     struct ifaddrmsg ifa;
        !          1773:     char buf[1024];
        !          1774:   } req;
        !          1775: 
        !          1776:   p = ifc->address;
        !          1777:   memset (&req, 0, sizeof req);
        !          1778: 
        !          1779:   bytelen = (family == AF_INET ? 4 : 16);
        !          1780: 
        !          1781:   req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg));
        !          1782:   req.n.nlmsg_flags = NLM_F_REQUEST;
        !          1783:   req.n.nlmsg_type = cmd;
        !          1784:   req.ifa.ifa_family = family;
        !          1785: 
        !          1786:   req.ifa.ifa_index = ifp->ifindex;
        !          1787:   req.ifa.ifa_prefixlen = p->prefixlen;
        !          1788: 
        !          1789:   addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen);
        !          1790: 
        !          1791:   if (family == AF_INET && cmd == RTM_NEWADDR)
        !          1792:     {
        !          1793:       if (!CONNECTED_PEER(ifc) && ifc->destination)
        !          1794:         {
        !          1795:           p = ifc->destination;
        !          1796:           addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix,
        !          1797:                      bytelen);
        !          1798:         }
        !          1799:     }
        !          1800: 
        !          1801:   if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
        !          1802:     SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY);
        !          1803: 
        !          1804:   if (ifc->label)
        !          1805:     addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
        !          1806:                strlen (ifc->label) + 1);
        !          1807: 
        !          1808:   return netlink_talk (&req.n, &netlink_cmd);
        !          1809: }
        !          1810: 
        !          1811: int
        !          1812: kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc)
        !          1813: {
        !          1814:   return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc);
        !          1815: }
        !          1816: 
        !          1817: int
        !          1818: kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc)
        !          1819: {
        !          1820:   return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc);
        !          1821: }
        !          1822: 
        !          1823: 
        !          1824: extern struct thread_master *master;
        !          1825: 
        !          1826: /* Kernel route reflection. */
        !          1827: static int
        !          1828: kernel_read (struct thread *thread)
        !          1829: {
        !          1830:   int ret;
        !          1831:   int sock;
        !          1832: 
        !          1833:   sock = THREAD_FD (thread);
        !          1834:   ret = netlink_parse_info (netlink_information_fetch, &netlink);
        !          1835:   thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
        !          1836: 
        !          1837:   return 0;
        !          1838: }
        !          1839: 
        !          1840: /* Filter out messages from self that occur on listener socket,
        !          1841:    caused by our actions on the command socket
        !          1842:  */
        !          1843: static void netlink_install_filter (int sock, __u32 pid)
        !          1844: {
        !          1845:   struct sock_filter filter[] = {
        !          1846:     /* 0: ldh [4]                */
        !          1847:     BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)),
        !          1848:     /* 1: jeq 0x18 jt 3 jf 6  */
        !          1849:     BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0),
        !          1850:     /* 2: jeq 0x19 jt 3 jf 6  */
        !          1851:     BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3),
        !          1852:     /* 3: ldw [12]               */
        !          1853:     BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)),
        !          1854:     /* 4: jeq XX  jt 5 jf 6   */
        !          1855:     BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1),
        !          1856:     /* 5: ret 0    (skip)     */
        !          1857:     BPF_STMT(BPF_RET|BPF_K, 0),
        !          1858:     /* 6: ret 0xffff (keep)   */
        !          1859:     BPF_STMT(BPF_RET|BPF_K, 0xffff),
        !          1860:   };
        !          1861: 
        !          1862:   struct sock_fprog prog = {
        !          1863:     .len = sizeof(filter) / sizeof(filter[0]),
        !          1864:     .filter = filter,
        !          1865:   };
        !          1866: 
        !          1867:   if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0)
        !          1868:     zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno));
        !          1869: }
        !          1870: 
        !          1871: /* Exported interface function.  This function simply calls
        !          1872:    netlink_socket (). */
        !          1873: void
        !          1874: kernel_init (void)
        !          1875: {
        !          1876:   unsigned long groups;
        !          1877: 
        !          1878:   groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
        !          1879: #ifdef HAVE_IPV6
        !          1880:   groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
        !          1881: #endif /* HAVE_IPV6 */
        !          1882:   netlink_socket (&netlink, groups);
        !          1883:   netlink_socket (&netlink_cmd, 0);
        !          1884: 
        !          1885:   /* Register kernel socket. */
        !          1886:   if (netlink.sock > 0)
        !          1887:     {
        !          1888:       /* Only want non-blocking on the netlink event socket */
        !          1889:       if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
        !          1890:        zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
        !          1891:                safe_strerror (errno));
        !          1892: 
        !          1893:       /* Set receive buffer size if it's set from command line */
        !          1894:       if (nl_rcvbufsize)
        !          1895:        netlink_recvbuf (&netlink, nl_rcvbufsize);
        !          1896: 
        !          1897:       netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
        !          1898:       thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
        !          1899:     }
        !          1900: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>