LCOV - code coverage report
Current view: top level - zebra - zebra_fpm_netlink.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 152 0.0 %
Date: 2015-11-19 Functions: 0 9 0.0 %

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

Generated by: LCOV version 1.10