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