Annotation of embedaddon/quagga/bgpd/bgp_mpath.c, revision 1.1

1.1     ! misho       1: /* $QuaggaId: Format:%an, %ai, %h$ $
        !             2:  *
        !             3:  * BGP Multipath
        !             4:  * Copyright (C) 2010 Google Inc.
        !             5:  *
        !             6:  * This file is part of Quagga
        !             7:  *
        !             8:  * Quagga is free software; you can redistribute it and/or modify it
        !             9:  * under the terms of the GNU General Public License as published by the
        !            10:  * Free Software Foundation; either version 2, or (at your option) any
        !            11:  * later version.
        !            12:  *
        !            13:  * Quagga is distributed in the hope that it will be useful, but
        !            14:  * WITHOUT ANY WARRANTY; without even the implied warranty of
        !            15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        !            16:  * General Public License for more details.
        !            17:  *
        !            18:  * You should have received a copy of the GNU General Public License
        !            19:  * along with Quagga; see the file COPYING.  If not, write to the Free
        !            20:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
        !            21:  * 02111-1307, USA.
        !            22:  */
        !            23: 
        !            24: #include <zebra.h>
        !            25: 
        !            26: #include "command.h"
        !            27: #include "prefix.h"
        !            28: #include "linklist.h"
        !            29: #include "sockunion.h"
        !            30: #include "memory.h"
        !            31: 
        !            32: #include "bgpd/bgpd.h"
        !            33: #include "bgpd/bgp_table.h"
        !            34: #include "bgpd/bgp_route.h"
        !            35: #include "bgpd/bgp_attr.h"
        !            36: #include "bgpd/bgp_debug.h"
        !            37: #include "bgpd/bgp_aspath.h"
        !            38: #include "bgpd/bgp_community.h"
        !            39: #include "bgpd/bgp_ecommunity.h"
        !            40: #include "bgpd/bgp_mpath.h"
        !            41: 
        !            42: /*
        !            43:  * bgp_maximum_paths_set
        !            44:  *
        !            45:  * Record maximum-paths configuration for BGP instance
        !            46:  */
        !            47: int
        !            48: bgp_maximum_paths_set (struct bgp *bgp, afi_t afi, safi_t safi,
        !            49:                        int peertype, u_int16_t maxpaths)
        !            50: {
        !            51:   if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
        !            52:     return -1;
        !            53: 
        !            54:   switch (peertype)
        !            55:     {
        !            56:     case BGP_PEER_IBGP:
        !            57:       bgp->maxpaths[afi][safi].maxpaths_ibgp = maxpaths;
        !            58:       break;
        !            59:     case BGP_PEER_EBGP:
        !            60:       bgp->maxpaths[afi][safi].maxpaths_ebgp = maxpaths;
        !            61:       break;
        !            62:     default:
        !            63:       return -1;
        !            64:     }
        !            65: 
        !            66:   return 0;
        !            67: }
        !            68: 
        !            69: /*
        !            70:  * bgp_maximum_paths_unset
        !            71:  *
        !            72:  * Remove maximum-paths configuration from BGP instance
        !            73:  */
        !            74: int
        !            75: bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi,
        !            76:                          int peertype)
        !            77: {
        !            78:   if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
        !            79:     return -1;
        !            80: 
        !            81:   switch (peertype)
        !            82:     {
        !            83:     case BGP_PEER_IBGP:
        !            84:       bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS;
        !            85:       break;
        !            86:     case BGP_PEER_EBGP:
        !            87:       bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS;
        !            88:       break;
        !            89:     default:
        !            90:       return -1;
        !            91:     }
        !            92: 
        !            93:   return 0;
        !            94: }
        !            95: 
        !            96: /*
        !            97:  * bgp_info_nexthop_cmp
        !            98:  *
        !            99:  * Compare the nexthops of two paths. Return value is less than, equal to,
        !           100:  * or greater than zero if bi1 is respectively less than, equal to,
        !           101:  * or greater than bi2.
        !           102:  */
        !           103: static int
        !           104: bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2)
        !           105: {
        !           106:   struct attr_extra *ae1, *ae2;
        !           107:   int compare;
        !           108: 
        !           109:   ae1 = bi1->attr->extra;
        !           110:   ae2 = bi2->attr->extra;
        !           111: 
        !           112:   compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop);
        !           113: 
        !           114:   if (!compare && ae1 && ae2 && (ae1->mp_nexthop_len == ae2->mp_nexthop_len))
        !           115:     {
        !           116:       switch (ae1->mp_nexthop_len)
        !           117:         {
        !           118:         case 4:
        !           119:         case 12:
        !           120:           compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in,
        !           121:                                    &ae2->mp_nexthop_global_in);
        !           122:           break;
        !           123: #ifdef HAVE_IPV6
        !           124:         case 16:
        !           125:           compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
        !           126:                                    &ae2->mp_nexthop_global);
        !           127:           break;
        !           128:         case 32:
        !           129:           compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
        !           130:                                    &ae2->mp_nexthop_global);
        !           131:           if (!compare)
        !           132:             compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local,
        !           133:                                      &ae2->mp_nexthop_local);
        !           134:           break;
        !           135: #endif /* HAVE_IPV6 */
        !           136:         }
        !           137:     }
        !           138: 
        !           139:   return compare;
        !           140: }
        !           141: 
        !           142: /*
        !           143:  * bgp_info_mpath_cmp
        !           144:  *
        !           145:  * This function determines our multipath list ordering. By ordering
        !           146:  * the list we can deterministically select which paths are included
        !           147:  * in the multipath set. The ordering also helps in detecting changes
        !           148:  * in the multipath selection so we can detect whether to send an
        !           149:  * update to zebra.
        !           150:  *
        !           151:  * The order of paths is determined first by received nexthop, and then
        !           152:  * by peer address if the nexthops are the same.
        !           153:  */
        !           154: static int
        !           155: bgp_info_mpath_cmp (void *val1, void *val2)
        !           156: {
        !           157:   struct bgp_info *bi1, *bi2;
        !           158:   int compare;
        !           159: 
        !           160:   bi1 = val1;
        !           161:   bi2 = val2;
        !           162: 
        !           163:   compare = bgp_info_nexthop_cmp (bi1, bi2);
        !           164: 
        !           165:   if (!compare)
        !           166:     compare = sockunion_cmp (bi1->peer->su_remote, bi2->peer->su_remote);
        !           167: 
        !           168:   return compare;
        !           169: }
        !           170: 
        !           171: /*
        !           172:  * bgp_mp_list_init
        !           173:  *
        !           174:  * Initialize the mp_list, which holds the list of multipaths
        !           175:  * selected by bgp_best_selection
        !           176:  */
        !           177: void
        !           178: bgp_mp_list_init (struct list *mp_list)
        !           179: {
        !           180:   assert (mp_list);
        !           181:   memset (mp_list, 0, sizeof (struct list));
        !           182:   mp_list->cmp = bgp_info_mpath_cmp;
        !           183: }
        !           184: 
        !           185: /*
        !           186:  * bgp_mp_list_clear
        !           187:  *
        !           188:  * Clears all entries out of the mp_list
        !           189:  */
        !           190: void
        !           191: bgp_mp_list_clear (struct list *mp_list)
        !           192: {
        !           193:   assert (mp_list);
        !           194:   list_delete_all_node (mp_list);
        !           195: }
        !           196: 
        !           197: /*
        !           198:  * bgp_mp_list_add
        !           199:  *
        !           200:  * Adds a multipath entry to the mp_list
        !           201:  */
        !           202: void
        !           203: bgp_mp_list_add (struct list *mp_list, struct bgp_info *mpinfo)
        !           204: {
        !           205:   assert (mp_list && mpinfo);
        !           206:   listnode_add_sort (mp_list, mpinfo);
        !           207: }
        !           208: 
        !           209: /*
        !           210:  * bgp_info_mpath_new
        !           211:  *
        !           212:  * Allocate and zero memory for a new bgp_info_mpath element
        !           213:  */
        !           214: static struct bgp_info_mpath *
        !           215: bgp_info_mpath_new (void)
        !           216: {
        !           217:   struct bgp_info_mpath *new_mpath;
        !           218:   new_mpath = XCALLOC (MTYPE_BGP_MPATH_INFO, sizeof (struct bgp_info_mpath));
        !           219:   return new_mpath;
        !           220: }
        !           221: 
        !           222: /*
        !           223:  * bgp_info_mpath_free
        !           224:  *
        !           225:  * Release resources for a bgp_info_mpath element and zero out pointer
        !           226:  */
        !           227: void
        !           228: bgp_info_mpath_free (struct bgp_info_mpath **mpath)
        !           229: {
        !           230:   if (mpath && *mpath)
        !           231:     {
        !           232:       if ((*mpath)->mp_attr)
        !           233:         bgp_attr_unintern (&(*mpath)->mp_attr);
        !           234:       XFREE (MTYPE_BGP_MPATH_INFO, *mpath);
        !           235:       *mpath = NULL;
        !           236:     }
        !           237: }
        !           238: 
        !           239: /*
        !           240:  * bgp_info_mpath_get
        !           241:  *
        !           242:  * Fetch the mpath element for the given bgp_info. Used for
        !           243:  * doing lazy allocation.
        !           244:  */
        !           245: static struct bgp_info_mpath *
        !           246: bgp_info_mpath_get (struct bgp_info *binfo)
        !           247: {
        !           248:   struct bgp_info_mpath *mpath;
        !           249:   if (!binfo->mpath)
        !           250:     {
        !           251:       mpath = bgp_info_mpath_new();
        !           252:       if (!mpath)
        !           253:         return NULL;
        !           254:       binfo->mpath = mpath;
        !           255:       mpath->mp_info = binfo;
        !           256:     }
        !           257:   return binfo->mpath;
        !           258: }
        !           259: 
        !           260: /*
        !           261:  * bgp_info_mpath_enqueue
        !           262:  *
        !           263:  * Enqueue a path onto the multipath list given the previous multipath
        !           264:  * list entry
        !           265:  */
        !           266: static void
        !           267: bgp_info_mpath_enqueue (struct bgp_info *prev_info, struct bgp_info *binfo)
        !           268: {
        !           269:   struct bgp_info_mpath *prev, *mpath;
        !           270: 
        !           271:   prev = bgp_info_mpath_get (prev_info);
        !           272:   mpath = bgp_info_mpath_get (binfo);
        !           273:   if (!prev || !mpath)
        !           274:     return;
        !           275: 
        !           276:   mpath->mp_next = prev->mp_next;
        !           277:   mpath->mp_prev = prev;
        !           278:   if (prev->mp_next)
        !           279:     prev->mp_next->mp_prev = mpath;
        !           280:   prev->mp_next = mpath;
        !           281: 
        !           282:   SET_FLAG (binfo->flags, BGP_INFO_MULTIPATH);
        !           283: }
        !           284: 
        !           285: /*
        !           286:  * bgp_info_mpath_dequeue
        !           287:  *
        !           288:  * Remove a path from the multipath list
        !           289:  */
        !           290: void
        !           291: bgp_info_mpath_dequeue (struct bgp_info *binfo)
        !           292: {
        !           293:   struct bgp_info_mpath *mpath = binfo->mpath;
        !           294:   if (!mpath)
        !           295:     return;
        !           296:   if (mpath->mp_prev)
        !           297:     mpath->mp_prev->mp_next = mpath->mp_next;
        !           298:   if (mpath->mp_next)
        !           299:     mpath->mp_next->mp_prev = mpath->mp_prev;
        !           300:   mpath->mp_next = mpath->mp_prev = NULL;
        !           301:   UNSET_FLAG (binfo->flags, BGP_INFO_MULTIPATH);
        !           302: }
        !           303: 
        !           304: /*
        !           305:  * bgp_info_mpath_next
        !           306:  *
        !           307:  * Given a bgp_info, return the next multipath entry
        !           308:  */
        !           309: struct bgp_info *
        !           310: bgp_info_mpath_next (struct bgp_info *binfo)
        !           311: {
        !           312:   if (!binfo->mpath || !binfo->mpath->mp_next)
        !           313:     return NULL;
        !           314:   return binfo->mpath->mp_next->mp_info;
        !           315: }
        !           316: 
        !           317: /*
        !           318:  * bgp_info_mpath_first
        !           319:  *
        !           320:  * Given bestpath bgp_info, return the first multipath entry.
        !           321:  */
        !           322: struct bgp_info *
        !           323: bgp_info_mpath_first (struct bgp_info *binfo)
        !           324: {
        !           325:   return bgp_info_mpath_next (binfo);
        !           326: }
        !           327: 
        !           328: /*
        !           329:  * bgp_info_mpath_count
        !           330:  *
        !           331:  * Given the bestpath bgp_info, return the number of multipath entries
        !           332:  */
        !           333: u_int32_t
        !           334: bgp_info_mpath_count (struct bgp_info *binfo)
        !           335: {
        !           336:   if (!binfo->mpath)
        !           337:     return 0;
        !           338:   return binfo->mpath->mp_count;
        !           339: }
        !           340: 
        !           341: /*
        !           342:  * bgp_info_mpath_count_set
        !           343:  *
        !           344:  * Sets the count of multipaths into bestpath's mpath element
        !           345:  */
        !           346: static void
        !           347: bgp_info_mpath_count_set (struct bgp_info *binfo, u_int32_t count)
        !           348: {
        !           349:   struct bgp_info_mpath *mpath;
        !           350:   if (!count && !binfo->mpath)
        !           351:     return;
        !           352:   mpath = bgp_info_mpath_get (binfo);
        !           353:   if (!mpath)
        !           354:     return;
        !           355:   mpath->mp_count = count;
        !           356: }
        !           357: 
        !           358: /*
        !           359:  * bgp_info_mpath_attr
        !           360:  *
        !           361:  * Given bestpath bgp_info, return aggregated attribute set used
        !           362:  * for advertising the multipath route
        !           363:  */
        !           364: struct attr *
        !           365: bgp_info_mpath_attr (struct bgp_info *binfo)
        !           366: {
        !           367:   if (!binfo->mpath)
        !           368:     return NULL;
        !           369:   return binfo->mpath->mp_attr;
        !           370: }
        !           371: 
        !           372: /*
        !           373:  * bgp_info_mpath_attr_set
        !           374:  *
        !           375:  * Sets the aggregated attribute into bestpath's mpath element
        !           376:  */
        !           377: static void
        !           378: bgp_info_mpath_attr_set (struct bgp_info *binfo, struct attr *attr)
        !           379: {
        !           380:   struct bgp_info_mpath *mpath;
        !           381:   if (!attr && !binfo->mpath)
        !           382:     return;
        !           383:   mpath = bgp_info_mpath_get (binfo);
        !           384:   if (!mpath)
        !           385:     return;
        !           386:   mpath->mp_attr = attr;
        !           387: }
        !           388: 
        !           389: /*
        !           390:  * bgp_info_mpath_update
        !           391:  *
        !           392:  * Compare and sync up the multipath list with the mp_list generated by
        !           393:  * bgp_best_selection
        !           394:  */
        !           395: void
        !           396: bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best,
        !           397:                        struct bgp_info *old_best, struct list *mp_list,
        !           398:                        struct bgp_maxpaths_cfg *mpath_cfg)
        !           399: {
        !           400:   u_int16_t maxpaths, mpath_count, old_mpath_count;
        !           401:   struct listnode *mp_node, *mp_next_node;
        !           402:   struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
        !           403:   int mpath_changed, debug;
        !           404:   char pfx_buf[INET_ADDRSTRLEN], nh_buf[2][INET_ADDRSTRLEN];
        !           405: 
        !           406:   mpath_changed = 0;
        !           407:   maxpaths = BGP_DEFAULT_MAXPATHS;
        !           408:   mpath_count = 0;
        !           409:   cur_mpath = NULL;
        !           410:   old_mpath_count = 0;
        !           411:   prev_mpath = new_best;
        !           412:   mp_node = listhead (mp_list);
        !           413:   debug = BGP_DEBUG (events, EVENTS);
        !           414: 
        !           415:   if (debug)
        !           416:     prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf));
        !           417: 
        !           418:   if (new_best)
        !           419:     {
        !           420:       mpath_count++;
        !           421:       if (new_best != old_best)
        !           422:         bgp_info_mpath_dequeue (new_best);
        !           423:       maxpaths = (peer_sort (new_best->peer) == BGP_PEER_IBGP) ?
        !           424:         mpath_cfg->maxpaths_ibgp : mpath_cfg->maxpaths_ebgp;
        !           425:     }
        !           426: 
        !           427:   if (old_best)
        !           428:     {
        !           429:       cur_mpath = bgp_info_mpath_first (old_best);
        !           430:       old_mpath_count = bgp_info_mpath_count (old_best);
        !           431:       bgp_info_mpath_count_set (old_best, 0);
        !           432:       bgp_info_mpath_dequeue (old_best);
        !           433:     }
        !           434: 
        !           435:   /*
        !           436:    * We perform an ordered walk through both lists in parallel.
        !           437:    * The reason for the ordered walk is that if there are paths
        !           438:    * that were previously multipaths and are still multipaths, the walk
        !           439:    * should encounter them in both lists at the same time. Otherwise
        !           440:    * there will be paths that are in one list or another, and we
        !           441:    * will deal with these separately.
        !           442:    *
        !           443:    * Note that new_best might be somewhere in the mp_list, so we need
        !           444:    * to skip over it
        !           445:    */
        !           446:   while (mp_node || cur_mpath)
        !           447:     {
        !           448:       /*
        !           449:        * We can bail out of this loop if all existing paths on the
        !           450:        * multipath list have been visited (for cleanup purposes) and
        !           451:        * the maxpath requirement is fulfulled
        !           452:        */
        !           453:       if (!cur_mpath && (mpath_count >= maxpaths))
        !           454:         break;
        !           455: 
        !           456:       mp_next_node = mp_node ? listnextnode (mp_node) : NULL;
        !           457:       next_mpath = cur_mpath ? bgp_info_mpath_next (cur_mpath) : NULL;
        !           458: 
        !           459:       /*
        !           460:        * If equal, the path was a multipath and is still a multipath.
        !           461:        * Insert onto new multipath list if maxpaths allows.
        !           462:        */
        !           463:       if (mp_node && (listgetdata (mp_node) == cur_mpath))
        !           464:         {
        !           465:           list_delete_node (mp_list, mp_node);
        !           466:           bgp_info_mpath_dequeue (cur_mpath);
        !           467:           if ((mpath_count < maxpaths) &&
        !           468:               bgp_info_nexthop_cmp (prev_mpath, cur_mpath))
        !           469:             {
        !           470:               bgp_info_mpath_enqueue (prev_mpath, cur_mpath);
        !           471:               prev_mpath = cur_mpath;
        !           472:               mpath_count++;
        !           473:             }
        !           474:           else
        !           475:             {
        !           476:               mpath_changed = 1;
        !           477:               if (debug)
        !           478:                 zlog_debug ("%s remove mpath nexthop %s peer %s", pfx_buf,
        !           479:                             inet_ntop (AF_INET, &cur_mpath->attr->nexthop,
        !           480:                                        nh_buf[0], sizeof (nh_buf[0])),
        !           481:                             sockunion2str (cur_mpath->peer->su_remote,
        !           482:                                            nh_buf[1], sizeof (nh_buf[1])));
        !           483:             }
        !           484:           mp_node = mp_next_node;
        !           485:           cur_mpath = next_mpath;
        !           486:           continue;
        !           487:         }
        !           488: 
        !           489:       if (cur_mpath && (!mp_node ||
        !           490:                         (bgp_info_mpath_cmp (cur_mpath,
        !           491:                                              listgetdata (mp_node)) < 0)))
        !           492:         {
        !           493:           /*
        !           494:            * If here, we have an old multipath and either the mp_list
        !           495:            * is finished or the next mp_node points to a later
        !           496:            * multipath, so we need to purge this path from the
        !           497:            * multipath list
        !           498:            */
        !           499:           bgp_info_mpath_dequeue (cur_mpath);
        !           500:           mpath_changed = 1;
        !           501:           if (debug)
        !           502:             zlog_debug ("%s remove mpath nexthop %s peer %s", pfx_buf,
        !           503:                         inet_ntop (AF_INET, &cur_mpath->attr->nexthop,
        !           504:                                    nh_buf[0], sizeof (nh_buf[0])),
        !           505:                         sockunion2str (cur_mpath->peer->su_remote,
        !           506:                                        nh_buf[1], sizeof (nh_buf[1])));
        !           507:           cur_mpath = next_mpath;
        !           508:         }
        !           509:       else
        !           510:         {
        !           511:           /*
        !           512:            * If here, we have a path on the mp_list that was not previously
        !           513:            * a multipath (due to non-equivalance or maxpaths exceeded),
        !           514:            * or the matching multipath is sorted later in the multipath
        !           515:            * list. Before we enqueue the path on the new multipath list,
        !           516:            * make sure its not on the old_best multipath list or referenced
        !           517:            * via next_mpath:
        !           518:            * - If next_mpath points to this new path, update next_mpath to
        !           519:            *   point to the multipath after this one
        !           520:            * - Dequeue the path from the multipath list just to make sure
        !           521:            */
        !           522:           new_mpath = listgetdata (mp_node);
        !           523:           list_delete_node (mp_list, mp_node);
        !           524:           if ((mpath_count < maxpaths) && (new_mpath != new_best) &&
        !           525:               bgp_info_nexthop_cmp (prev_mpath, new_mpath))
        !           526:             {
        !           527:               if (new_mpath == next_mpath)
        !           528:                 next_mpath = bgp_info_mpath_next (new_mpath);
        !           529:               bgp_info_mpath_dequeue (new_mpath);
        !           530: 
        !           531:               bgp_info_mpath_enqueue (prev_mpath, new_mpath);
        !           532:               prev_mpath = new_mpath;
        !           533:               mpath_changed = 1;
        !           534:               mpath_count++;
        !           535:               if (debug)
        !           536:                 zlog_debug ("%s add mpath nexthop %s peer %s", pfx_buf,
        !           537:                             inet_ntop (AF_INET, &new_mpath->attr->nexthop,
        !           538:                                        nh_buf[0], sizeof (nh_buf[0])),
        !           539:                             sockunion2str (new_mpath->peer->su_remote,
        !           540:                                            nh_buf[1], sizeof (nh_buf[1])));
        !           541:             }
        !           542:           mp_node = mp_next_node;
        !           543:         }
        !           544:     }
        !           545: 
        !           546:   if (new_best)
        !           547:     {
        !           548:       bgp_info_mpath_count_set (new_best, mpath_count-1);
        !           549:       if (mpath_changed || (bgp_info_mpath_count (new_best) != old_mpath_count))
        !           550:         SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG);
        !           551:     }
        !           552: }
        !           553: 
        !           554: /*
        !           555:  * bgp_mp_dmed_deselect
        !           556:  *
        !           557:  * Clean up multipath information for BGP_INFO_DMED_SELECTED path that
        !           558:  * is not selected as best path
        !           559:  */
        !           560: void
        !           561: bgp_mp_dmed_deselect (struct bgp_info *dmed_best)
        !           562: {
        !           563:   struct bgp_info *mpinfo, *mpnext;
        !           564: 
        !           565:   if (!dmed_best)
        !           566:     return;
        !           567: 
        !           568:   for (mpinfo = bgp_info_mpath_first (dmed_best); mpinfo; mpinfo = mpnext)
        !           569:     {
        !           570:       mpnext = bgp_info_mpath_next (mpinfo);
        !           571:       bgp_info_mpath_dequeue (mpinfo);
        !           572:     }
        !           573: 
        !           574:   bgp_info_mpath_count_set (dmed_best, 0);
        !           575:   UNSET_FLAG (dmed_best->flags, BGP_INFO_MULTIPATH_CHG);
        !           576:   assert (bgp_info_mpath_first (dmed_best) == 0);
        !           577: }
        !           578: 
        !           579: /*
        !           580:  * bgp_info_mpath_aggregate_update
        !           581:  *
        !           582:  * Set the multipath aggregate attribute. We need to see if the
        !           583:  * aggregate has changed and then set the ATTR_CHANGED flag on the
        !           584:  * bestpath info so that a peer update will be generated. The
        !           585:  * change is detected by generating the current attribute,
        !           586:  * interning it, and then comparing the interned pointer with the
        !           587:  * current value. We can skip this generate/compare step if there
        !           588:  * is no change in multipath selection and no attribute change in
        !           589:  * any multipath.
        !           590:  */
        !           591: void
        !           592: bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
        !           593:                                  struct bgp_info *old_best)
        !           594: {
        !           595:   struct bgp_info *mpinfo;
        !           596:   struct aspath *aspath;
        !           597:   struct aspath *asmerge;
        !           598:   struct attr *new_attr, *old_attr;
        !           599:   u_char origin, attr_chg;
        !           600:   struct community *community, *commerge;
        !           601:   struct ecommunity *ecomm, *ecommerge;
        !           602:   struct attr_extra *ae;
        !           603:   struct attr attr = { 0 };
        !           604: 
        !           605:   if (old_best && (old_best != new_best) &&
        !           606:       (old_attr = bgp_info_mpath_attr (old_best)))
        !           607:     {
        !           608:       bgp_attr_unintern (&old_attr);
        !           609:       bgp_info_mpath_attr_set (old_best, NULL);
        !           610:     }
        !           611: 
        !           612:   if (!new_best)
        !           613:     return;
        !           614: 
        !           615:   if (!bgp_info_mpath_count (new_best))
        !           616:     {
        !           617:       if ((new_attr = bgp_info_mpath_attr (new_best)))
        !           618:         {
        !           619:           bgp_attr_unintern (&new_attr);
        !           620:           bgp_info_mpath_attr_set (new_best, NULL);
        !           621:           SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
        !           622:         }
        !           623:       return;
        !           624:     }
        !           625: 
        !           626:   /*
        !           627:    * Bail out here if the following is true:
        !           628:    * - MULTIPATH_CHG bit is not set on new_best, and
        !           629:    * - No change in bestpath, and
        !           630:    * - ATTR_CHANGED bit is not set on new_best or any of the multipaths
        !           631:    */
        !           632:   if (!CHECK_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG) &&
        !           633:       (old_best == new_best))
        !           634:     {
        !           635:       attr_chg = 0;
        !           636: 
        !           637:       if (CHECK_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED))
        !           638:         attr_chg = 1;
        !           639:       else
        !           640:         for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
        !           641:              mpinfo = bgp_info_mpath_next (mpinfo))
        !           642:           {
        !           643:             if (CHECK_FLAG (mpinfo->flags, BGP_INFO_ATTR_CHANGED))
        !           644:               {
        !           645:                 attr_chg = 1;
        !           646:                 break;
        !           647:               }
        !           648:           }
        !           649: 
        !           650:       if (!attr_chg)
        !           651:         {
        !           652:           assert (bgp_info_mpath_attr (new_best));
        !           653:           return;
        !           654:         }
        !           655:     }
        !           656: 
        !           657:   bgp_attr_dup (&attr, new_best->attr);
        !           658: 
        !           659:   /* aggregate attribute from multipath constituents */
        !           660:   aspath = aspath_dup (attr.aspath);
        !           661:   origin = attr.origin;
        !           662:   community = attr.community ? community_dup (attr.community) : NULL;
        !           663:   ae = attr.extra;
        !           664:   ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL;
        !           665: 
        !           666:   for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
        !           667:        mpinfo = bgp_info_mpath_next (mpinfo))
        !           668:     {
        !           669:       asmerge = aspath_aggregate (aspath, mpinfo->attr->aspath);
        !           670:       aspath_free (aspath);
        !           671:       aspath = asmerge;
        !           672: 
        !           673:       if (origin < mpinfo->attr->origin)
        !           674:         origin = mpinfo->attr->origin;
        !           675: 
        !           676:       if (mpinfo->attr->community)
        !           677:         {
        !           678:           if (community)
        !           679:             {
        !           680:               commerge = community_merge (community, mpinfo->attr->community);
        !           681:               community = community_uniq_sort (commerge);
        !           682:               community_free (commerge);
        !           683:             }
        !           684:           else
        !           685:             community = community_dup (mpinfo->attr->community);
        !           686:         }
        !           687: 
        !           688:       ae = mpinfo->attr->extra;
        !           689:       if (ae && ae->ecommunity)
        !           690:         {
        !           691:           if (ecomm)
        !           692:             {
        !           693:               ecommerge = ecommunity_merge (ecomm, ae->ecommunity);
        !           694:               ecomm = ecommunity_uniq_sort (ecommerge);
        !           695:               ecommunity_free (&ecommerge);
        !           696:             }
        !           697:           else
        !           698:             ecomm = ecommunity_dup (ae->ecommunity);
        !           699:         }
        !           700:     }
        !           701: 
        !           702:   attr.aspath = aspath;
        !           703:   attr.origin = origin;
        !           704:   if (community)
        !           705:     {
        !           706:       attr.community = community;
        !           707:       attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
        !           708:     }
        !           709:   if (ecomm)
        !           710:     {
        !           711:       ae = bgp_attr_extra_get (&attr);
        !           712:       ae->ecommunity = ecomm;
        !           713:       attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
        !           714:     }
        !           715: 
        !           716:   /* Zap multipath attr nexthop so we set nexthop to self */
        !           717:   attr.nexthop.s_addr = 0;
        !           718: #ifdef HAVE_IPV6
        !           719:   if (attr.extra)
        !           720:     memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr));
        !           721: #endif /* HAVE_IPV6 */
        !           722: 
        !           723:   /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */
        !           724: 
        !           725:   new_attr = bgp_attr_intern (&attr);
        !           726:   bgp_attr_extra_free (&attr);
        !           727: 
        !           728:   if (new_attr != bgp_info_mpath_attr (new_best))
        !           729:     {
        !           730:       if ((old_attr = bgp_info_mpath_attr (new_best)))
        !           731:         bgp_attr_unintern (&old_attr);
        !           732:       bgp_info_mpath_attr_set (new_best, new_attr);
        !           733:       SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
        !           734:     }
        !           735:   else
        !           736:     bgp_attr_unintern (&new_attr);
        !           737: }

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