File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / zebra / rt_socket.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, 6 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 updates by routing socket.
    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 "if.h"
   26: #include "prefix.h"
   27: #include "sockunion.h"
   28: #include "log.h"
   29: #include "str.h"
   30: #include "privs.h"
   31: 
   32: #include "zebra/debug.h"
   33: #include "zebra/rib.h"
   34: #include "zebra/rt.h"
   35: #include "zebra/kernel_socket.h"
   36: 
   37: extern struct zebra_privs_t zserv_privs;
   38: 
   39: /* kernel socket export */
   40: extern int rtm_write (int message, union sockunion *dest,
   41:                       union sockunion *mask, union sockunion *gate,
   42:                       unsigned int index, int zebra_flags, int metric);
   43: 
   44: /* Adjust netmask socket length. Return value is a adjusted sin_len
   45:    value. */
   46: static int
   47: sin_masklen (struct in_addr mask)
   48: {
   49:   char *p, *lim;
   50:   int len;
   51:   struct sockaddr_in sin;
   52: 
   53:   if (mask.s_addr == 0) 
   54:     return sizeof (long);
   55: 
   56:   sin.sin_addr = mask;
   57:   len = sizeof (struct sockaddr_in);
   58: 
   59:   lim = (char *) &sin.sin_addr;
   60:   p = lim + sizeof (sin.sin_addr);
   61: 
   62:   while (*--p == 0 && p >= lim) 
   63:     len--;
   64:   return len;
   65: }
   66: 
   67: /* Interface between zebra message and rtm message. */
   68: static int
   69: kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
   70: 
   71: {
   72:   struct sockaddr_in *mask = NULL;
   73:   struct sockaddr_in sin_dest, sin_mask, sin_gate;
   74:   struct nexthop *nexthop;
   75:   int nexthop_num = 0;
   76:   unsigned int ifindex = 0;
   77:   int gate = 0;
   78:   int error;
   79:   char prefix_buf[INET_ADDRSTRLEN];
   80: 
   81:   if (IS_ZEBRA_DEBUG_RIB)
   82:     inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN);
   83:   memset (&sin_dest, 0, sizeof (struct sockaddr_in));
   84:   sin_dest.sin_family = AF_INET;
   85: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
   86:   sin_dest.sin_len = sizeof (struct sockaddr_in);
   87: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
   88:   sin_dest.sin_addr = p->u.prefix4;
   89: 
   90:   memset (&sin_mask, 0, sizeof (struct sockaddr_in));
   91: 
   92:   memset (&sin_gate, 0, sizeof (struct sockaddr_in));
   93:   sin_gate.sin_family = AF_INET;
   94: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
   95:   sin_gate.sin_len = sizeof (struct sockaddr_in);
   96: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
   97: 
   98:   /* Make gateway. */
   99:   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
  100:     {
  101:       gate = 0;
  102:       char gate_buf[INET_ADDRSTRLEN] = "NULL";
  103: 
  104:       /*
  105:        * XXX We need to refrain from kernel operations in some cases,
  106:        * but this if statement seems overly cautious - what about
  107:        * other than ADD and DELETE?
  108:        */
  109:       if ((cmd == RTM_ADD
  110: 	   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
  111: 	  || (cmd == RTM_DELETE
  112: 	      && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
  113: 	      ))
  114: 	{
  115: 	  if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
  116: 	    {
  117: 	      if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
  118: 		  nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
  119: 		{
  120: 		  sin_gate.sin_addr = nexthop->rgate.ipv4;
  121: 		  gate = 1;
  122: 		}
  123: 	      if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
  124: 		  || nexthop->rtype == NEXTHOP_TYPE_IFNAME
  125: 		  || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
  126: 		ifindex = nexthop->rifindex;
  127: 	    }
  128: 	  else
  129: 	    {
  130: 	      if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
  131: 		  nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
  132: 		{
  133: 		  sin_gate.sin_addr = nexthop->gate.ipv4;
  134: 		  gate = 1;
  135: 		}
  136: 	      if (nexthop->type == NEXTHOP_TYPE_IFINDEX
  137: 		  || nexthop->type == NEXTHOP_TYPE_IFNAME
  138: 		  || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
  139: 		ifindex = nexthop->ifindex;
  140: 	      if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE)
  141: 		{
  142: 		  struct in_addr loopback;
  143: 		  loopback.s_addr = htonl (INADDR_LOOPBACK);
  144: 		  sin_gate.sin_addr = loopback;
  145: 		  gate = 1;
  146: 		}
  147: 	    }
  148: 
  149: 	  if (gate && p->prefixlen == 32)
  150: 	    mask = NULL;
  151: 	  else
  152: 	    {
  153: 	      masklen2ip (p->prefixlen, &sin_mask.sin_addr);
  154: 	      sin_mask.sin_family = AF_INET;
  155: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  156: 	      sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
  157: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
  158: 	      mask = &sin_mask;
  159: 	    }
  160: 
  161: 	  error = rtm_write (cmd,
  162: 			     (union sockunion *)&sin_dest, 
  163: 			     (union sockunion *)mask, 
  164: 			     gate ? (union sockunion *)&sin_gate : NULL,
  165: 			     ifindex,
  166: 			     rib->flags,
  167: 			     rib->metric);
  168: 
  169:            if (IS_ZEBRA_DEBUG_RIB)
  170:            {
  171:              if (!gate)
  172:              {
  173:                zlog_debug ("%s: %s/%d: attention! gate not found for rib %p",
  174:                  __func__, prefix_buf, p->prefixlen, rib);
  175:                rib_dump (__func__, (struct prefix_ipv4 *)p, rib);
  176:              }
  177:              else
  178:                inet_ntop (AF_INET, &sin_gate.sin_addr, gate_buf, INET_ADDRSTRLEN);
  179:            }
  180:  
  181:            switch (error)
  182:            {
  183:              /* We only flag nexthops as being in FIB if rtm_write() did its work. */
  184:              case ZEBRA_ERR_NOERROR:
  185:                nexthop_num++;
  186:                if (IS_ZEBRA_DEBUG_RIB)
  187:                  zlog_debug ("%s: %s/%d: successfully did NH %s",
  188:                    __func__, prefix_buf, p->prefixlen, gate_buf);
  189:                if (cmd == RTM_ADD)
  190:                  SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
  191:                break;
  192:  
  193:              /* The only valid case for this error is kernel's failure to install
  194:               * a multipath route, which is common for FreeBSD. This should be
  195:               * ignored silently, but logged as an error otherwise.
  196:               */
  197:              case ZEBRA_ERR_RTEXIST:
  198:                if (cmd != RTM_ADD)
  199:                  zlog_err ("%s: rtm_write() returned %d for command %d",
  200:                    __func__, error, cmd);
  201:                continue;
  202:                break;
  203:  
  204:              /* Given that our NEXTHOP_FLAG_FIB matches real kernel FIB, it isn't
  205:               * normal to get any other messages in ANY case.
  206:               */
  207:              case ZEBRA_ERR_RTNOEXIST:
  208:              case ZEBRA_ERR_RTUNREACH:
  209:              default:
  210:                /* This point is reachable regardless of debugging mode. */
  211:                if (!IS_ZEBRA_DEBUG_RIB)
  212:                  inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN);
  213:                zlog_err ("%s: %s/%d: rtm_write() unexpectedly returned %d for command %s",
  214:                  __func__, prefix_buf, p->prefixlen, error, lookup (rtm_type_str, cmd));
  215:                break;
  216:            }
  217:          } /* if (cmd and flags make sense) */
  218:        else
  219:          if (IS_ZEBRA_DEBUG_RIB)
  220:            zlog_debug ("%s: odd command %s for flags %d",
  221:              __func__, lookup (rtm_type_str, cmd), nexthop->flags);
  222:      } /* for (nexthop = ... */
  223:  
  224:    /* If there was no useful nexthop, then complain. */
  225:    if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL)
  226:      zlog_debug ("%s: No useful nexthops were found in RIB entry %p", __func__, rib);
  227: 
  228:   return 0; /*XXX*/
  229: }
  230: 
  231: int
  232: kernel_add_ipv4 (struct prefix *p, struct rib *rib)
  233: {
  234:   int route;
  235: 
  236:   if (zserv_privs.change(ZPRIVS_RAISE))
  237:     zlog (NULL, LOG_ERR, "Can't raise privileges");
  238:   route = kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET);
  239:   if (zserv_privs.change(ZPRIVS_LOWER))
  240:     zlog (NULL, LOG_ERR, "Can't lower privileges");
  241: 
  242:   return route;
  243: }
  244: 
  245: int
  246: kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
  247: {
  248:   int route;
  249: 
  250:   if (zserv_privs.change(ZPRIVS_RAISE))
  251:     zlog (NULL, LOG_ERR, "Can't raise privileges");
  252:   route = kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET);
  253:   if (zserv_privs.change(ZPRIVS_LOWER))
  254:     zlog (NULL, LOG_ERR, "Can't lower privileges");
  255: 
  256:   return route;
  257: }
  258: 
  259: #ifdef HAVE_IPV6
  260: 
  261: /* Calculate sin6_len value for netmask socket value. */
  262: static int
  263: sin6_masklen (struct in6_addr mask)
  264: {
  265:   struct sockaddr_in6 sin6;
  266:   char *p, *lim;
  267:   int len;
  268: 
  269: #if defined (INRIA)
  270:   if (IN_ANYADDR6 (mask)) 
  271:     return sizeof (long);
  272: #else /* ! INRIA */
  273:   if (IN6_IS_ADDR_UNSPECIFIED (&mask)) 
  274:     return sizeof (long);
  275: #endif /* ! INRIA */
  276: 
  277:   sin6.sin6_addr = mask;
  278:   len = sizeof (struct sockaddr_in6);
  279: 
  280:   lim = (char *) & sin6.sin6_addr;
  281:   p = lim + sizeof (sin6.sin6_addr);
  282: 
  283:   while (*--p == 0 && p >= lim) 
  284:     len--;
  285: 
  286:   return len;
  287: }
  288: 
  289: /* Interface between zebra message and rtm message. */
  290: static int
  291: kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest,
  292: 		 struct in6_addr *gate, int index, int flags)
  293: {
  294:   struct sockaddr_in6 *mask;
  295:   struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
  296: 
  297:   memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
  298:   sin_dest.sin6_family = AF_INET6;
  299: #ifdef SIN6_LEN
  300:   sin_dest.sin6_len = sizeof (struct sockaddr_in6);
  301: #endif /* SIN6_LEN */
  302: 
  303:   memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
  304: 
  305:   memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
  306:   sin_gate.sin6_family = AF_INET6;
  307: #ifdef SIN6_LEN
  308:   sin_gate.sin6_len = sizeof (struct sockaddr_in6);
  309: #endif /* SIN6_LEN */
  310: 
  311:   sin_dest.sin6_addr = dest->prefix;
  312: 
  313:   if (gate)
  314:     memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr));
  315: 
  316:   /* Under kame set interface index to link local address. */
  317: #ifdef KAME
  318: 
  319: #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
  320:   do { \
  321:     (a).s6_addr[2] = ((i) >> 8) & 0xff; \
  322:     (a).s6_addr[3] = (i) & 0xff; \
  323:   } while (0)
  324: 
  325:   if (gate && IN6_IS_ADDR_LINKLOCAL(gate))
  326:     SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index);
  327: #endif /* KAME */
  328: 
  329:   if (gate && dest->prefixlen == 128)
  330:     mask = NULL;
  331:   else
  332:     {
  333:       masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
  334:       sin_mask.sin6_family = AF_INET6;
  335: #ifdef SIN6_LEN
  336:       sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
  337: #endif /* SIN6_LEN */
  338:       mask = &sin_mask;
  339:     }
  340: 
  341:   return rtm_write (message, 
  342: 		    (union sockunion *) &sin_dest,
  343: 		    (union sockunion *) mask,
  344: 		    gate ? (union sockunion *)&sin_gate : NULL,
  345: 		    index,
  346: 		    flags,
  347: 		    0);
  348: }
  349: 
  350: /* Interface between zebra message and rtm message. */
  351: static int
  352: kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
  353: 			   int family)
  354: {
  355:   struct sockaddr_in6 *mask;
  356:   struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
  357:   struct nexthop *nexthop;
  358:   int nexthop_num = 0;
  359:   unsigned int ifindex = 0;
  360:   int gate = 0;
  361:   int error;
  362: 
  363:   memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
  364:   sin_dest.sin6_family = AF_INET6;
  365: #ifdef SIN6_LEN
  366:   sin_dest.sin6_len = sizeof (struct sockaddr_in6);
  367: #endif /* SIN6_LEN */
  368:   sin_dest.sin6_addr = p->u.prefix6;
  369: 
  370:   memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
  371: 
  372:   memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
  373:   sin_gate.sin6_family = AF_INET6;
  374: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  375:   sin_gate.sin6_len = sizeof (struct sockaddr_in6);
  376: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
  377: 
  378:   /* Make gateway. */
  379:   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
  380:     {
  381:       gate = 0;
  382: 
  383:       if ((cmd == RTM_ADD
  384: 	   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
  385: 	  || (cmd == RTM_DELETE
  386: #if 0
  387: 	      && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
  388: #endif
  389: 	      ))
  390: 	{
  391: 	  if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
  392: 	    {
  393: 	      if (nexthop->rtype == NEXTHOP_TYPE_IPV6
  394: 		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
  395: 		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
  396: 		{
  397: 		  sin_gate.sin6_addr = nexthop->rgate.ipv6;
  398: 		  gate = 1;
  399: 		}
  400: 	      if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
  401: 		  || nexthop->rtype == NEXTHOP_TYPE_IFNAME
  402: 		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
  403: 		  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
  404: 		ifindex = nexthop->rifindex;
  405: 	    }
  406: 	  else
  407: 	    {
  408: 	      if (nexthop->type == NEXTHOP_TYPE_IPV6
  409: 		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
  410: 		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
  411: 		{
  412: 		  sin_gate.sin6_addr = nexthop->gate.ipv6;
  413: 		  gate = 1;
  414: 		}
  415: 	      if (nexthop->type == NEXTHOP_TYPE_IFINDEX
  416: 		  || nexthop->type == NEXTHOP_TYPE_IFNAME
  417: 		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
  418: 		  || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
  419: 		ifindex = nexthop->ifindex;
  420: 	    }
  421: 
  422: 	  if (cmd == RTM_ADD)
  423: 	    SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
  424: 	}
  425: 
  426:       /* Under kame set interface index to link local address. */
  427: #ifdef KAME
  428: 
  429: #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
  430:       do { \
  431: 	(a).s6_addr[2] = ((i) >> 8) & 0xff; \
  432: 	(a).s6_addr[3] = (i) & 0xff; \
  433:       } while (0)
  434: 
  435:       if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
  436: 	SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
  437: #endif /* KAME */
  438: 
  439:       if (gate && p->prefixlen == 128)
  440: 	mask = NULL;
  441:       else
  442: 	{
  443: 	  masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
  444: 	  sin_mask.sin6_family = AF_INET6;
  445: #ifdef SIN6_LEN
  446: 	  sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
  447: #endif /* SIN6_LEN */
  448: 	  mask = &sin_mask;
  449: 	}
  450: 
  451:       error = rtm_write (cmd,
  452: 			(union sockunion *) &sin_dest,
  453: 			(union sockunion *) mask,
  454: 			gate ? (union sockunion *)&sin_gate : NULL,
  455: 			ifindex,
  456: 			rib->flags,
  457: 			rib->metric);
  458: 
  459: #if 0
  460:       if (error)
  461: 	{
  462: 	  zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
  463: 	    nexthop_num, error);
  464: 	}
  465: #endif
  466: 
  467:       nexthop_num++;
  468:     }
  469: 
  470:   /* If there is no useful nexthop then return. */
  471:   if (nexthop_num == 0)
  472:     {
  473:       if (IS_ZEBRA_DEBUG_KERNEL)
  474: 	zlog_debug ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
  475:       return 0;
  476:     }
  477: 
  478:   return 0; /*XXX*/
  479: }
  480: 
  481: int
  482: kernel_add_ipv6 (struct prefix *p, struct rib *rib)
  483: {
  484:   int route;
  485: 
  486:   if (zserv_privs.change(ZPRIVS_RAISE))
  487:     zlog (NULL, LOG_ERR, "Can't raise privileges");
  488:   route =  kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6);
  489:   if (zserv_privs.change(ZPRIVS_LOWER))
  490:     zlog (NULL, LOG_ERR, "Can't lower privileges");
  491: 
  492:   return route;
  493: }
  494: 
  495: int
  496: kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
  497: {
  498:   int route;
  499: 
  500:   if (zserv_privs.change(ZPRIVS_RAISE))
  501:     zlog (NULL, LOG_ERR, "Can't raise privileges");
  502:   route =  kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6);
  503:   if (zserv_privs.change(ZPRIVS_LOWER))
  504:     zlog (NULL, LOG_ERR, "Can't lower privileges");
  505: 
  506:   return route;
  507: }
  508: 
  509: /* Delete IPv6 route from the kernel. */
  510: int
  511: kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
  512:  		        unsigned int index, int flags, int table)
  513: {
  514:   int route;
  515: 
  516:   if (zserv_privs.change(ZPRIVS_RAISE))
  517:     zlog (NULL, LOG_ERR, "Can't raise privileges");
  518:   route = kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
  519:   if (zserv_privs.change(ZPRIVS_LOWER))
  520:     zlog (NULL, LOG_ERR, "Can't lower privileges");
  521: 
  522:   return route;
  523: }
  524: #endif /* HAVE_IPV6 */

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