File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / zebra / rt_ioctl.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 4 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, v0_99_21, v0_99_20_1, v0_99_20, HEAD
quagga

    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>