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

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

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