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