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