blob: 73b93cebb46f11cddc0c1d6fb627e374eafa4987 [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"
Donald Sharp04907292016-01-07 10:03:01 -050031#include "filter.h"
Josh Bailey165b5ff2011-07-20 20:43:22 -070032
33#include "bgpd/bgpd.h"
Josh Bailey96450fa2011-07-20 20:45:12 -070034#include "bgpd/bgp_table.h"
35#include "bgpd/bgp_route.h"
36#include "bgpd/bgp_attr.h"
Josh Baileyde8d5df2011-07-20 20:46:01 -070037#include "bgpd/bgp_debug.h"
Josh Bailey0b597ef2011-07-20 20:49:11 -070038#include "bgpd/bgp_aspath.h"
39#include "bgpd/bgp_community.h"
40#include "bgpd/bgp_ecommunity.h"
Josh Bailey165b5ff2011-07-20 20:43:22 -070041#include "bgpd/bgp_mpath.h"
42
Paul Jakma6d4742b2015-11-25 17:14:37 +000043bool
44bgp_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
63bool
64bgp_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
Josh Bailey165b5ff2011-07-20 20:43:22 -070070/*
71 * bgp_maximum_paths_set
72 *
73 * Record maximum-paths configuration for BGP instance
74 */
75int
76bgp_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 */
102int
103bgp_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}
Josh Bailey96450fa2011-07-20 20:45:12 -0700123
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 */
131static int
132bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2)
133{
134 struct attr_extra *ae1, *ae2;
135 int compare;
136
Josh Bailey0b597ef2011-07-20 20:49:11 -0700137 ae1 = bi1->attr->extra;
138 ae2 = bi2->attr->extra;
Josh Bailey96450fa2011-07-20 20:45:12 -0700139
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;
Josh Bailey96450fa2011-07-20 20:45:12 -0700151 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;
Josh Bailey96450fa2011-07-20 20:45:12 -0700162 }
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 */
180static int
181bgp_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 */
203void
204bgp_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 */
216void
217bgp_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 */
228void
229bgp_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}
Josh Baileyde8d5df2011-07-20 20:46:01 -0700234
235/*
236 * bgp_info_mpath_new
237 *
238 * Allocate and zero memory for a new bgp_info_mpath element
239 */
240static struct bgp_info_mpath *
241bgp_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 */
253void
254bgp_info_mpath_free (struct bgp_info_mpath **mpath)
255{
256 if (mpath && *mpath)
257 {
Josh Bailey0b597ef2011-07-20 20:49:11 -0700258 if ((*mpath)->mp_attr)
David Lamparterfac3c242012-04-28 22:37:20 +0200259 bgp_attr_unintern (&(*mpath)->mp_attr);
Josh Baileyde8d5df2011-07-20 20:46:01 -0700260 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 */
271static struct bgp_info_mpath *
272bgp_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 */
292static void
293bgp_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 */
316void
317bgp_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 */
335struct bgp_info *
336bgp_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 */
348struct bgp_info *
349bgp_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 */
359u_int32_t
360bgp_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 */
372static void
373bgp_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/*
Josh Bailey0b597ef2011-07-20 20:49:11 -0700385 * bgp_info_mpath_attr
386 *
387 * Given bestpath bgp_info, return aggregated attribute set used
388 * for advertising the multipath route
389 */
390struct attr *
391bgp_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 */
403static void
404bgp_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/*
Josh Baileyde8d5df2011-07-20 20:46:01 -0700416 * bgp_info_mpath_update
417 *
418 * Compare and sync up the multipath list with the mp_list generated by
419 * bgp_best_selection
420 */
421void
422bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best,
423 struct bgp_info *old_best, struct list *mp_list,
Paul Jakma6d4742b2015-11-25 17:14:37 +0000424 afi_t afi, safi_t safi)
Josh Baileyde8d5df2011-07-20 20:46:01 -0700425{
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
432 mpath_changed = 0;
433 maxpaths = BGP_DEFAULT_MAXPATHS;
434 mpath_count = 0;
435 cur_mpath = NULL;
436 old_mpath_count = 0;
437 prev_mpath = new_best;
438 mp_node = listhead (mp_list);
Paul Jakma6d4742b2015-11-25 17:14:37 +0000439 struct bgp_maxpaths_cfg *mpath_cfg;
Josh Baileyde8d5df2011-07-20 20:46:01 -0700440 debug = BGP_DEBUG (events, EVENTS);
441
Paul Jakma6d4742b2015-11-25 17:14:37 +0000442 mpath_cfg = &new_best->peer->bgp->maxpaths[afi][safi];
443
Josh Baileyde8d5df2011-07-20 20:46:01 -0700444 if (debug)
445 prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf));
446
447 if (new_best)
448 {
449 mpath_count++;
450 if (new_best != old_best)
451 bgp_info_mpath_dequeue (new_best);
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000452 maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ?
Josh Baileyde8d5df2011-07-20 20:46:01 -0700453 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);
Josh Baileyde8d5df2011-07-20 20:46:01 -0700553 if ((mpath_count < maxpaths) && (new_mpath != new_best) &&
554 bgp_info_nexthop_cmp (prev_mpath, new_mpath))
555 {
Josh Bailey78d92e12011-07-20 20:51:07 -0700556 if (new_mpath == next_mpath)
557 next_mpath = bgp_info_mpath_next (new_mpath);
558 bgp_info_mpath_dequeue (new_mpath);
559
Josh Baileyde8d5df2011-07-20 20:46:01 -0700560 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}
Josh Bailey6918e742011-07-20 20:48:20 -0700582
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 */
589void
590bgp_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}
Josh Bailey0b597ef2011-07-20 20:49:11 -0700607
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 */
620void
621bgp_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 {
David Lamparterfac3c242012-04-28 22:37:20 +0200637 bgp_attr_unintern (&old_attr);
Josh Bailey0b597ef2011-07-20 20:49:11 -0700638 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 {
David Lamparterfac3c242012-04-28 22:37:20 +0200648 bgp_attr_unintern (&new_attr);
Josh Bailey0b597ef2011-07-20 20:49:11 -0700649 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
Josh Bailey01d7ff02011-07-20 20:52:06 -0700658 * - No change in bestpath, and
Josh Bailey0b597ef2011-07-20 20:49:11 -0700659 * - ATTR_CHANGED bit is not set on new_best or any of the multipaths
660 */
Josh Bailey01d7ff02011-07-20 20:52:06 -0700661 if (!CHECK_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG) &&
662 (old_best == new_best))
Josh Bailey0b597ef2011-07-20 20:49:11 -0700663 {
Josh Bailey01d7ff02011-07-20 20:52:06 -0700664 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 }
Josh Bailey0b597ef2011-07-20 20:49:11 -0700684 }
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);
David Lamparterfac3c242012-04-28 22:37:20 +0200724 ecommunity_free (&ecommerge);
Josh Bailey0b597ef2011-07-20 20:49:11 -0700725 }
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;
Josh Bailey0b597ef2011-07-20 20:49:11 -0700747 if (attr.extra)
748 memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr));
Josh Bailey0b597ef2011-07-20 20:49:11 -0700749
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)))
David Lamparterfac3c242012-04-28 22:37:20 +0200758 bgp_attr_unintern (&old_attr);
Josh Bailey0b597ef2011-07-20 20:49:11 -0700759 bgp_info_mpath_attr_set (new_best, new_attr);
760 SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
761 }
762 else
David Lamparterfac3c242012-04-28 22:37:20 +0200763 bgp_attr_unintern (&new_attr);
Josh Bailey0b597ef2011-07-20 20:49:11 -0700764}