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