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