blob: 7999d16b6636b5c100d0de4e09e2f607e8d222a6 [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
42/*
43 * bgp_maximum_paths_set
44 *
45 * Record maximum-paths configuration for BGP instance
46 */
47int
48bgp_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 */
74int
75bgp_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}
Josh Bailey96450fa2011-07-20 20:45:12 -070095
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 */
103static int
104bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2)
105{
106 struct attr_extra *ae1, *ae2;
107 int compare;
108
Josh Bailey0b597ef2011-07-20 20:49:11 -0700109 ae1 = bi1->attr->extra;
110 ae2 = bi2->attr->extra;
Josh Bailey96450fa2011-07-20 20:45:12 -0700111
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 */
154static int
155bgp_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 */
177void
178bgp_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 */
190void
191bgp_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 */
202void
203bgp_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}
Josh Baileyde8d5df2011-07-20 20:46:01 -0700208
209/*
210 * bgp_info_mpath_new
211 *
212 * Allocate and zero memory for a new bgp_info_mpath element
213 */
214static struct bgp_info_mpath *
215bgp_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 */
227void
228bgp_info_mpath_free (struct bgp_info_mpath **mpath)
229{
230 if (mpath && *mpath)
231 {
Josh Bailey0b597ef2011-07-20 20:49:11 -0700232 if ((*mpath)->mp_attr)
David Lamparterfac3c242012-04-28 22:37:20 +0200233 bgp_attr_unintern (&(*mpath)->mp_attr);
Josh Baileyde8d5df2011-07-20 20:46:01 -0700234 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 */
245static struct bgp_info_mpath *
246bgp_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 */
266static void
267bgp_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 */
290void
291bgp_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 */
309struct bgp_info *
310bgp_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 */
322struct bgp_info *
323bgp_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 */
333u_int32_t
334bgp_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 */
346static void
347bgp_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/*
Josh Bailey0b597ef2011-07-20 20:49:11 -0700359 * bgp_info_mpath_attr
360 *
361 * Given bestpath bgp_info, return aggregated attribute set used
362 * for advertising the multipath route
363 */
364struct attr *
365bgp_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 */
377static void
378bgp_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/*
Josh Baileyde8d5df2011-07-20 20:46:01 -0700390 * bgp_info_mpath_update
391 *
392 * Compare and sync up the multipath list with the mp_list generated by
393 * bgp_best_selection
394 */
395void
396bgp_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);
Jorge Boncompte [DTI2]6d85b152012-05-07 16:52:54 +0000423 maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ?
Josh Baileyde8d5df2011-07-20 20:46:01 -0700424 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);
Josh Baileyde8d5df2011-07-20 20:46:01 -0700524 if ((mpath_count < maxpaths) && (new_mpath != new_best) &&
525 bgp_info_nexthop_cmp (prev_mpath, new_mpath))
526 {
Josh Bailey78d92e12011-07-20 20:51:07 -0700527 if (new_mpath == next_mpath)
528 next_mpath = bgp_info_mpath_next (new_mpath);
529 bgp_info_mpath_dequeue (new_mpath);
530
Josh Baileyde8d5df2011-07-20 20:46:01 -0700531 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}
Josh Bailey6918e742011-07-20 20:48:20 -0700553
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 */
560void
561bgp_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}
Josh Bailey0b597ef2011-07-20 20:49:11 -0700578
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 */
591void
592bgp_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 {
David Lamparterfac3c242012-04-28 22:37:20 +0200608 bgp_attr_unintern (&old_attr);
Josh Bailey0b597ef2011-07-20 20:49:11 -0700609 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 {
David Lamparterfac3c242012-04-28 22:37:20 +0200619 bgp_attr_unintern (&new_attr);
Josh Bailey0b597ef2011-07-20 20:49:11 -0700620 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
Josh Bailey01d7ff02011-07-20 20:52:06 -0700629 * - No change in bestpath, and
Josh Bailey0b597ef2011-07-20 20:49:11 -0700630 * - ATTR_CHANGED bit is not set on new_best or any of the multipaths
631 */
Josh Bailey01d7ff02011-07-20 20:52:06 -0700632 if (!CHECK_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG) &&
633 (old_best == new_best))
Josh Bailey0b597ef2011-07-20 20:49:11 -0700634 {
Josh Bailey01d7ff02011-07-20 20:52:06 -0700635 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 }
Josh Bailey0b597ef2011-07-20 20:49:11 -0700655 }
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);
David Lamparterfac3c242012-04-28 22:37:20 +0200695 ecommunity_free (&ecommerge);
Josh Bailey0b597ef2011-07-20 20:49:11 -0700696 }
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)))
David Lamparterfac3c242012-04-28 22:37:20 +0200731 bgp_attr_unintern (&old_attr);
Josh Bailey0b597ef2011-07-20 20:49:11 -0700732 bgp_info_mpath_attr_set (new_best, new_attr);
733 SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
734 }
735 else
David Lamparterfac3c242012-04-28 22:37:20 +0200736 bgp_attr_unintern (&new_attr);
Josh Bailey0b597ef2011-07-20 20:49:11 -0700737}