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