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

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"
1.1.1.3 ! misho      31: #include "filter.h"
1.1       misho      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: 
1.1.1.3 ! misho      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: 
1.1       misho      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,
1.1.1.3 ! misho     424:                         afi_t afi, safi_t safi)
1.1       misho     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];
1.1.1.3 ! misho     431:   struct bgp_maxpaths_cfg *mpath_cfg = NULL;
1.1       misho     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);
1.1.1.3 ! misho     440: 
1.1       misho     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:     {
1.1.1.3 ! misho     448:       mpath_cfg = &new_best->peer->bgp->maxpaths[afi][safi];
1.1       misho     449:       mpath_count++;
                    450:       if (new_best != old_best)
                    451:         bgp_info_mpath_dequeue (new_best);
1.1.1.2   misho     452:       maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ?
1.1       misho     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>