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