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

1.1     ! misho       1: /*
        !             2:  * kernel routing table update by ioctl().
        !             3:  * Copyright (C) 1997, 98 Kunihiro Ishiguro
        !             4:  *
        !             5:  * This file is part of GNU Zebra.
        !             6:  *
        !             7:  * GNU Zebra is free software; you can redistribute it and/or modify it
        !             8:  * under the terms of the GNU General Public License as published by the
        !             9:  * Free Software Foundation; either version 2, or (at your option) any
        !            10:  * later version.
        !            11:  *
        !            12:  * GNU Zebra is distributed in the hope that it will be useful, but
        !            13:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            15:  * General Public License for more details.
        !            16:  *
        !            17:  * You should have received a copy of the GNU General Public License
        !            18:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
        !            19:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
        !            20:  * 02111-1307, USA.  
        !            21:  */
        !            22: 
        !            23: #include <zebra.h>
        !            24: 
        !            25: #include "prefix.h"
        !            26: #include "log.h"
        !            27: #include "if.h"
        !            28: 
        !            29: #include "zebra/zserv.h"
        !            30: #include "zebra/rib.h"
        !            31: #include "zebra/debug.h"
        !            32: #include "zebra/rt.h"
        !            33: 
        !            34: /* Initialize of kernel interface.  There is no kernel communication
        !            35:    support under ioctl().  So this is dummy stub function. */
        !            36: void
        !            37: kernel_init (void)
        !            38: {
        !            39:   return;
        !            40: }
        !            41: 
        !            42: /* Dummy function of routing socket. */
        !            43: static void
        !            44: kernel_read (int sock)
        !            45: {
        !            46:   return;
        !            47: }
        !            48: 
        !            49: #if 0
        !            50: /* Initialization prototype of struct sockaddr_in. */
        !            51: static struct sockaddr_in sin_proto =
        !            52: {
        !            53: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
        !            54:   sizeof (struct sockaddr_in), 
        !            55: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
        !            56:   AF_INET, 0, {0}, {0}
        !            57: };
        !            58: #endif /* 0 */
        !            59: 
        !            60: /* Solaris has ortentry. */
        !            61: #ifdef HAVE_OLD_RTENTRY
        !            62: #define rtentry ortentry
        !            63: #endif /* HAVE_OLD_RTENTRY */
        !            64: 
        !            65: /* Interface to ioctl route message. */
        !            66: int
        !            67: kernel_add_route (struct prefix_ipv4 *dest, struct in_addr *gate,
        !            68:                  int index, int flags)
        !            69: {
        !            70:   int ret;
        !            71:   int sock;
        !            72:   struct rtentry rtentry;
        !            73:   struct sockaddr_in sin_dest, sin_mask, sin_gate;
        !            74: 
        !            75:   memset (&rtentry, 0, sizeof (struct rtentry));
        !            76: 
        !            77:   /* Make destination. */
        !            78:   memset (&sin_dest, 0, sizeof (struct sockaddr_in));
        !            79:   sin_dest.sin_family = AF_INET;
        !            80: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
        !            81:   sin_dest.sin_len = sizeof (struct sockaddr_in);
        !            82: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
        !            83:   sin_dest.sin_addr = dest->prefix;
        !            84: 
        !            85:   /* Make gateway. */
        !            86:   if (gate)
        !            87:     {
        !            88:       memset (&sin_gate, 0, sizeof (struct sockaddr_in));
        !            89:       sin_gate.sin_family = AF_INET;
        !            90: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
        !            91:       sin_gate.sin_len = sizeof (struct sockaddr_in);
        !            92: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
        !            93:       sin_gate.sin_addr = *gate;
        !            94:     }
        !            95: 
        !            96:   memset (&sin_mask, 0, sizeof (struct sockaddr_in));
        !            97:   sin_mask.sin_family = AF_INET;
        !            98: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
        !            99:       sin_gate.sin_len = sizeof (struct sockaddr_in);
        !           100: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
        !           101:   masklen2ip (dest->prefixlen, &sin_mask.sin_addr);
        !           102: 
        !           103:   /* Set destination address, mask and gateway.*/
        !           104:   memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
        !           105:   if (gate)
        !           106:     memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
        !           107: #ifndef SUNOS_5
        !           108:   memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
        !           109: #endif /* SUNOS_5 */
        !           110: 
        !           111:   /* Routing entry flag set. */
        !           112:   if (dest->prefixlen == 32)
        !           113:     rtentry.rt_flags |= RTF_HOST;
        !           114: 
        !           115:   if (gate && gate->s_addr != INADDR_ANY)
        !           116:     rtentry.rt_flags |= RTF_GATEWAY;
        !           117: 
        !           118:   rtentry.rt_flags |= RTF_UP;
        !           119: 
        !           120:   /* Additional flags */
        !           121:   rtentry.rt_flags |= flags;
        !           122: 
        !           123: 
        !           124:   /* For tagging route. */
        !           125:   /* rtentry.rt_flags |= RTF_DYNAMIC; */
        !           126: 
        !           127:   /* Open socket for ioctl. */
        !           128:   sock = socket (AF_INET, SOCK_DGRAM, 0);
        !           129:   if (sock < 0)
        !           130:     {
        !           131:       zlog_warn ("can't make socket\n");
        !           132:       return -1;
        !           133:     }
        !           134: 
        !           135:   /* Send message by ioctl(). */
        !           136:   ret = ioctl (sock, SIOCADDRT, &rtentry);
        !           137:   if (ret < 0)
        !           138:     {
        !           139:       switch (errno) 
        !           140:        {
        !           141:        case EEXIST:
        !           142:          close (sock);
        !           143:          return ZEBRA_ERR_RTEXIST;
        !           144:          break;
        !           145:        case ENETUNREACH:
        !           146:          close (sock);
        !           147:          return ZEBRA_ERR_RTUNREACH;
        !           148:          break;
        !           149:        case EPERM:
        !           150:          close (sock);
        !           151:          return ZEBRA_ERR_EPERM;
        !           152:          break;
        !           153:        }
        !           154: 
        !           155:       close (sock);
        !           156:       zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
        !           157:       return 1;
        !           158:     }
        !           159:   close (sock);
        !           160: 
        !           161:   return ret;
        !           162: }
        !           163: 
        !           164: /* Interface to ioctl route message. */
        !           165: static int
        !           166: kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family)
        !           167: {
        !           168:   int ret;
        !           169:   int sock;
        !           170:   struct rtentry rtentry;
        !           171:   struct sockaddr_in sin_dest, sin_mask, sin_gate;
        !           172:   struct nexthop *nexthop;
        !           173:   int nexthop_num = 0;
        !           174:   struct interface *ifp;
        !           175: 
        !           176:   memset (&rtentry, 0, sizeof (struct rtentry));
        !           177: 
        !           178:   /* Make destination. */
        !           179:   memset (&sin_dest, 0, sizeof (struct sockaddr_in));
        !           180:   sin_dest.sin_family = AF_INET;
        !           181: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
        !           182:   sin_dest.sin_len = sizeof (struct sockaddr_in);
        !           183: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
        !           184:   sin_dest.sin_addr = p->u.prefix4;
        !           185: 
        !           186:   if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE))
        !           187:     {
        !           188:       SET_FLAG (rtentry.rt_flags, RTF_REJECT);
        !           189: 
        !           190:       if (cmd == SIOCADDRT)
        !           191:        for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
        !           192:          SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
        !           193: 
        !           194:       goto skip;
        !           195:     }
        !           196: 
        !           197:   memset (&sin_gate, 0, sizeof (struct sockaddr_in));
        !           198: 
        !           199:   /* Make gateway. */
        !           200:   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
        !           201:     {
        !           202:       if ((cmd == SIOCADDRT 
        !           203:           && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
        !           204:          || (cmd == SIOCDELRT
        !           205:              && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
        !           206:        {
        !           207:          if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
        !           208:            {
        !           209:              if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
        !           210:                  nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
        !           211:                {
        !           212:                  sin_gate.sin_family = AF_INET;
        !           213: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
        !           214:                  sin_gate.sin_len = sizeof (struct sockaddr_in);
        !           215: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
        !           216:                  sin_gate.sin_addr = nexthop->rgate.ipv4;
        !           217:                  rtentry.rt_flags |= RTF_GATEWAY;
        !           218:                }
        !           219:              if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
        !           220:                  || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
        !           221:                {
        !           222:                  ifp = if_lookup_by_index (nexthop->rifindex);
        !           223:                  if (ifp)
        !           224:                    rtentry.rt_dev = ifp->name;
        !           225:                  else
        !           226:                    return -1;
        !           227:                }
        !           228:            }
        !           229:          else
        !           230:            {
        !           231:              if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
        !           232:                  nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
        !           233:                {
        !           234:                  sin_gate.sin_family = AF_INET;
        !           235: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
        !           236:                  sin_gate.sin_len = sizeof (struct sockaddr_in);
        !           237: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
        !           238:                  sin_gate.sin_addr = nexthop->gate.ipv4;
        !           239:                  rtentry.rt_flags |= RTF_GATEWAY;
        !           240:                }
        !           241:              if (nexthop->type == NEXTHOP_TYPE_IFINDEX
        !           242:                  || nexthop->type == NEXTHOP_TYPE_IFNAME)
        !           243:                {
        !           244:                  ifp = if_lookup_by_index (nexthop->ifindex);
        !           245:                  if (ifp)
        !           246:                    rtentry.rt_dev = ifp->name;
        !           247:                  else
        !           248:                    return -1;
        !           249:                }
        !           250:            }
        !           251: 
        !           252:          if (cmd == SIOCADDRT)
        !           253:            SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
        !           254: 
        !           255:          nexthop_num++;
        !           256:          break;
        !           257:        }
        !           258:     }
        !           259: 
        !           260:   /* If there is no useful nexthop then return. */
        !           261:   if (nexthop_num == 0)
        !           262:     {
        !           263:       if (IS_ZEBRA_DEBUG_KERNEL)
        !           264:        zlog_debug ("netlink_route_multipath(): No useful nexthop.");
        !           265:       return 0;
        !           266:     }
        !           267: 
        !           268:  skip:
        !           269: 
        !           270:   memset (&sin_mask, 0, sizeof (struct sockaddr_in));
        !           271:   sin_mask.sin_family = AF_INET;
        !           272: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
        !           273:   sin_mask.sin_len = sizeof (struct sockaddr_in);
        !           274: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
        !           275:   masklen2ip (p->prefixlen, &sin_mask.sin_addr);
        !           276: 
        !           277:   /* Set destination address, mask and gateway.*/
        !           278:   memcpy (&rtentry.rt_dst, &sin_dest, sizeof (struct sockaddr_in));
        !           279: 
        !           280:   if (rtentry.rt_flags & RTF_GATEWAY)
        !           281:     memcpy (&rtentry.rt_gateway, &sin_gate, sizeof (struct sockaddr_in));
        !           282: 
        !           283: #ifndef SUNOS_5
        !           284:   memcpy (&rtentry.rt_genmask, &sin_mask, sizeof (struct sockaddr_in));
        !           285: #endif /* SUNOS_5 */
        !           286: 
        !           287:   /* Metric.  It seems metric minus one value is installed... */
        !           288:   rtentry.rt_metric = rib->metric;
        !           289: 
        !           290:   /* Routing entry flag set. */
        !           291:   if (p->prefixlen == 32)
        !           292:     rtentry.rt_flags |= RTF_HOST;
        !           293: 
        !           294:   rtentry.rt_flags |= RTF_UP;
        !           295: 
        !           296:   /* Additional flags */
        !           297:   /* rtentry.rt_flags |= flags; */
        !           298: 
        !           299:   /* For tagging route. */
        !           300:   /* rtentry.rt_flags |= RTF_DYNAMIC; */
        !           301: 
        !           302:   /* Open socket for ioctl. */
        !           303:   sock = socket (AF_INET, SOCK_DGRAM, 0);
        !           304:   if (sock < 0)
        !           305:     {
        !           306:       zlog_warn ("can't make socket\n");
        !           307:       return -1;
        !           308:     }
        !           309: 
        !           310:   /* Send message by ioctl(). */
        !           311:   ret = ioctl (sock, cmd, &rtentry);
        !           312:   if (ret < 0)
        !           313:     {
        !           314:       switch (errno) 
        !           315:        {
        !           316:        case EEXIST:
        !           317:          close (sock);
        !           318:          return ZEBRA_ERR_RTEXIST;
        !           319:          break;
        !           320:        case ENETUNREACH:
        !           321:          close (sock);
        !           322:          return ZEBRA_ERR_RTUNREACH;
        !           323:          break;
        !           324:        case EPERM:
        !           325:          close (sock);
        !           326:          return ZEBRA_ERR_EPERM;
        !           327:          break;
        !           328:        }
        !           329: 
        !           330:       close (sock);
        !           331:       zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
        !           332:       return ret;
        !           333:     }
        !           334:   close (sock);
        !           335: 
        !           336:   return ret;
        !           337: }
        !           338: 
        !           339: int
        !           340: kernel_add_ipv4 (struct prefix *p, struct rib *rib)
        !           341: {
        !           342:   return kernel_ioctl_ipv4 (SIOCADDRT, p, rib, AF_INET);
        !           343: }
        !           344: 
        !           345: int
        !           346: kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
        !           347: {
        !           348:   return kernel_ioctl_ipv4 (SIOCDELRT, p, rib, AF_INET);
        !           349: }
        !           350: 
        !           351: #ifdef HAVE_IPV6
        !           352: 
        !           353: /* Below is hack for GNU libc definition and Linux 2.1.X header. */
        !           354: #undef RTF_DEFAULT
        !           355: #undef RTF_ADDRCONF
        !           356: 
        !           357: #include <asm/types.h>
        !           358: 
        !           359: #if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
        !           360: /* struct in6_rtmsg will be declared in net/route.h. */
        !           361: #else
        !           362: #include <linux/ipv6_route.h>
        !           363: #endif
        !           364: 
        !           365: static int
        !           366: kernel_ioctl_ipv6 (u_long type, struct prefix_ipv6 *dest, struct in6_addr *gate,
        !           367:                   int index, int flags)
        !           368: {
        !           369:   int ret;
        !           370:   int sock;
        !           371:   struct in6_rtmsg rtm;
        !           372:     
        !           373:   memset (&rtm, 0, sizeof (struct in6_rtmsg));
        !           374: 
        !           375:   rtm.rtmsg_flags |= RTF_UP;
        !           376:   rtm.rtmsg_metric = 1;
        !           377:   memcpy (&rtm.rtmsg_dst, &dest->prefix, sizeof (struct in6_addr));
        !           378:   rtm.rtmsg_dst_len = dest->prefixlen;
        !           379: 
        !           380:   /* We need link local index. But this should be done caller...
        !           381:   if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
        !           382:     {
        !           383:       index = if_index_address (&rtm.rtmsg_gateway);
        !           384:       rtm.rtmsg_ifindex = index;
        !           385:     }
        !           386:   else
        !           387:     rtm.rtmsg_ifindex = 0;
        !           388:   */
        !           389: 
        !           390:   rtm.rtmsg_flags |= RTF_GATEWAY;
        !           391: 
        !           392:   /* For tagging route. */
        !           393:   /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
        !           394: 
        !           395:   memcpy (&rtm.rtmsg_gateway, gate, sizeof (struct in6_addr));
        !           396: 
        !           397:   if (index)
        !           398:     rtm.rtmsg_ifindex = index;
        !           399:   else
        !           400:     rtm.rtmsg_ifindex = 0;
        !           401: 
        !           402:   rtm.rtmsg_metric = 1;
        !           403:   
        !           404:   sock = socket (AF_INET6, SOCK_DGRAM, 0);
        !           405:   if (sock < 0)
        !           406:     {
        !           407:       zlog_warn ("can't make socket\n");
        !           408:       return -1;
        !           409:     }
        !           410: 
        !           411:   /* Send message via ioctl. */
        !           412:   ret = ioctl (sock, type, &rtm);
        !           413:   if (ret < 0)
        !           414:     {
        !           415:       zlog_warn ("can't %s ipv6 route: %s\n", type == SIOCADDRT ? "add" : "delete", 
        !           416:           safe_strerror(errno));
        !           417:       ret = errno;
        !           418:       close (sock);
        !           419:       return ret;
        !           420:     }
        !           421:   close (sock);
        !           422: 
        !           423:   return ret;
        !           424: }
        !           425: 
        !           426: static int
        !           427: kernel_ioctl_ipv6_multipath (u_long cmd, struct prefix *p, struct rib *rib,
        !           428:                             int family)
        !           429: {
        !           430:   int ret;
        !           431:   int sock;
        !           432:   struct in6_rtmsg rtm;
        !           433:   struct nexthop *nexthop;
        !           434:   int nexthop_num = 0;
        !           435:     
        !           436:   memset (&rtm, 0, sizeof (struct in6_rtmsg));
        !           437: 
        !           438:   rtm.rtmsg_flags |= RTF_UP;
        !           439:   rtm.rtmsg_metric = rib->metric;
        !           440:   memcpy (&rtm.rtmsg_dst, &p->u.prefix, sizeof (struct in6_addr));
        !           441:   rtm.rtmsg_dst_len = p->prefixlen;
        !           442: 
        !           443:   /* We need link local index. But this should be done caller...
        !           444:   if (IN6_IS_ADDR_LINKLOCAL(&rtm.rtmsg_gateway))
        !           445:     {
        !           446:       index = if_index_address (&rtm.rtmsg_gateway);
        !           447:       rtm.rtmsg_ifindex = index;
        !           448:     }
        !           449:   else
        !           450:     rtm.rtmsg_ifindex = 0;
        !           451:   */
        !           452: 
        !           453:   rtm.rtmsg_flags |= RTF_GATEWAY;
        !           454: 
        !           455:   /* For tagging route. */
        !           456:   /* rtm.rtmsg_flags |= RTF_DYNAMIC; */
        !           457: 
        !           458:   /* Make gateway. */
        !           459:   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
        !           460:     {
        !           461:       if ((cmd == SIOCADDRT 
        !           462:           && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
        !           463:          || (cmd == SIOCDELRT
        !           464:              && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
        !           465:        {
        !           466:          if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
        !           467:            {
        !           468:              if (nexthop->rtype == NEXTHOP_TYPE_IPV6
        !           469:                  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
        !           470:                  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
        !           471:                {
        !           472:                  memcpy (&rtm.rtmsg_gateway, &nexthop->rgate.ipv6,
        !           473:                          sizeof (struct in6_addr));
        !           474:                }
        !           475:              if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
        !           476:                  || nexthop->rtype == NEXTHOP_TYPE_IFNAME
        !           477:                  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
        !           478:                  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
        !           479:                rtm.rtmsg_ifindex = nexthop->rifindex;
        !           480:              else
        !           481:                rtm.rtmsg_ifindex = 0;
        !           482:              
        !           483:            }
        !           484:          else
        !           485:            {
        !           486:              if (nexthop->type == NEXTHOP_TYPE_IPV6
        !           487:                  || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
        !           488:                  || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
        !           489:                {
        !           490:                  memcpy (&rtm.rtmsg_gateway, &nexthop->gate.ipv6,
        !           491:                          sizeof (struct in6_addr));
        !           492:                }
        !           493:              if (nexthop->type == NEXTHOP_TYPE_IFINDEX
        !           494:                  || nexthop->type == NEXTHOP_TYPE_IFNAME
        !           495:                  || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
        !           496:                  || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
        !           497:                rtm.rtmsg_ifindex = nexthop->ifindex;
        !           498:              else
        !           499:                rtm.rtmsg_ifindex = 0;
        !           500:            }
        !           501: 
        !           502:          if (cmd == SIOCADDRT)
        !           503:            SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
        !           504: 
        !           505:          nexthop_num++;
        !           506:          break;
        !           507:        }
        !           508:     }
        !           509: 
        !           510:   /* If there is no useful nexthop then return. */
        !           511:   if (nexthop_num == 0)
        !           512:     {
        !           513:       if (IS_ZEBRA_DEBUG_KERNEL)
        !           514:        zlog_debug ("netlink_route_multipath(): No useful nexthop.");
        !           515:       return 0;
        !           516:     }
        !           517: 
        !           518:   sock = socket (AF_INET6, SOCK_DGRAM, 0);
        !           519:   if (sock < 0)
        !           520:     {
        !           521:       zlog_warn ("can't make socket\n");
        !           522:       return -1;
        !           523:     }
        !           524: 
        !           525:   /* Send message via ioctl. */
        !           526:   ret = ioctl (sock, cmd, &rtm);
        !           527:   if (ret < 0)
        !           528:     {
        !           529:       zlog_warn ("can't %s ipv6 route: %s\n",
        !           530:                 cmd == SIOCADDRT ? "add" : "delete", 
        !           531:           safe_strerror(errno));
        !           532:       ret = errno;
        !           533:       close (sock);
        !           534:       return ret;
        !           535:     }
        !           536:   close (sock);
        !           537: 
        !           538:   return ret;
        !           539: }
        !           540: 
        !           541: int
        !           542: kernel_add_ipv6 (struct prefix *p, struct rib *rib)
        !           543: {
        !           544:   return kernel_ioctl_ipv6_multipath (SIOCADDRT, p, rib, AF_INET6);
        !           545: }
        !           546: 
        !           547: int
        !           548: kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
        !           549: {
        !           550:   return kernel_ioctl_ipv6_multipath (SIOCDELRT, p, rib, AF_INET6);
        !           551: }
        !           552: 
        !           553: /* Delete IPv6 route from the kernel. */
        !           554: int
        !           555: kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
        !           556:                    unsigned int index, int flags, int table)
        !           557: {
        !           558:   return kernel_ioctl_ipv6 (SIOCDELRT, dest, gate, index, flags);
        !           559: }
        !           560: #endif /* HAVE_IPV6 */

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