File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / zebra / zebra_fpm_netlink.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:54:41 2013 UTC (10 years, 11 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, HEAD
0.99.22

    1: /*
    2:  * Code for encoding/decoding FPM messages that are in netlink format.
    3:  *
    4:  * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
    5:  * Copyright (C) 2012 by Open Source Routing.
    6:  * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC")
    7:  *
    8:  * This file is part of GNU Zebra.
    9:  *
   10:  * GNU Zebra is free software; you can redistribute it and/or modify it
   11:  * under the terms of the GNU General Public License as published by the
   12:  * Free Software Foundation; either version 2, or (at your option) any
   13:  * later version.
   14:  *
   15:  * GNU Zebra is distributed in the hope that it will be useful, but
   16:  * WITHOUT ANY WARRANTY; without even the implied warranty of
   17:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   18:  * General Public License for more details.
   19:  *
   20:  * You should have received a copy of the GNU General Public License
   21:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
   22:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   23:  * 02111-1307, USA.
   24:  */
   25: 
   26: #include <zebra.h>
   27: 
   28: #include "log.h"
   29: #include "rib.h"
   30: 
   31: #include "rt_netlink.h"
   32: 
   33: #include "zebra_fpm_private.h"
   34: 
   35: /*
   36:  * addr_to_a
   37:  *
   38:  * Returns string representation of an address of the given AF.
   39:  */
   40: static inline const char *
   41: addr_to_a (u_char af, void *addr)
   42: {
   43:   if (!addr)
   44:     return "<No address>";
   45: 
   46:   switch (af)
   47:     {
   48: 
   49:     case AF_INET:
   50:       return inet_ntoa (*((struct in_addr *) addr));
   51: 
   52: #ifdef HAVE_IPV6
   53:     case AF_INET6:
   54:       return inet6_ntoa (*((struct in6_addr *) addr));
   55: #endif
   56: 
   57:     default:
   58:       return "<Addr in unknown AF>";
   59:     }
   60: }
   61: 
   62: /*
   63:  * prefix_addr_to_a
   64:  *
   65:  * Convience wrapper that returns a human-readable string for the
   66:  * address in a prefix.
   67:  */
   68: static const char *
   69: prefix_addr_to_a (struct prefix *prefix)
   70: {
   71:   if (!prefix)
   72:     return "<No address>";
   73: 
   74:   return addr_to_a (prefix->family, &prefix->u.prefix);
   75: }
   76: 
   77: /*
   78:  * af_addr_size
   79:  *
   80:  * The size of an address in a given address family.
   81:  */
   82: static size_t
   83: af_addr_size (u_char af)
   84: {
   85:   switch (af)
   86:     {
   87: 
   88:     case AF_INET:
   89:       return 4;
   90: 
   91: #ifdef HAVE_IPV6
   92:     case AF_INET6:
   93:       return 16;
   94: #endif
   95: 
   96:     default:
   97:       assert(0);
   98:       return 16;
   99:     }
  100: }
  101: 
  102: /*
  103:  * netlink_nh_info_t
  104:  *
  105:  * Holds information about a single nexthop for netlink. These info
  106:  * structures are transient and may contain pointers into rib
  107:  * data structures for convenience.
  108:  */
  109: typedef struct netlink_nh_info_t_
  110: {
  111:   uint32_t if_index;
  112:   union g_addr *gateway;
  113: 
  114:   /*
  115:    * Information from the struct nexthop from which this nh was
  116:    * derived. For debug purposes only.
  117:    */
  118:   int recursive;
  119:   enum nexthop_types_t type;
  120: } netlink_nh_info_t;
  121: 
  122: /*
  123:  * netlink_route_info_t
  124:  *
  125:  * A structure for holding information for a netlink route message.
  126:  */
  127: typedef struct netlink_route_info_t_
  128: {
  129:   uint16_t nlmsg_type;
  130:   u_char rtm_type;
  131:   uint32_t rtm_table;
  132:   u_char rtm_protocol;
  133:   u_char af;
  134:   struct prefix *prefix;
  135:   uint32_t *metric;
  136:   int num_nhs;
  137: 
  138:   /*
  139:    * Nexthop structures. We keep things simple for now by enforcing a
  140:    * maximum of 64 in case MULTIPATH_NUM is 0;
  141:    */
  142:   netlink_nh_info_t nhs[MAX (MULTIPATH_NUM, 64)];
  143:   union g_addr *pref_src;
  144: } netlink_route_info_t;
  145: 
  146: /*
  147:  * netlink_route_info_add_nh
  148:  *
  149:  * Add information about the given nexthop to the given route info
  150:  * structure.
  151:  *
  152:  * Returns TRUE if a nexthop was added, FALSE otherwise.
  153:  */
  154: static int
  155: netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop)
  156: {
  157:   netlink_nh_info_t nhi;
  158:   union g_addr *src;
  159: 
  160:   memset (&nhi, 0, sizeof (nhi));
  161:   src = NULL;
  162: 
  163:   if (ri->num_nhs >= (int) ZEBRA_NUM_OF (ri->nhs))
  164:     return 0;
  165: 
  166:   if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
  167:     {
  168:       nhi.recursive = 1;
  169:       nhi.type = nexthop->rtype;
  170:       nhi.if_index = nexthop->rifindex;
  171: 
  172:       if (nexthop->rtype == NEXTHOP_TYPE_IPV4
  173: 	  || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
  174: 	{
  175: 	  nhi.gateway = &nexthop->rgate;
  176: 	  if (nexthop->src.ipv4.s_addr)
  177: 	    src = &nexthop->src;
  178: 	}
  179: 
  180: #ifdef HAVE_IPV6
  181:       if (nexthop->rtype == NEXTHOP_TYPE_IPV6
  182: 	  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX
  183: 	  || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME)
  184: 	{
  185: 	  nhi.gateway = &nexthop->rgate;
  186: 	}
  187: #endif /* HAVE_IPV6 */
  188: 
  189:       if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
  190: 	  || nexthop->rtype == NEXTHOP_TYPE_IFNAME)
  191: 	{
  192: 	  if (nexthop->src.ipv4.s_addr)
  193: 	    src = &nexthop->src;
  194: 	}
  195: 
  196:       goto done;
  197:     }
  198: 
  199:   nhi.recursive = 0;
  200:   nhi.type = nexthop->type;
  201:   nhi.if_index = nexthop->ifindex;
  202: 
  203:   if (nexthop->type == NEXTHOP_TYPE_IPV4
  204:       || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
  205:     {
  206:       nhi.gateway = &nexthop->gate;
  207:       if (nexthop->src.ipv4.s_addr)
  208: 	src = &nexthop->src;
  209:     }
  210: 
  211: #ifdef HAVE_IPV6
  212:   if (nexthop->type == NEXTHOP_TYPE_IPV6
  213:       || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
  214:       || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
  215:     {
  216:       nhi.gateway = &nexthop->gate;
  217:     }
  218: #endif /* HAVE_IPV6 */
  219: 
  220:   if (nexthop->type == NEXTHOP_TYPE_IFINDEX
  221:       || nexthop->type == NEXTHOP_TYPE_IFNAME)
  222:     {
  223:       if (nexthop->src.ipv4.s_addr)
  224: 	src = &nexthop->src;
  225:     }
  226: 
  227:   /*
  228:    * Fall through...
  229:    */
  230: 
  231:  done:
  232:   if (!nhi.gateway && nhi.if_index == 0)
  233:     return 0;
  234: 
  235:   /*
  236:    * We have a valid nhi. Copy the structure over to the route_info.
  237:    */
  238:   ri->nhs[ri->num_nhs] = nhi;
  239:   ri->num_nhs++;
  240: 
  241:   if (src && !ri->pref_src)
  242:     ri->pref_src = src;
  243: 
  244:   return 1;
  245: }
  246: 
  247: /*
  248:  * netlink_proto_from_route_type
  249:  */
  250: static u_char
  251: netlink_proto_from_route_type (int type)
  252: {
  253:   switch (type)
  254:     {
  255:     case ZEBRA_ROUTE_KERNEL:
  256:     case ZEBRA_ROUTE_CONNECT:
  257:       return RTPROT_KERNEL;
  258: 
  259:     default:
  260:       return RTPROT_ZEBRA;
  261:     }
  262: }
  263: 
  264: /*
  265:  * netlink_route_info_fill
  266:  *
  267:  * Fill out the route information object from the given route.
  268:  *
  269:  * Returns TRUE on success and FALSE on failure.
  270:  */
  271: static int
  272: netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
  273: 			 rib_dest_t *dest, struct rib *rib)
  274: {
  275:   struct nexthop *nexthop = NULL;
  276:   int discard;
  277: 
  278:   memset (ri, 0, sizeof (*ri));
  279: 
  280:   ri->prefix = rib_dest_prefix (dest);
  281:   ri->af = rib_dest_af (dest);
  282: 
  283:   ri->nlmsg_type = cmd;
  284:   ri->rtm_table = rib_dest_vrf (dest)->id;
  285:   ri->rtm_protocol = RTPROT_UNSPEC;
  286: 
  287:   /*
  288:    * An RTM_DELROUTE need not be accompanied by any nexthops,
  289:    * particularly in our communication with the FPM.
  290:    */
  291:   if (cmd == RTM_DELROUTE && !rib)
  292:     goto skip;
  293: 
  294:   if (rib)
  295:     ri->rtm_protocol = netlink_proto_from_route_type (rib->type);
  296: 
  297:   if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
  298:     discard = 1;
  299:   else
  300:     discard = 0;
  301: 
  302:   if (cmd == RTM_NEWROUTE)
  303:     {
  304:       if (discard)
  305:         {
  306:           if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
  307:             ri->rtm_type = RTN_BLACKHOLE;
  308:           else if (rib->flags & ZEBRA_FLAG_REJECT)
  309:             ri->rtm_type = RTN_UNREACHABLE;
  310:           else
  311:             assert (0);
  312:         }
  313:       else
  314:         ri->rtm_type = RTN_UNICAST;
  315:     }
  316: 
  317:   ri->metric = &rib->metric;
  318: 
  319:   if (discard)
  320:     {
  321:       goto skip;
  322:     }
  323: 
  324:   /* Multipath case. */
  325:   if (rib->nexthop_active_num == 1 || MULTIPATH_NUM == 1)
  326:     {
  327:       for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
  328:         {
  329: 
  330:           if ((cmd == RTM_NEWROUTE
  331:                && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
  332:               || (cmd == RTM_DELROUTE
  333:                   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
  334:             {
  335: 	      netlink_route_info_add_nh (ri, nexthop);
  336:               break;
  337:             }
  338:         }
  339:     }
  340:   else
  341:     {
  342:       for (nexthop = rib->nexthop;
  343:            nexthop && (MULTIPATH_NUM == 0 || ri->num_nhs < MULTIPATH_NUM);
  344:            nexthop = nexthop->next)
  345:         {
  346:           if ((cmd == RTM_NEWROUTE
  347:                && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
  348:               || (cmd == RTM_DELROUTE
  349:                   && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
  350:             {
  351: 	      netlink_route_info_add_nh (ri, nexthop);
  352:             }
  353:         }
  354:     }
  355: 
  356:   /* If there is no useful nexthop then return. */
  357:   if (ri->num_nhs == 0)
  358:     {
  359:       zfpm_debug ("netlink_encode_route(): No useful nexthop.");
  360:       return 0;
  361:     }
  362: 
  363:  skip:
  364:   return 1;
  365: }
  366: 
  367: /*
  368:  * netlink_route_info_encode
  369:  *
  370:  * Returns the number of bytes written to the buffer. 0 or a negative
  371:  * value indicates an error.
  372:  */
  373: static int
  374: netlink_route_info_encode (netlink_route_info_t *ri, char *in_buf,
  375: 			   size_t in_buf_len)
  376: {
  377:   int bytelen;
  378:   int nexthop_num = 0;
  379:   size_t buf_offset;
  380:   netlink_nh_info_t *nhi;
  381: 
  382:   struct
  383:   {
  384:     struct nlmsghdr n;
  385:     struct rtmsg r;
  386:     char buf[1];
  387:   } *req;
  388: 
  389:   req = (void *) in_buf;
  390: 
  391:   buf_offset = ((char *) req->buf) - ((char *) req);
  392: 
  393:   if (in_buf_len < buf_offset) {
  394:     assert(0);
  395:     return 0;
  396:   }
  397: 
  398:   memset (req, 0, buf_offset);
  399: 
  400:   bytelen = af_addr_size (ri->af);
  401: 
  402:   req->n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
  403:   req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
  404:   req->n.nlmsg_type = ri->nlmsg_type;
  405:   req->r.rtm_family = ri->af;
  406:   req->r.rtm_table = ri->rtm_table;
  407:   req->r.rtm_dst_len = ri->prefix->prefixlen;
  408:   req->r.rtm_protocol = ri->rtm_protocol;
  409:   req->r.rtm_scope = RT_SCOPE_UNIVERSE;
  410: 
  411:   addattr_l (&req->n, in_buf_len, RTA_DST, &ri->prefix->u.prefix, bytelen);
  412: 
  413:   req->r.rtm_type = ri->rtm_type;
  414: 
  415:   /* Metric. */
  416:   if (ri->metric)
  417:     addattr32 (&req->n, in_buf_len, RTA_PRIORITY, *ri->metric);
  418: 
  419:   if (ri->num_nhs == 0)
  420:     goto done;
  421: 
  422:   if (ri->num_nhs == 1)
  423:     {
  424:       nhi = &ri->nhs[0];
  425: 
  426:       if (nhi->gateway)
  427: 	{
  428: 	  addattr_l (&req->n, in_buf_len, RTA_GATEWAY, nhi->gateway,
  429: 		     bytelen);
  430: 	}
  431: 
  432:       if (nhi->if_index)
  433: 	{
  434: 	  addattr32 (&req->n, in_buf_len, RTA_OIF, nhi->if_index);
  435: 	}
  436: 
  437:       goto done;
  438: 
  439:     }
  440: 
  441:   /*
  442:    * Multipath case.
  443:    */
  444:   char buf[NL_PKT_BUF_SIZE];
  445:   struct rtattr *rta = (void *) buf;
  446:   struct rtnexthop *rtnh;
  447: 
  448:   rta->rta_type = RTA_MULTIPATH;
  449:   rta->rta_len = RTA_LENGTH (0);
  450:   rtnh = RTA_DATA (rta);
  451: 
  452:   for (nexthop_num = 0; nexthop_num < ri->num_nhs; nexthop_num++)
  453:     {
  454:       nhi = &ri->nhs[nexthop_num];
  455: 
  456:       rtnh->rtnh_len = sizeof (*rtnh);
  457:       rtnh->rtnh_flags = 0;
  458:       rtnh->rtnh_hops = 0;
  459:       rtnh->rtnh_ifindex = 0;
  460:       rta->rta_len += rtnh->rtnh_len;
  461: 
  462:       if (nhi->gateway)
  463: 	{
  464: 	  rta_addattr_l (rta, sizeof (buf), RTA_GATEWAY, nhi->gateway, bytelen);
  465: 	  rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
  466: 	}
  467: 
  468:       if (nhi->if_index)
  469: 	{
  470: 	  rtnh->rtnh_ifindex = nhi->if_index;
  471: 	}
  472: 
  473:       rtnh = RTNH_NEXT (rtnh);
  474:     }
  475: 
  476:   assert (rta->rta_len > RTA_LENGTH (0));
  477:   addattr_l (&req->n, in_buf_len, RTA_MULTIPATH, RTA_DATA (rta),
  478: 	     RTA_PAYLOAD (rta));
  479: 
  480: done:
  481: 
  482:   if (ri->pref_src)
  483:     {
  484:       addattr_l (&req->n, in_buf_len, RTA_PREFSRC, &ri->pref_src, bytelen);
  485:     }
  486: 
  487:   assert (req->n.nlmsg_len < in_buf_len);
  488:   return req->n.nlmsg_len;
  489: }
  490: 
  491: /*
  492:  * zfpm_log_route_info
  493:  *
  494:  * Helper function to log the information in a route_info structure.
  495:  */
  496: static void
  497: zfpm_log_route_info (netlink_route_info_t *ri, const char *label)
  498: {
  499:   netlink_nh_info_t *nhi;
  500:   int i;
  501: 
  502:   zfpm_debug ("%s : %s %s/%d, Proto: %s, Metric: %u", label,
  503: 	      nl_msg_type_to_str (ri->nlmsg_type),
  504: 	      prefix_addr_to_a (ri->prefix), ri->prefix->prefixlen,
  505: 	      nl_rtproto_to_str (ri->rtm_protocol),
  506: 	      ri->metric ? *ri->metric : 0);
  507: 
  508:   for (i = 0; i < ri->num_nhs; i++)
  509:     {
  510:       nhi = &ri->nhs[i];
  511:       zfpm_debug("  Intf: %u, Gateway: %s, Recursive: %s, Type: %s",
  512: 		 nhi->if_index, addr_to_a (ri->af, nhi->gateway),
  513: 		 nhi->recursive ? "yes" : "no",
  514: 		 nexthop_type_to_str (nhi->type));
  515:     }
  516: }
  517: 
  518: /*
  519:  * zfpm_netlink_encode_route
  520:  *
  521:  * Create a netlink message corresponding to the given route in the
  522:  * given buffer space.
  523:  *
  524:  * Returns the number of bytes written to the buffer. 0 or a negative
  525:  * value indicates an error.
  526:  */
  527: int
  528: zfpm_netlink_encode_route (int cmd, rib_dest_t *dest, struct rib *rib,
  529: 			   char *in_buf, size_t in_buf_len)
  530: {
  531:   netlink_route_info_t ri_space, *ri;
  532: 
  533:   ri = &ri_space;
  534: 
  535:   if (!netlink_route_info_fill (ri, cmd, dest, rib))
  536:     return 0;
  537: 
  538:   zfpm_log_route_info (ri, __FUNCTION__);
  539: 
  540:   return netlink_route_info_encode (ri, in_buf, in_buf_len);
  541: }

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