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