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

    1: /* $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 = (new_best->peer->sort == 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>