]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_mpath.c
*: add indent control files
[mirror_frr.git] / bgpd / bgp_mpath.c
CommitLineData
8ef0791c 1/*
165b5fff
JB
2 * BGP Multipath
3 * Copyright (C) 2010 Google Inc.
4 *
5 * This file is part of Quagga
6 *
7 * Quagga is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * Quagga is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
896014f4
DL
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
165b5fff
JB
20 */
21
22#include <zebra.h>
23
24#include "command.h"
96450faf
JB
25#include "prefix.h"
26#include "linklist.h"
27#include "sockunion.h"
de8d5dff 28#include "memory.h"
3f9c7369 29#include "queue.h"
039f3a34 30#include "filter.h"
165b5fff
JB
31
32#include "bgpd/bgpd.h"
96450faf
JB
33#include "bgpd/bgp_table.h"
34#include "bgpd/bgp_route.h"
35#include "bgpd/bgp_attr.h"
de8d5dff 36#include "bgpd/bgp_debug.h"
0b597ef0
JB
37#include "bgpd/bgp_aspath.h"
38#include "bgpd/bgp_community.h"
39#include "bgpd/bgp_ecommunity.h"
57d187bc 40#include "bgpd/bgp_lcommunity.h"
165b5fff
JB
41#include "bgpd/bgp_mpath.h"
42
43/*
44 * bgp_maximum_paths_set
45 *
46 * Record maximum-paths configuration for BGP instance
47 */
48int
49bgp_maximum_paths_set (struct bgp *bgp, afi_t afi, safi_t safi,
5e242b0d 50 int peertype, u_int16_t maxpaths, u_int16_t options)
165b5fff
JB
51{
52 if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
53 return -1;
54
55 switch (peertype)
56 {
57 case BGP_PEER_IBGP:
58 bgp->maxpaths[afi][safi].maxpaths_ibgp = maxpaths;
5e242b0d 59 bgp->maxpaths[afi][safi].ibgp_flags |= options;
165b5fff
JB
60 break;
61 case BGP_PEER_EBGP:
62 bgp->maxpaths[afi][safi].maxpaths_ebgp = maxpaths;
63 break;
64 default:
65 return -1;
66 }
67
68 return 0;
69}
70
71/*
72 * bgp_maximum_paths_unset
73 *
74 * Remove maximum-paths configuration from BGP instance
75 */
76int
77bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi,
78 int peertype)
79{
80 if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
81 return -1;
82
83 switch (peertype)
84 {
85 case BGP_PEER_IBGP:
37fe7731 86 bgp->maxpaths[afi][safi].maxpaths_ibgp = multipath_num;
5e242b0d 87 bgp->maxpaths[afi][safi].ibgp_flags = 0;
165b5fff
JB
88 break;
89 case BGP_PEER_EBGP:
37fe7731 90 bgp->maxpaths[afi][safi].maxpaths_ebgp = multipath_num;
165b5fff
JB
91 break;
92 default:
93 return -1;
94 }
95
96 return 0;
97}
96450faf
JB
98
99/*
100 * bgp_info_nexthop_cmp
101 *
102 * Compare the nexthops of two paths. Return value is less than, equal to,
103 * or greater than zero if bi1 is respectively less than, equal to,
104 * or greater than bi2.
105 */
7dc9d4e4 106int
96450faf
JB
107bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2)
108{
96450faf
JB
109 int compare;
110
96450faf 111 compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop);
aadc0905 112 if (!compare)
96450faf 113 {
aadc0905 114 if (bi1->attr->mp_nexthop_len == bi2->attr->mp_nexthop_len)
96450faf 115 {
aadc0905 116 switch (bi1->attr->mp_nexthop_len)
e328382f 117 {
801a9bcc
DS
118 case BGP_ATTR_NHLEN_IPV4:
119 case BGP_ATTR_NHLEN_VPNV4:
aadc0905
DS
120 compare = IPV4_ADDR_CMP (&bi1->attr->mp_nexthop_global_in,
121 &bi2->attr->mp_nexthop_global_in);
e328382f 122 break;
801a9bcc 123 case BGP_ATTR_NHLEN_IPV6_GLOBAL:
af37568a 124 case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
aadc0905
DS
125 compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global,
126 &bi2->attr->mp_nexthop_global);
e328382f 127 break;
801a9bcc 128 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
aadc0905
DS
129 compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global,
130 &bi2->attr->mp_nexthop_global);
e328382f 131 if (!compare)
aadc0905
DS
132 compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_local,
133 &bi2->attr->mp_nexthop_local);
e328382f 134 break;
e328382f
DS
135 }
136 }
137
e328382f
DS
138 /* This can happen if one IPv6 peer sends you global and link-local
139 * nexthops but another IPv6 peer only sends you global
140 */
aadc0905
DS
141 else if (bi1->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
142 bi1->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
e328382f 143 {
aadc0905
DS
144 compare = IPV6_ADDR_CMP (&bi1->attr->mp_nexthop_global,
145 &bi2->attr->mp_nexthop_global);
96450faf 146 if (!compare)
e328382f 147 {
aadc0905 148 if (bi1->attr->mp_nexthop_len < bi2->attr->mp_nexthop_len)
e328382f
DS
149 compare = -1;
150 else
151 compare = 1;
152 }
96450faf
JB
153 }
154 }
155
156 return compare;
157}
158
159/*
160 * bgp_info_mpath_cmp
161 *
162 * This function determines our multipath list ordering. By ordering
163 * the list we can deterministically select which paths are included
164 * in the multipath set. The ordering also helps in detecting changes
165 * in the multipath selection so we can detect whether to send an
166 * update to zebra.
167 *
168 * The order of paths is determined first by received nexthop, and then
169 * by peer address if the nexthops are the same.
170 */
171static int
172bgp_info_mpath_cmp (void *val1, void *val2)
173{
174 struct bgp_info *bi1, *bi2;
175 int compare;
176
177 bi1 = val1;
178 bi2 = val2;
179
180 compare = bgp_info_nexthop_cmp (bi1, bi2);
181
182 if (!compare)
a3cb01d8 183 {
184 if (!bi1->peer->su_remote && !bi2->peer->su_remote)
185 compare = 0;
186 else if (!bi1->peer->su_remote)
187 compare = 1;
188 else if (!bi2->peer->su_remote)
189 compare = -1;
190 else
191 compare = sockunion_cmp (bi1->peer->su_remote, bi2->peer->su_remote);
192 }
96450faf
JB
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}
de8d5dff
JB
234
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 {
0b597ef0 258 if ((*mpath)->mp_attr)
fac3c245 259 bgp_attr_unintern (&(*mpath)->mp_attr);
de8d5dff
JB
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 */
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
0b597ef0
JB
384/*
385 * 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
de8d5dff
JB
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 */
421void
422bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best,
423 struct bgp_info *old_best, struct list *mp_list,
424 struct bgp_maxpaths_cfg *mpath_cfg)
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;
4690c7d7 430 char pfx_buf[PREFIX2STR_BUFFER], nh_buf[2][INET6_ADDRSTRLEN];
2ec1e66f 431 char path_buf[PATH_ADDPATH_STR_BUFFER];
de8d5dff
JB
432
433 mpath_changed = 0;
37fe7731 434 maxpaths = multipath_num;
de8d5dff
JB
435 mpath_count = 0;
436 cur_mpath = NULL;
437 old_mpath_count = 0;
438 prev_mpath = new_best;
439 mp_node = listhead (mp_list);
9fbdd100 440 debug = bgp_debug_bestpath(&rn->p);
de8d5dff
JB
441
442 if (debug)
443 prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf));
444
445 if (new_best)
446 {
447 mpath_count++;
448 if (new_best != old_best)
449 bgp_info_mpath_dequeue (new_best);
6d85b15b 450 maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ?
de8d5dff
JB
451 mpath_cfg->maxpaths_ibgp : mpath_cfg->maxpaths_ebgp;
452 }
453
454 if (old_best)
455 {
456 cur_mpath = bgp_info_mpath_first (old_best);
457 old_mpath_count = bgp_info_mpath_count (old_best);
458 bgp_info_mpath_count_set (old_best, 0);
459 bgp_info_mpath_dequeue (old_best);
460 }
461
a6086ad4 462 if (debug)
463 zlog_debug("%s: starting mpath update, newbest %s num candidates %d old-mpath-count %d",
464 pfx_buf, new_best ? new_best->peer->host : "NONE",
465 listcount (mp_list), old_mpath_count);
466
de8d5dff
JB
467 /*
468 * We perform an ordered walk through both lists in parallel.
469 * The reason for the ordered walk is that if there are paths
470 * that were previously multipaths and are still multipaths, the walk
471 * should encounter them in both lists at the same time. Otherwise
472 * there will be paths that are in one list or another, and we
473 * will deal with these separately.
474 *
475 * Note that new_best might be somewhere in the mp_list, so we need
476 * to skip over it
477 */
478 while (mp_node || cur_mpath)
479 {
a6086ad4 480 struct bgp_info *tmp_info;
481
de8d5dff
JB
482 /*
483 * We can bail out of this loop if all existing paths on the
484 * multipath list have been visited (for cleanup purposes) and
485 * the maxpath requirement is fulfulled
486 */
487 if (!cur_mpath && (mpath_count >= maxpaths))
488 break;
489
490 mp_next_node = mp_node ? listnextnode (mp_node) : NULL;
491 next_mpath = cur_mpath ? bgp_info_mpath_next (cur_mpath) : NULL;
a6086ad4 492 tmp_info = mp_node ? listgetdata (mp_node) : NULL;
493
494 if (debug)
495 zlog_debug("%s: comparing candidate %s with existing mpath %s",
496 pfx_buf, tmp_info ? tmp_info->peer->host : "NONE",
497 cur_mpath ? cur_mpath->peer->host : "NONE");
de8d5dff
JB
498
499 /*
500 * If equal, the path was a multipath and is still a multipath.
501 * Insert onto new multipath list if maxpaths allows.
502 */
503 if (mp_node && (listgetdata (mp_node) == cur_mpath))
504 {
505 list_delete_node (mp_list, mp_node);
506 bgp_info_mpath_dequeue (cur_mpath);
507 if ((mpath_count < maxpaths) &&
508 bgp_info_nexthop_cmp (prev_mpath, cur_mpath))
509 {
510 bgp_info_mpath_enqueue (prev_mpath, cur_mpath);
511 prev_mpath = cur_mpath;
512 mpath_count++;
a6086ad4 513 if (debug)
514 {
515 bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf);
516 zlog_debug("%s: %s is still multipath, cur count %d",
517 pfx_buf, path_buf, mpath_count);
518 }
de8d5dff
JB
519 }
520 else
521 {
522 mpath_changed = 1;
523 if (debug)
2ec1e66f
DW
524 {
525 bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf);
a6086ad4 526 zlog_debug ("%s: remove mpath %s nexthop %s, cur count %d",
527 pfx_buf, path_buf,
2ec1e66f
DW
528 inet_ntop (AF_INET, &cur_mpath->attr->nexthop,
529 nh_buf[0], sizeof (nh_buf[0])),
a6086ad4 530 mpath_count);
2ec1e66f 531 }
de8d5dff
JB
532 }
533 mp_node = mp_next_node;
534 cur_mpath = next_mpath;
535 continue;
536 }
537
538 if (cur_mpath && (!mp_node ||
539 (bgp_info_mpath_cmp (cur_mpath,
540 listgetdata (mp_node)) < 0)))
541 {
542 /*
543 * If here, we have an old multipath and either the mp_list
544 * is finished or the next mp_node points to a later
545 * multipath, so we need to purge this path from the
546 * multipath list
547 */
548 bgp_info_mpath_dequeue (cur_mpath);
549 mpath_changed = 1;
550 if (debug)
2ec1e66f
DW
551 {
552 bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf);
a6086ad4 553 zlog_debug ("%s: remove mpath %s nexthop %s, cur count %d",
554 pfx_buf, path_buf,
2ec1e66f
DW
555 inet_ntop (AF_INET, &cur_mpath->attr->nexthop,
556 nh_buf[0], sizeof (nh_buf[0])),
a6086ad4 557 mpath_count);
2ec1e66f 558 }
de8d5dff
JB
559 cur_mpath = next_mpath;
560 }
561 else
562 {
563 /*
564 * If here, we have a path on the mp_list that was not previously
565 * a multipath (due to non-equivalance or maxpaths exceeded),
566 * or the matching multipath is sorted later in the multipath
567 * list. Before we enqueue the path on the new multipath list,
568 * make sure its not on the old_best multipath list or referenced
569 * via next_mpath:
570 * - If next_mpath points to this new path, update next_mpath to
571 * point to the multipath after this one
572 * - Dequeue the path from the multipath list just to make sure
573 */
574 new_mpath = listgetdata (mp_node);
575 list_delete_node (mp_list, mp_node);
de8d5dff
JB
576 if ((mpath_count < maxpaths) && (new_mpath != new_best) &&
577 bgp_info_nexthop_cmp (prev_mpath, new_mpath))
578 {
78d92e17 579 if (new_mpath == next_mpath)
18f1dc06 580 bgp_info_mpath_next (new_mpath);
78d92e17
JB
581 bgp_info_mpath_dequeue (new_mpath);
582
de8d5dff
JB
583 bgp_info_mpath_enqueue (prev_mpath, new_mpath);
584 prev_mpath = new_mpath;
585 mpath_changed = 1;
586 mpath_count++;
587 if (debug)
2ec1e66f
DW
588 {
589 bgp_info_path_with_addpath_rx_str(new_mpath, path_buf);
a6086ad4 590 zlog_debug ("%s: add mpath %s nexthop %s, cur count %d",
591 pfx_buf, path_buf,
2ec1e66f
DW
592 inet_ntop (AF_INET, &new_mpath->attr->nexthop,
593 nh_buf[0], sizeof (nh_buf[0])),
a6086ad4 594 mpath_count);
2ec1e66f 595 }
de8d5dff
JB
596 }
597 mp_node = mp_next_node;
598 }
599 }
600
601 if (new_best)
602 {
a6086ad4 603 if (debug)
604 zlog_debug("%s: New mpath count (incl newbest) %d mpath-change %s",
605 pfx_buf, mpath_count, mpath_changed ? "YES" : "NO");
606
de8d5dff
JB
607 bgp_info_mpath_count_set (new_best, mpath_count-1);
608 if (mpath_changed || (bgp_info_mpath_count (new_best) != old_mpath_count))
609 SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG);
610 }
611}
6918e74b
JB
612
613/*
614 * bgp_mp_dmed_deselect
615 *
616 * Clean up multipath information for BGP_INFO_DMED_SELECTED path that
617 * is not selected as best path
618 */
619void
620bgp_mp_dmed_deselect (struct bgp_info *dmed_best)
621{
622 struct bgp_info *mpinfo, *mpnext;
623
624 if (!dmed_best)
625 return;
626
627 for (mpinfo = bgp_info_mpath_first (dmed_best); mpinfo; mpinfo = mpnext)
628 {
629 mpnext = bgp_info_mpath_next (mpinfo);
630 bgp_info_mpath_dequeue (mpinfo);
631 }
632
633 bgp_info_mpath_count_set (dmed_best, 0);
634 UNSET_FLAG (dmed_best->flags, BGP_INFO_MULTIPATH_CHG);
635 assert (bgp_info_mpath_first (dmed_best) == 0);
636}
0b597ef0
JB
637
638/*
639 * bgp_info_mpath_aggregate_update
640 *
641 * Set the multipath aggregate attribute. We need to see if the
642 * aggregate has changed and then set the ATTR_CHANGED flag on the
643 * bestpath info so that a peer update will be generated. The
644 * change is detected by generating the current attribute,
645 * interning it, and then comparing the interned pointer with the
646 * current value. We can skip this generate/compare step if there
647 * is no change in multipath selection and no attribute change in
648 * any multipath.
649 */
650void
651bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
652 struct bgp_info *old_best)
653{
654 struct bgp_info *mpinfo;
655 struct aspath *aspath;
656 struct aspath *asmerge;
657 struct attr *new_attr, *old_attr;
219178b6 658 u_char origin;
0b597ef0
JB
659 struct community *community, *commerge;
660 struct ecommunity *ecomm, *ecommerge;
57d187bc 661 struct lcommunity *lcomm, *lcommerge;
0b597ef0
JB
662 struct attr attr = { 0 };
663
664 if (old_best && (old_best != new_best) &&
665 (old_attr = bgp_info_mpath_attr (old_best)))
666 {
fac3c245 667 bgp_attr_unintern (&old_attr);
0b597ef0
JB
668 bgp_info_mpath_attr_set (old_best, NULL);
669 }
670
671 if (!new_best)
672 return;
673
674 if (!bgp_info_mpath_count (new_best))
675 {
676 if ((new_attr = bgp_info_mpath_attr (new_best)))
677 {
fac3c245 678 bgp_attr_unintern (&new_attr);
0b597ef0
JB
679 bgp_info_mpath_attr_set (new_best, NULL);
680 SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
681 }
682 return;
683 }
684
0b597ef0
JB
685 bgp_attr_dup (&attr, new_best->attr);
686
16fc1eec 687 if (new_best->peer &&
219178b6 688 bgp_flag_check (new_best->peer->bgp, BGP_FLAG_MULTIPATH_RELAX_AS_SET))
0b597ef0 689 {
0b597ef0 690
16fc1eec
DS
691 /* aggregate attribute from multipath constituents */
692 aspath = aspath_dup (attr.aspath);
693 origin = attr.origin;
694 community = attr.community ? community_dup (attr.community) : NULL;
aadc0905
DS
695 ecomm = (attr.ecommunity) ? ecommunity_dup (attr.ecommunity) : NULL;
696 lcomm = (attr.lcommunity) ? lcommunity_dup (attr.lcommunity) : NULL;
0b597ef0 697
16fc1eec
DS
698 for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
699 mpinfo = bgp_info_mpath_next (mpinfo))
0b597ef0 700 {
16fc1eec
DS
701 asmerge = aspath_aggregate (aspath, mpinfo->attr->aspath);
702 aspath_free (aspath);
703 aspath = asmerge;
704
705 if (origin < mpinfo->attr->origin)
706 origin = mpinfo->attr->origin;
707
708 if (mpinfo->attr->community)
0b597ef0 709 {
16fc1eec
DS
710 if (community)
711 {
712 commerge = community_merge (community, mpinfo->attr->community);
713 community = community_uniq_sort (commerge);
714 community_free (commerge);
715 }
716 else
717 community = community_dup (mpinfo->attr->community);
0b597ef0 718 }
0b597ef0 719
aadc0905 720 if (mpinfo->attr->ecommunity)
0b597ef0 721 {
16fc1eec
DS
722 if (ecomm)
723 {
aadc0905 724 ecommerge = ecommunity_merge (ecomm, mpinfo->attr->ecommunity);
16fc1eec
DS
725 ecomm = ecommunity_uniq_sort (ecommerge);
726 ecommunity_free (&ecommerge);
727 }
728 else
aadc0905 729 ecomm = ecommunity_dup (mpinfo->attr->ecommunity);
0b597ef0 730 }
aadc0905 731 if (mpinfo->attr->lcommunity)
57d187bc
JS
732 {
733 if (lcomm)
734 {
aadc0905 735 lcommerge = lcommunity_merge (lcomm, mpinfo->attr->lcommunity);
57d187bc
JS
736 lcomm = lcommunity_uniq_sort (lcommerge);
737 lcommunity_free (&lcommerge);
738 }
739 else
aadc0905 740 lcomm = lcommunity_dup (mpinfo->attr->lcommunity);
57d187bc 741 }
0b597ef0 742 }
0b597ef0 743
16fc1eec
DS
744 attr.aspath = aspath;
745 attr.origin = origin;
746 if (community)
747 {
748 attr.community = community;
749 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
750 }
751 if (ecomm)
752 {
aadc0905 753 attr.ecommunity = ecomm;
16fc1eec
DS
754 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
755 }
0b597ef0 756
16fc1eec
DS
757 /* Zap multipath attr nexthop so we set nexthop to self */
758 attr.nexthop.s_addr = 0;
aadc0905 759 memset (&attr.mp_nexthop_global, 0, sizeof (struct in6_addr));
0b597ef0 760
16fc1eec
DS
761 /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */
762 }
0b597ef0
JB
763
764 new_attr = bgp_attr_intern (&attr);
0b597ef0
JB
765
766 if (new_attr != bgp_info_mpath_attr (new_best))
767 {
768 if ((old_attr = bgp_info_mpath_attr (new_best)))
fac3c245 769 bgp_attr_unintern (&old_attr);
0b597ef0
JB
770 bgp_info_mpath_attr_set (new_best, new_attr);
771 SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
772 }
773 else
fac3c245 774 bgp_attr_unintern (&new_attr);
0b597ef0 775}