]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_mpath.c
bgpd: Convert `struct bgp_info` to `struct bgp_path_info`
[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 uint16_t maxpaths, uint16_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_path_info *bi1, struct bgp_path_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_path_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_path_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_path_info_mpath *bgp_info_mpath_new(void)
262 {
263 struct bgp_path_info_mpath *new_mpath;
264 new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO,
265 sizeof(struct bgp_path_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_path_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_path_info_mpath *
291 bgp_info_mpath_get(struct bgp_path_info *binfo)
292 {
293 struct bgp_path_info_mpath *mpath;
294 if (!binfo->mpath) {
295 mpath = bgp_info_mpath_new();
296 if (!mpath)
297 return NULL;
298 binfo->mpath = mpath;
299 mpath->mp_info = binfo;
300 }
301 return binfo->mpath;
302 }
303
304 /*
305 * bgp_info_mpath_enqueue
306 *
307 * Enqueue a path onto the multipath list given the previous multipath
308 * list entry
309 */
310 static void bgp_info_mpath_enqueue(struct bgp_path_info *prev_info,
311 struct bgp_path_info *binfo)
312 {
313 struct bgp_path_info_mpath *prev, *mpath;
314
315 prev = bgp_info_mpath_get(prev_info);
316 mpath = bgp_info_mpath_get(binfo);
317 if (!prev || !mpath)
318 return;
319
320 mpath->mp_next = prev->mp_next;
321 mpath->mp_prev = prev;
322 if (prev->mp_next)
323 prev->mp_next->mp_prev = mpath;
324 prev->mp_next = mpath;
325
326 SET_FLAG(binfo->flags, BGP_PATH_MULTIPATH);
327 }
328
329 /*
330 * bgp_info_mpath_dequeue
331 *
332 * Remove a path from the multipath list
333 */
334 void bgp_info_mpath_dequeue(struct bgp_path_info *binfo)
335 {
336 struct bgp_path_info_mpath *mpath = binfo->mpath;
337 if (!mpath)
338 return;
339 if (mpath->mp_prev)
340 mpath->mp_prev->mp_next = mpath->mp_next;
341 if (mpath->mp_next)
342 mpath->mp_next->mp_prev = mpath->mp_prev;
343 mpath->mp_next = mpath->mp_prev = NULL;
344 UNSET_FLAG(binfo->flags, BGP_PATH_MULTIPATH);
345 }
346
347 /*
348 * bgp_info_mpath_next
349 *
350 * Given a bgp_info, return the next multipath entry
351 */
352 struct bgp_path_info *bgp_info_mpath_next(struct bgp_path_info *binfo)
353 {
354 if (!binfo->mpath || !binfo->mpath->mp_next)
355 return NULL;
356 return binfo->mpath->mp_next->mp_info;
357 }
358
359 /*
360 * bgp_info_mpath_first
361 *
362 * Given bestpath bgp_info, return the first multipath entry.
363 */
364 struct bgp_path_info *bgp_info_mpath_first(struct bgp_path_info *binfo)
365 {
366 return bgp_info_mpath_next(binfo);
367 }
368
369 /*
370 * bgp_info_mpath_count
371 *
372 * Given the bestpath bgp_info, return the number of multipath entries
373 */
374 uint32_t bgp_info_mpath_count(struct bgp_path_info *binfo)
375 {
376 if (!binfo->mpath)
377 return 0;
378 return binfo->mpath->mp_count;
379 }
380
381 /*
382 * bgp_info_mpath_count_set
383 *
384 * Sets the count of multipaths into bestpath's mpath element
385 */
386 static void bgp_info_mpath_count_set(struct bgp_path_info *binfo,
387 uint32_t count)
388 {
389 struct bgp_path_info_mpath *mpath;
390 if (!count && !binfo->mpath)
391 return;
392 mpath = bgp_info_mpath_get(binfo);
393 if (!mpath)
394 return;
395 mpath->mp_count = count;
396 }
397
398 /*
399 * bgp_info_mpath_attr
400 *
401 * Given bestpath bgp_info, return aggregated attribute set used
402 * for advertising the multipath route
403 */
404 struct attr *bgp_info_mpath_attr(struct bgp_path_info *binfo)
405 {
406 if (!binfo->mpath)
407 return NULL;
408 return binfo->mpath->mp_attr;
409 }
410
411 /*
412 * bgp_info_mpath_attr_set
413 *
414 * Sets the aggregated attribute into bestpath's mpath element
415 */
416 static void bgp_info_mpath_attr_set(struct bgp_path_info *binfo,
417 struct attr *attr)
418 {
419 struct bgp_path_info_mpath *mpath;
420 if (!attr && !binfo->mpath)
421 return;
422 mpath = bgp_info_mpath_get(binfo);
423 if (!mpath)
424 return;
425 mpath->mp_attr = attr;
426 }
427
428 /*
429 * bgp_info_mpath_update
430 *
431 * Compare and sync up the multipath list with the mp_list generated by
432 * bgp_best_selection
433 */
434 void bgp_info_mpath_update(struct bgp_node *rn, struct bgp_path_info *new_best,
435 struct bgp_path_info *old_best, struct list *mp_list,
436 struct bgp_maxpaths_cfg *mpath_cfg)
437 {
438 uint16_t maxpaths, mpath_count, old_mpath_count;
439 struct listnode *mp_node, *mp_next_node;
440 struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
441 int mpath_changed, debug;
442 char pfx_buf[PREFIX2STR_BUFFER], nh_buf[2][INET6_ADDRSTRLEN];
443 char path_buf[PATH_ADDPATH_STR_BUFFER];
444
445 mpath_changed = 0;
446 maxpaths = multipath_num;
447 mpath_count = 0;
448 cur_mpath = NULL;
449 old_mpath_count = 0;
450 prev_mpath = new_best;
451 mp_node = listhead(mp_list);
452 debug = bgp_debug_bestpath(&rn->p);
453
454 if (debug)
455 prefix2str(&rn->p, pfx_buf, sizeof(pfx_buf));
456
457 if (new_best) {
458 mpath_count++;
459 if (new_best != old_best)
460 bgp_info_mpath_dequeue(new_best);
461 maxpaths = (new_best->peer->sort == BGP_PEER_IBGP)
462 ? mpath_cfg->maxpaths_ibgp
463 : mpath_cfg->maxpaths_ebgp;
464 }
465
466 if (old_best) {
467 cur_mpath = bgp_info_mpath_first(old_best);
468 old_mpath_count = bgp_info_mpath_count(old_best);
469 bgp_info_mpath_count_set(old_best, 0);
470 bgp_info_mpath_dequeue(old_best);
471 }
472
473 if (debug)
474 zlog_debug(
475 "%s: starting mpath update, newbest %s num candidates %d old-mpath-count %d",
476 pfx_buf, new_best ? new_best->peer->host : "NONE",
477 mp_list ? listcount(mp_list) : 0, old_mpath_count);
478
479 /*
480 * We perform an ordered walk through both lists in parallel.
481 * The reason for the ordered walk is that if there are paths
482 * that were previously multipaths and are still multipaths, the walk
483 * should encounter them in both lists at the same time. Otherwise
484 * there will be paths that are in one list or another, and we
485 * will deal with these separately.
486 *
487 * Note that new_best might be somewhere in the mp_list, so we need
488 * to skip over it
489 */
490 while (mp_node || cur_mpath) {
491 struct bgp_path_info *tmp_info;
492
493 /*
494 * We can bail out of this loop if all existing paths on the
495 * multipath list have been visited (for cleanup purposes) and
496 * the maxpath requirement is fulfulled
497 */
498 if (!cur_mpath && (mpath_count >= maxpaths))
499 break;
500
501 mp_next_node = mp_node ? listnextnode(mp_node) : NULL;
502 next_mpath = cur_mpath ? bgp_info_mpath_next(cur_mpath) : NULL;
503 tmp_info = mp_node ? listgetdata(mp_node) : NULL;
504
505 if (debug)
506 zlog_debug(
507 "%s: comparing candidate %s with existing mpath %s",
508 pfx_buf,
509 tmp_info ? tmp_info->peer->host : "NONE",
510 cur_mpath ? cur_mpath->peer->host : "NONE");
511
512 /*
513 * If equal, the path was a multipath and is still a multipath.
514 * Insert onto new multipath list if maxpaths allows.
515 */
516 if (mp_node && (listgetdata(mp_node) == cur_mpath)) {
517 list_delete_node(mp_list, mp_node);
518 bgp_info_mpath_dequeue(cur_mpath);
519 if ((mpath_count < maxpaths)
520 && bgp_info_nexthop_cmp(prev_mpath, cur_mpath)) {
521 bgp_info_mpath_enqueue(prev_mpath, cur_mpath);
522 prev_mpath = cur_mpath;
523 mpath_count++;
524 if (debug) {
525 bgp_info_path_with_addpath_rx_str(
526 cur_mpath, path_buf);
527 zlog_debug(
528 "%s: %s is still multipath, cur count %d",
529 pfx_buf, path_buf, mpath_count);
530 }
531 } else {
532 mpath_changed = 1;
533 if (debug) {
534 bgp_info_path_with_addpath_rx_str(
535 cur_mpath, path_buf);
536 zlog_debug(
537 "%s: remove mpath %s nexthop %s, cur count %d",
538 pfx_buf, path_buf,
539 inet_ntop(AF_INET,
540 &cur_mpath->attr
541 ->nexthop,
542 nh_buf[0],
543 sizeof(nh_buf[0])),
544 mpath_count);
545 }
546 }
547 mp_node = mp_next_node;
548 cur_mpath = next_mpath;
549 continue;
550 }
551
552 if (cur_mpath
553 && (!mp_node
554 || (bgp_info_mpath_cmp(cur_mpath, listgetdata(mp_node))
555 < 0))) {
556 /*
557 * If here, we have an old multipath and either the
558 * mp_list
559 * is finished or the next mp_node points to a later
560 * multipath, so we need to purge this path from the
561 * multipath list
562 */
563 bgp_info_mpath_dequeue(cur_mpath);
564 mpath_changed = 1;
565 if (debug) {
566 bgp_info_path_with_addpath_rx_str(cur_mpath,
567 path_buf);
568 zlog_debug(
569 "%s: remove mpath %s nexthop %s, cur count %d",
570 pfx_buf, path_buf,
571 inet_ntop(AF_INET,
572 &cur_mpath->attr->nexthop,
573 nh_buf[0], sizeof(nh_buf[0])),
574 mpath_count);
575 }
576 cur_mpath = next_mpath;
577 } else {
578 /*
579 * If here, we have a path on the mp_list that was not
580 * previously
581 * a multipath (due to non-equivalance or maxpaths
582 * exceeded),
583 * or the matching multipath is sorted later in the
584 * multipath
585 * list. Before we enqueue the path on the new multipath
586 * list,
587 * make sure its not on the old_best multipath list or
588 * referenced
589 * via next_mpath:
590 * - If next_mpath points to this new path, update
591 * next_mpath to
592 * point to the multipath after this one
593 * - Dequeue the path from the multipath list just to
594 * make sure
595 */
596 new_mpath = listgetdata(mp_node);
597 list_delete_node(mp_list, mp_node);
598 assert(new_mpath);
599 assert(prev_mpath);
600 if ((mpath_count < maxpaths) && (new_mpath != new_best)
601 && bgp_info_nexthop_cmp(prev_mpath, new_mpath)) {
602 if (new_mpath == next_mpath)
603 bgp_info_mpath_next(new_mpath);
604 bgp_info_mpath_dequeue(new_mpath);
605
606 bgp_info_mpath_enqueue(prev_mpath, new_mpath);
607 prev_mpath = new_mpath;
608 mpath_changed = 1;
609 mpath_count++;
610 if (debug) {
611 bgp_info_path_with_addpath_rx_str(
612 new_mpath, path_buf);
613 zlog_debug(
614 "%s: add mpath %s nexthop %s, cur count %d",
615 pfx_buf, path_buf,
616 inet_ntop(AF_INET,
617 &new_mpath->attr
618 ->nexthop,
619 nh_buf[0],
620 sizeof(nh_buf[0])),
621 mpath_count);
622 }
623 }
624 mp_node = mp_next_node;
625 }
626 }
627
628 if (new_best) {
629 if (debug)
630 zlog_debug(
631 "%s: New mpath count (incl newbest) %d mpath-change %s",
632 pfx_buf, mpath_count,
633 mpath_changed ? "YES" : "NO");
634
635 bgp_info_mpath_count_set(new_best, mpath_count - 1);
636 if (mpath_changed
637 || (bgp_info_mpath_count(new_best) != old_mpath_count))
638 SET_FLAG(new_best->flags, BGP_PATH_MULTIPATH_CHG);
639 }
640 }
641
642 /*
643 * bgp_mp_dmed_deselect
644 *
645 * Clean up multipath information for BGP_PATH_DMED_SELECTED path that
646 * is not selected as best path
647 */
648 void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best)
649 {
650 struct bgp_path_info *mpinfo, *mpnext;
651
652 if (!dmed_best)
653 return;
654
655 for (mpinfo = bgp_info_mpath_first(dmed_best); mpinfo;
656 mpinfo = mpnext) {
657 mpnext = bgp_info_mpath_next(mpinfo);
658 bgp_info_mpath_dequeue(mpinfo);
659 }
660
661 bgp_info_mpath_count_set(dmed_best, 0);
662 UNSET_FLAG(dmed_best->flags, BGP_PATH_MULTIPATH_CHG);
663 assert(bgp_info_mpath_first(dmed_best) == 0);
664 }
665
666 /*
667 * bgp_info_mpath_aggregate_update
668 *
669 * Set the multipath aggregate attribute. We need to see if the
670 * aggregate has changed and then set the ATTR_CHANGED flag on the
671 * bestpath info so that a peer update will be generated. The
672 * change is detected by generating the current attribute,
673 * interning it, and then comparing the interned pointer with the
674 * current value. We can skip this generate/compare step if there
675 * is no change in multipath selection and no attribute change in
676 * any multipath.
677 */
678 void bgp_info_mpath_aggregate_update(struct bgp_path_info *new_best,
679 struct bgp_path_info *old_best)
680 {
681 struct bgp_path_info *mpinfo;
682 struct aspath *aspath;
683 struct aspath *asmerge;
684 struct attr *new_attr, *old_attr;
685 uint8_t origin;
686 struct community *community, *commerge;
687 struct ecommunity *ecomm, *ecommerge;
688 struct lcommunity *lcomm, *lcommerge;
689 struct attr attr = {0};
690
691 if (old_best && (old_best != new_best)
692 && (old_attr = bgp_info_mpath_attr(old_best))) {
693 bgp_attr_unintern(&old_attr);
694 bgp_info_mpath_attr_set(old_best, NULL);
695 }
696
697 if (!new_best)
698 return;
699
700 if (!bgp_info_mpath_count(new_best)) {
701 if ((new_attr = bgp_info_mpath_attr(new_best))) {
702 bgp_attr_unintern(&new_attr);
703 bgp_info_mpath_attr_set(new_best, NULL);
704 SET_FLAG(new_best->flags, BGP_PATH_ATTR_CHANGED);
705 }
706 return;
707 }
708
709 bgp_attr_dup(&attr, new_best->attr);
710
711 if (new_best->peer && bgp_flag_check(new_best->peer->bgp,
712 BGP_FLAG_MULTIPATH_RELAX_AS_SET)) {
713
714 /* aggregate attribute from multipath constituents */
715 aspath = aspath_dup(attr.aspath);
716 origin = attr.origin;
717 community =
718 attr.community ? community_dup(attr.community) : NULL;
719 ecomm = (attr.ecommunity) ? ecommunity_dup(attr.ecommunity)
720 : NULL;
721 lcomm = (attr.lcommunity) ? lcommunity_dup(attr.lcommunity)
722 : NULL;
723
724 for (mpinfo = bgp_info_mpath_first(new_best); mpinfo;
725 mpinfo = bgp_info_mpath_next(mpinfo)) {
726 asmerge =
727 aspath_aggregate(aspath, mpinfo->attr->aspath);
728 aspath_free(aspath);
729 aspath = asmerge;
730
731 if (origin < mpinfo->attr->origin)
732 origin = mpinfo->attr->origin;
733
734 if (mpinfo->attr->community) {
735 if (community) {
736 commerge = community_merge(
737 community,
738 mpinfo->attr->community);
739 community =
740 community_uniq_sort(commerge);
741 community_free(commerge);
742 } else
743 community = community_dup(
744 mpinfo->attr->community);
745 }
746
747 if (mpinfo->attr->ecommunity) {
748 if (ecomm) {
749 ecommerge = ecommunity_merge(
750 ecomm,
751 mpinfo->attr->ecommunity);
752 ecomm = ecommunity_uniq_sort(ecommerge);
753 ecommunity_free(&ecommerge);
754 } else
755 ecomm = ecommunity_dup(
756 mpinfo->attr->ecommunity);
757 }
758 if (mpinfo->attr->lcommunity) {
759 if (lcomm) {
760 lcommerge = lcommunity_merge(
761 lcomm,
762 mpinfo->attr->lcommunity);
763 lcomm = lcommunity_uniq_sort(lcommerge);
764 lcommunity_free(&lcommerge);
765 } else
766 lcomm = lcommunity_dup(
767 mpinfo->attr->lcommunity);
768 }
769 }
770
771 attr.aspath = aspath;
772 attr.origin = origin;
773 if (community) {
774 attr.community = community;
775 attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
776 }
777 if (ecomm) {
778 attr.ecommunity = ecomm;
779 attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
780 }
781 if (lcomm) {
782 attr.lcommunity = lcomm;
783 attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES);
784 }
785
786 /* Zap multipath attr nexthop so we set nexthop to self */
787 attr.nexthop.s_addr = 0;
788 memset(&attr.mp_nexthop_global, 0, sizeof(struct in6_addr));
789
790 /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */
791 }
792
793 new_attr = bgp_attr_intern(&attr);
794
795 if (new_attr != bgp_info_mpath_attr(new_best)) {
796 if ((old_attr = bgp_info_mpath_attr(new_best)))
797 bgp_attr_unintern(&old_attr);
798 bgp_info_mpath_attr_set(new_best, new_attr);
799 SET_FLAG(new_best->flags, BGP_PATH_ATTR_CHANGED);
800 } else
801 bgp_attr_unintern(&new_attr);
802 }