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

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

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