Annotation of embedaddon/quagga/zebra/zebra_fpm_netlink.c, revision 1.1.1.2

1.1       misho       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:   /*
1.1.1.2 ! misho     139:    * Nexthop structures
1.1       misho     140:    */
1.1.1.2 ! misho     141:   netlink_nh_info_t nhs[MULTIPATH_NUM];
1.1       misho     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
1.1.1.2 ! misho     154: netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop,
        !           155:                           int recursive)
1.1       misho     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: 
1.1.1.2 ! misho     166:   nhi.recursive = recursive;
1.1       misho     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: {
1.1.1.2 ! misho     237:   struct nexthop *nexthop, *tnexthop;
        !           238:   int recursing;
1.1       misho     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;
1.1.1.2 ! misho     247:   ri->rtm_table = rib_dest_vrf (dest)->vrf_id;
1.1       misho     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: 
1.1.1.2 ! misho     287:   for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
1.1       misho     288:     {
1.1.1.2 ! misho     289:       if (ri->num_nhs >= MULTIPATH_NUM)
        !           290:         break;
1.1       misho     291: 
1.1.1.2 ! misho     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)))
1.1       misho     299:         {
1.1.1.2 ! misho     300:           netlink_route_info_add_nh (ri, nexthop, recursing);
1.1       misho     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>