File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / zebra / zebra_fpm_netlink.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:10 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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
  140:    */
  141:   netlink_nh_info_t nhs[MULTIPATH_NUM];
  142:   union g_addr *pref_src;
  143: } netlink_route_info_t;
  144: 
  145: /*
  146:  * netlink_route_info_add_nh
  147:  *
  148:  * Add information about the given nexthop to the given route info
  149:  * structure.
  150:  *
  151:  * Returns TRUE if a nexthop was added, FALSE otherwise.
  152:  */
  153: static int
  154: netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop,
  155: 			   int recursive)
  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:   nhi.recursive = recursive;
  167:   nhi.type = nexthop->type;
  168:   nhi.if_index = nexthop->ifindex;
  169: 
  170:   if (nexthop->type == NEXTHOP_TYPE_IPV4
  171:       || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
  172:     {
  173:       nhi.gateway = &nexthop->gate;
  174:       if (nexthop->src.ipv4.s_addr)
  175: 	src = &nexthop->src;
  176:     }
  177: 
  178: #ifdef HAVE_IPV6
  179:   if (nexthop->type == NEXTHOP_TYPE_IPV6
  180:       || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
  181:       || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
  182:     {
  183:       nhi.gateway = &nexthop->gate;
  184:     }
  185: #endif /* HAVE_IPV6 */
  186: 
  187:   if (nexthop->type == NEXTHOP_TYPE_IFINDEX
  188:       || nexthop->type == NEXTHOP_TYPE_IFNAME)
  189:     {
  190:       if (nexthop->src.ipv4.s_addr)
  191: 	src = &nexthop->src;
  192:     }
  193: 
  194:   if (!nhi.gateway && nhi.if_index == 0)
  195:     return 0;
  196: 
  197:   /*
  198:    * We have a valid nhi. Copy the structure over to the route_info.
  199:    */
  200:   ri->nhs[ri->num_nhs] = nhi;
  201:   ri->num_nhs++;
  202: 
  203:   if (src && !ri->pref_src)
  204:     ri->pref_src = src;
  205: 
  206:   return 1;
  207: }
  208: 
  209: /*
  210:  * netlink_proto_from_route_type
  211:  */
  212: static u_char
  213: netlink_proto_from_route_type (int type)
  214: {
  215:   switch (type)
  216:     {
  217:     case ZEBRA_ROUTE_KERNEL:
  218:     case ZEBRA_ROUTE_CONNECT:
  219:       return RTPROT_KERNEL;
  220: 
  221:     default:
  222:       return RTPROT_ZEBRA;
  223:     }
  224: }
  225: 
  226: /*
  227:  * netlink_route_info_fill
  228:  *
  229:  * Fill out the route information object from the given route.
  230:  *
  231:  * Returns TRUE on success and FALSE on failure.
  232:  */
  233: static int
  234: netlink_route_info_fill (netlink_route_info_t *ri, int cmd,
  235: 			 rib_dest_t *dest, struct rib *rib)
  236: {
  237:   struct nexthop *nexthop, *tnexthop;
  238:   int recursing;
  239:   int discard;
  240: 
  241:   memset (ri, 0, sizeof (*ri));
  242: 
  243:   ri->prefix = rib_dest_prefix (dest);
  244:   ri->af = rib_dest_af (dest);
  245: 
  246:   ri->nlmsg_type = cmd;
  247:   ri->rtm_table = rib_dest_vrf (dest)->vrf_id;
  248:   ri->rtm_protocol = RTPROT_UNSPEC;
  249: 
  250:   /*
  251:    * An RTM_DELROUTE need not be accompanied by any nexthops,
  252:    * particularly in our communication with the FPM.
  253:    */
  254:   if (cmd == RTM_DELROUTE && !rib)
  255:     goto skip;
  256: 
  257:   if (rib)
  258:     ri->rtm_protocol = netlink_proto_from_route_type (rib->type);
  259: 
  260:   if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
  261:     discard = 1;
  262:   else
  263:     discard = 0;
  264: 
  265:   if (cmd == RTM_NEWROUTE)
  266:     {
  267:       if (discard)
  268:         {
  269:           if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
  270:             ri->rtm_type = RTN_BLACKHOLE;
  271:           else if (rib->flags & ZEBRA_FLAG_REJECT)
  272:             ri->rtm_type = RTN_UNREACHABLE;
  273:           else
  274:             assert (0);
  275:         }
  276:       else
  277:         ri->rtm_type = RTN_UNICAST;
  278:     }
  279: 
  280:   ri->metric = &rib->metric;
  281: 
  282:   if (discard)
  283:     {
  284:       goto skip;
  285:     }
  286: 
  287:   for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
  288:     {
  289:       if (ri->num_nhs >= MULTIPATH_NUM)
  290:         break;
  291: 
  292:       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
  293:         continue;
  294: 
  295:       if ((cmd == RTM_NEWROUTE
  296:            && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
  297:           || (cmd == RTM_DELROUTE
  298:               && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
  299:         {
  300:           netlink_route_info_add_nh (ri, nexthop, recursing);
  301:         }
  302:     }
  303: 
  304:   /* If there is no useful nexthop then return. */
  305:   if (ri->num_nhs == 0)
  306:     {
  307:       zfpm_debug ("netlink_encode_route(): No useful nexthop.");
  308:       return 0;
  309:     }
  310: 
  311:  skip:
  312:   return 1;
  313: }
  314: 
  315: /*
  316:  * netlink_route_info_encode
  317:  *
  318:  * Returns the number of bytes written to the buffer. 0 or a negative
  319:  * value indicates an error.
  320:  */
  321: static int
  322: netlink_route_info_encode (netlink_route_info_t *ri, char *in_buf,
  323: 			   size_t in_buf_len)
  324: {
  325:   int bytelen;
  326:   int nexthop_num = 0;
  327:   size_t buf_offset;
  328:   netlink_nh_info_t *nhi;
  329: 
  330:   struct
  331:   {
  332:     struct nlmsghdr n;
  333:     struct rtmsg r;
  334:     char buf[1];
  335:   } *req;
  336: 
  337:   req = (void *) in_buf;
  338: 
  339:   buf_offset = ((char *) req->buf) - ((char *) req);
  340: 
  341:   if (in_buf_len < buf_offset) {
  342:     assert(0);
  343:     return 0;
  344:   }
  345: 
  346:   memset (req, 0, buf_offset);
  347: 
  348:   bytelen = af_addr_size (ri->af);
  349: 
  350:   req->n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
  351:   req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
  352:   req->n.nlmsg_type = ri->nlmsg_type;
  353:   req->r.rtm_family = ri->af;
  354:   req->r.rtm_table = ri->rtm_table;
  355:   req->r.rtm_dst_len = ri->prefix->prefixlen;
  356:   req->r.rtm_protocol = ri->rtm_protocol;
  357:   req->r.rtm_scope = RT_SCOPE_UNIVERSE;
  358: 
  359:   addattr_l (&req->n, in_buf_len, RTA_DST, &ri->prefix->u.prefix, bytelen);
  360: 
  361:   req->r.rtm_type = ri->rtm_type;
  362: 
  363:   /* Metric. */
  364:   if (ri->metric)
  365:     addattr32 (&req->n, in_buf_len, RTA_PRIORITY, *ri->metric);
  366: 
  367:   if (ri->num_nhs == 0)
  368:     goto done;
  369: 
  370:   if (ri->num_nhs == 1)
  371:     {
  372:       nhi = &ri->nhs[0];
  373: 
  374:       if (nhi->gateway)
  375: 	{
  376: 	  addattr_l (&req->n, in_buf_len, RTA_GATEWAY, nhi->gateway,
  377: 		     bytelen);
  378: 	}
  379: 
  380:       if (nhi->if_index)
  381: 	{
  382: 	  addattr32 (&req->n, in_buf_len, RTA_OIF, nhi->if_index);
  383: 	}
  384: 
  385:       goto done;
  386: 
  387:     }
  388: 
  389:   /*
  390:    * Multipath case.
  391:    */
  392:   char buf[NL_PKT_BUF_SIZE];
  393:   struct rtattr *rta = (void *) buf;
  394:   struct rtnexthop *rtnh;
  395: 
  396:   rta->rta_type = RTA_MULTIPATH;
  397:   rta->rta_len = RTA_LENGTH (0);
  398:   rtnh = RTA_DATA (rta);
  399: 
  400:   for (nexthop_num = 0; nexthop_num < ri->num_nhs; nexthop_num++)
  401:     {
  402:       nhi = &ri->nhs[nexthop_num];
  403: 
  404:       rtnh->rtnh_len = sizeof (*rtnh);
  405:       rtnh->rtnh_flags = 0;
  406:       rtnh->rtnh_hops = 0;
  407:       rtnh->rtnh_ifindex = 0;
  408:       rta->rta_len += rtnh->rtnh_len;
  409: 
  410:       if (nhi->gateway)
  411: 	{
  412: 	  rta_addattr_l (rta, sizeof (buf), RTA_GATEWAY, nhi->gateway, bytelen);
  413: 	  rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
  414: 	}
  415: 
  416:       if (nhi->if_index)
  417: 	{
  418: 	  rtnh->rtnh_ifindex = nhi->if_index;
  419: 	}
  420: 
  421:       rtnh = RTNH_NEXT (rtnh);
  422:     }
  423: 
  424:   assert (rta->rta_len > RTA_LENGTH (0));
  425:   addattr_l (&req->n, in_buf_len, RTA_MULTIPATH, RTA_DATA (rta),
  426: 	     RTA_PAYLOAD (rta));
  427: 
  428: done:
  429: 
  430:   if (ri->pref_src)
  431:     {
  432:       addattr_l (&req->n, in_buf_len, RTA_PREFSRC, &ri->pref_src, bytelen);
  433:     }
  434: 
  435:   assert (req->n.nlmsg_len < in_buf_len);
  436:   return req->n.nlmsg_len;
  437: }
  438: 
  439: /*
  440:  * zfpm_log_route_info
  441:  *
  442:  * Helper function to log the information in a route_info structure.
  443:  */
  444: static void
  445: zfpm_log_route_info (netlink_route_info_t *ri, const char *label)
  446: {
  447:   netlink_nh_info_t *nhi;
  448:   int i;
  449: 
  450:   zfpm_debug ("%s : %s %s/%d, Proto: %s, Metric: %u", label,
  451: 	      nl_msg_type_to_str (ri->nlmsg_type),
  452: 	      prefix_addr_to_a (ri->prefix), ri->prefix->prefixlen,
  453: 	      nl_rtproto_to_str (ri->rtm_protocol),
  454: 	      ri->metric ? *ri->metric : 0);
  455: 
  456:   for (i = 0; i < ri->num_nhs; i++)
  457:     {
  458:       nhi = &ri->nhs[i];
  459:       zfpm_debug("  Intf: %u, Gateway: %s, Recursive: %s, Type: %s",
  460: 		 nhi->if_index, addr_to_a (ri->af, nhi->gateway),
  461: 		 nhi->recursive ? "yes" : "no",
  462: 		 nexthop_type_to_str (nhi->type));
  463:     }
  464: }
  465: 
  466: /*
  467:  * zfpm_netlink_encode_route
  468:  *
  469:  * Create a netlink message corresponding to the given route in the
  470:  * given buffer space.
  471:  *
  472:  * Returns the number of bytes written to the buffer. 0 or a negative
  473:  * value indicates an error.
  474:  */
  475: int
  476: zfpm_netlink_encode_route (int cmd, rib_dest_t *dest, struct rib *rib,
  477: 			   char *in_buf, size_t in_buf_len)
  478: {
  479:   netlink_route_info_t ri_space, *ri;
  480: 
  481:   ri = &ri_space;
  482: 
  483:   if (!netlink_route_info_fill (ri, cmd, dest, rib))
  484:     return 0;
  485: 
  486:   zfpm_log_route_info (ri, __FUNCTION__);
  487: 
  488:   return netlink_route_info_encode (ri, in_buf, in_buf_len);
  489: }

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