]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_mpath.c
If the .conf file for a process is missing have /etc/init.d/quagga touch it so we...
[mirror_frr.git] / bgpd / bgp_mpath.c
CommitLineData
165b5fff
JB
1/* $QuaggaId: Format:%an, %ai, %h$ $
2 *
3 * BGP Multipath
4 * Copyright (C) 2010 Google Inc.
5 *
6 * This file is part of Quagga
7 *
8 * Quagga is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * Quagga is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Quagga; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23
24#include <zebra.h>
25
26#include "command.h"
96450faf
JB
27#include "prefix.h"
28#include "linklist.h"
29#include "sockunion.h"
de8d5dff 30#include "memory.h"
165b5fff
JB
31
32#include "bgpd/bgpd.h"
96450faf
JB
33#include "bgpd/bgp_table.h"
34#include "bgpd/bgp_route.h"
35#include "bgpd/bgp_attr.h"
de8d5dff 36#include "bgpd/bgp_debug.h"
0b597ef0
JB
37#include "bgpd/bgp_aspath.h"
38#include "bgpd/bgp_community.h"
39#include "bgpd/bgp_ecommunity.h"
165b5fff
JB
40#include "bgpd/bgp_mpath.h"
41
42/*
43 * bgp_maximum_paths_set
44 *
45 * Record maximum-paths configuration for BGP instance
46 */
47int
48bgp_maximum_paths_set (struct bgp *bgp, afi_t afi, safi_t safi,
5e242b0d 49 int peertype, u_int16_t maxpaths, u_int16_t options)
165b5fff
JB
50{
51 if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
52 return -1;
53
54 switch (peertype)
55 {
56 case BGP_PEER_IBGP:
57 bgp->maxpaths[afi][safi].maxpaths_ibgp = maxpaths;
5e242b0d 58 bgp->maxpaths[afi][safi].ibgp_flags |= options;
165b5fff
JB
59 break;
60 case BGP_PEER_EBGP:
61 bgp->maxpaths[afi][safi].maxpaths_ebgp = maxpaths;
62 break;
63 default:
64 return -1;
65 }
66
67 return 0;
68}
69
70/*
71 * bgp_maximum_paths_unset
72 *
73 * Remove maximum-paths configuration from BGP instance
74 */
75int
76bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi,
77 int peertype)
78{
79 if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
80 return -1;
81
82 switch (peertype)
83 {
84 case BGP_PEER_IBGP:
85 bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS;
5e242b0d 86 bgp->maxpaths[afi][safi].ibgp_flags = 0;
165b5fff
JB
87 break;
88 case BGP_PEER_EBGP:
89 bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS;
90 break;
91 default:
92 return -1;
93 }
94
95 return 0;
96}
96450faf
JB
97
98/*
99 * bgp_info_nexthop_cmp
100 *
101 * Compare the nexthops of two paths. Return value is less than, equal to,
102 * or greater than zero if bi1 is respectively less than, equal to,
103 * or greater than bi2.
104 */
105static int
106bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2)
107{
108 struct attr_extra *ae1, *ae2;
109 int compare;
110
0b597ef0
JB
111 ae1 = bi1->attr->extra;
112 ae2 = bi2->attr->extra;
96450faf
JB
113
114 compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop);
115
116 if (!compare && ae1 && ae2 && (ae1->mp_nexthop_len == ae2->mp_nexthop_len))
117 {
118 switch (ae1->mp_nexthop_len)
119 {
120 case 4:
121 case 12:
122 compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in,
123 &ae2->mp_nexthop_global_in);
124 break;
125#ifdef HAVE_IPV6
126 case 16:
127 compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
128 &ae2->mp_nexthop_global);
129 break;
130 case 32:
131 compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global,
132 &ae2->mp_nexthop_global);
133 if (!compare)
134 compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local,
135 &ae2->mp_nexthop_local);
136 break;
137#endif /* HAVE_IPV6 */
138 }
139 }
140
141 return compare;
142}
143
144/*
145 * bgp_info_mpath_cmp
146 *
147 * This function determines our multipath list ordering. By ordering
148 * the list we can deterministically select which paths are included
149 * in the multipath set. The ordering also helps in detecting changes
150 * in the multipath selection so we can detect whether to send an
151 * update to zebra.
152 *
153 * The order of paths is determined first by received nexthop, and then
154 * by peer address if the nexthops are the same.
155 */
156static int
157bgp_info_mpath_cmp (void *val1, void *val2)
158{
159 struct bgp_info *bi1, *bi2;
160 int compare;
161
162 bi1 = val1;
163 bi2 = val2;
164
165 compare = bgp_info_nexthop_cmp (bi1, bi2);
166
167 if (!compare)
168 compare = sockunion_cmp (bi1->peer->su_remote, bi2->peer->su_remote);
169
170 return compare;
171}
172
173/*
174 * bgp_mp_list_init
175 *
176 * Initialize the mp_list, which holds the list of multipaths
177 * selected by bgp_best_selection
178 */
179void
180bgp_mp_list_init (struct list *mp_list)
181{
182 assert (mp_list);
183 memset (mp_list, 0, sizeof (struct list));
184 mp_list->cmp = bgp_info_mpath_cmp;
185}
186
187/*
188 * bgp_mp_list_clear
189 *
190 * Clears all entries out of the mp_list
191 */
192void
193bgp_mp_list_clear (struct list *mp_list)
194{
195 assert (mp_list);
196 list_delete_all_node (mp_list);
197}
198
199/*
200 * bgp_mp_list_add
201 *
202 * Adds a multipath entry to the mp_list
203 */
204void
205bgp_mp_list_add (struct list *mp_list, struct bgp_info *mpinfo)
206{
207 assert (mp_list && mpinfo);
208 listnode_add_sort (mp_list, mpinfo);
209}
de8d5dff
JB
210
211/*
212 * bgp_info_mpath_new
213 *
214 * Allocate and zero memory for a new bgp_info_mpath element
215 */
216static struct bgp_info_mpath *
217bgp_info_mpath_new (void)
218{
219 struct bgp_info_mpath *new_mpath;
220 new_mpath = XCALLOC (MTYPE_BGP_MPATH_INFO, sizeof (struct bgp_info_mpath));
221 return new_mpath;
222}
223
224/*
225 * bgp_info_mpath_free
226 *
227 * Release resources for a bgp_info_mpath element and zero out pointer
228 */
229void
230bgp_info_mpath_free (struct bgp_info_mpath **mpath)
231{
232 if (mpath && *mpath)
233 {
0b597ef0 234 if ((*mpath)->mp_attr)
fac3c245 235 bgp_attr_unintern (&(*mpath)->mp_attr);
de8d5dff
JB
236 XFREE (MTYPE_BGP_MPATH_INFO, *mpath);
237 *mpath = NULL;
238 }
239}
240
241/*
242 * bgp_info_mpath_get
243 *
244 * Fetch the mpath element for the given bgp_info. Used for
245 * doing lazy allocation.
246 */
247static struct bgp_info_mpath *
248bgp_info_mpath_get (struct bgp_info *binfo)
249{
250 struct bgp_info_mpath *mpath;
251 if (!binfo->mpath)
252 {
253 mpath = bgp_info_mpath_new();
254 if (!mpath)
255 return NULL;
256 binfo->mpath = mpath;
257 mpath->mp_info = binfo;
258 }
259 return binfo->mpath;
260}
261
262/*
263 * bgp_info_mpath_enqueue
264 *
265 * Enqueue a path onto the multipath list given the previous multipath
266 * list entry
267 */
268static void
269bgp_info_mpath_enqueue (struct bgp_info *prev_info, struct bgp_info *binfo)
270{
271 struct bgp_info_mpath *prev, *mpath;
272
273 prev = bgp_info_mpath_get (prev_info);
274 mpath = bgp_info_mpath_get (binfo);
275 if (!prev || !mpath)
276 return;
277
278 mpath->mp_next = prev->mp_next;
279 mpath->mp_prev = prev;
280 if (prev->mp_next)
281 prev->mp_next->mp_prev = mpath;
282 prev->mp_next = mpath;
283
284 SET_FLAG (binfo->flags, BGP_INFO_MULTIPATH);
285}
286
287/*
288 * bgp_info_mpath_dequeue
289 *
290 * Remove a path from the multipath list
291 */
292void
293bgp_info_mpath_dequeue (struct bgp_info *binfo)
294{
295 struct bgp_info_mpath *mpath = binfo->mpath;
296 if (!mpath)
297 return;
298 if (mpath->mp_prev)
299 mpath->mp_prev->mp_next = mpath->mp_next;
300 if (mpath->mp_next)
301 mpath->mp_next->mp_prev = mpath->mp_prev;
302 mpath->mp_next = mpath->mp_prev = NULL;
303 UNSET_FLAG (binfo->flags, BGP_INFO_MULTIPATH);
304}
305
306/*
307 * bgp_info_mpath_next
308 *
309 * Given a bgp_info, return the next multipath entry
310 */
311struct bgp_info *
312bgp_info_mpath_next (struct bgp_info *binfo)
313{
314 if (!binfo->mpath || !binfo->mpath->mp_next)
315 return NULL;
316 return binfo->mpath->mp_next->mp_info;
317}
318
319/*
320 * bgp_info_mpath_first
321 *
322 * Given bestpath bgp_info, return the first multipath entry.
323 */
324struct bgp_info *
325bgp_info_mpath_first (struct bgp_info *binfo)
326{
327 return bgp_info_mpath_next (binfo);
328}
329
330/*
331 * bgp_info_mpath_count
332 *
333 * Given the bestpath bgp_info, return the number of multipath entries
334 */
335u_int32_t
336bgp_info_mpath_count (struct bgp_info *binfo)
337{
338 if (!binfo->mpath)
339 return 0;
340 return binfo->mpath->mp_count;
341}
342
343/*
344 * bgp_info_mpath_count_set
345 *
346 * Sets the count of multipaths into bestpath's mpath element
347 */
348static void
349bgp_info_mpath_count_set (struct bgp_info *binfo, u_int32_t count)
350{
351 struct bgp_info_mpath *mpath;
352 if (!count && !binfo->mpath)
353 return;
354 mpath = bgp_info_mpath_get (binfo);
355 if (!mpath)
356 return;
357 mpath->mp_count = count;
358}
359
0b597ef0
JB
360/*
361 * bgp_info_mpath_attr
362 *
363 * Given bestpath bgp_info, return aggregated attribute set used
364 * for advertising the multipath route
365 */
366struct attr *
367bgp_info_mpath_attr (struct bgp_info *binfo)
368{
369 if (!binfo->mpath)
370 return NULL;
371 return binfo->mpath->mp_attr;
372}
373
374/*
375 * bgp_info_mpath_attr_set
376 *
377 * Sets the aggregated attribute into bestpath's mpath element
378 */
379static void
380bgp_info_mpath_attr_set (struct bgp_info *binfo, struct attr *attr)
381{
382 struct bgp_info_mpath *mpath;
383 if (!attr && !binfo->mpath)
384 return;
385 mpath = bgp_info_mpath_get (binfo);
386 if (!mpath)
387 return;
388 mpath->mp_attr = attr;
389}
390
de8d5dff
JB
391/*
392 * bgp_info_mpath_update
393 *
394 * Compare and sync up the multipath list with the mp_list generated by
395 * bgp_best_selection
396 */
397void
398bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best,
399 struct bgp_info *old_best, struct list *mp_list,
400 struct bgp_maxpaths_cfg *mpath_cfg)
401{
402 u_int16_t maxpaths, mpath_count, old_mpath_count;
403 struct listnode *mp_node, *mp_next_node;
404 struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
405 int mpath_changed, debug;
406 char pfx_buf[INET_ADDRSTRLEN], nh_buf[2][INET_ADDRSTRLEN];
407
408 mpath_changed = 0;
409 maxpaths = BGP_DEFAULT_MAXPATHS;
410 mpath_count = 0;
411 cur_mpath = NULL;
412 old_mpath_count = 0;
413 prev_mpath = new_best;
414 mp_node = listhead (mp_list);
16286195 415 debug = bgp_debug_update(NULL, &rn->p, 1) || bgp_debug_update(NULL, &rn->p, 0);
de8d5dff
JB
416
417 if (debug)
418 prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf));
419
420 if (new_best)
421 {
422 mpath_count++;
423 if (new_best != old_best)
424 bgp_info_mpath_dequeue (new_best);
6d85b15b 425 maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ?
de8d5dff
JB
426 mpath_cfg->maxpaths_ibgp : mpath_cfg->maxpaths_ebgp;
427 }
428
429 if (old_best)
430 {
431 cur_mpath = bgp_info_mpath_first (old_best);
432 old_mpath_count = bgp_info_mpath_count (old_best);
433 bgp_info_mpath_count_set (old_best, 0);
434 bgp_info_mpath_dequeue (old_best);
435 }
436
437 /*
438 * We perform an ordered walk through both lists in parallel.
439 * The reason for the ordered walk is that if there are paths
440 * that were previously multipaths and are still multipaths, the walk
441 * should encounter them in both lists at the same time. Otherwise
442 * there will be paths that are in one list or another, and we
443 * will deal with these separately.
444 *
445 * Note that new_best might be somewhere in the mp_list, so we need
446 * to skip over it
447 */
448 while (mp_node || cur_mpath)
449 {
450 /*
451 * We can bail out of this loop if all existing paths on the
452 * multipath list have been visited (for cleanup purposes) and
453 * the maxpath requirement is fulfulled
454 */
455 if (!cur_mpath && (mpath_count >= maxpaths))
456 break;
457
458 mp_next_node = mp_node ? listnextnode (mp_node) : NULL;
459 next_mpath = cur_mpath ? bgp_info_mpath_next (cur_mpath) : NULL;
460
461 /*
462 * If equal, the path was a multipath and is still a multipath.
463 * Insert onto new multipath list if maxpaths allows.
464 */
465 if (mp_node && (listgetdata (mp_node) == cur_mpath))
466 {
467 list_delete_node (mp_list, mp_node);
468 bgp_info_mpath_dequeue (cur_mpath);
469 if ((mpath_count < maxpaths) &&
470 bgp_info_nexthop_cmp (prev_mpath, cur_mpath))
471 {
472 bgp_info_mpath_enqueue (prev_mpath, cur_mpath);
473 prev_mpath = cur_mpath;
474 mpath_count++;
475 }
476 else
477 {
478 mpath_changed = 1;
479 if (debug)
480 zlog_debug ("%s remove mpath nexthop %s peer %s", pfx_buf,
481 inet_ntop (AF_INET, &cur_mpath->attr->nexthop,
482 nh_buf[0], sizeof (nh_buf[0])),
483 sockunion2str (cur_mpath->peer->su_remote,
484 nh_buf[1], sizeof (nh_buf[1])));
485 }
486 mp_node = mp_next_node;
487 cur_mpath = next_mpath;
488 continue;
489 }
490
491 if (cur_mpath && (!mp_node ||
492 (bgp_info_mpath_cmp (cur_mpath,
493 listgetdata (mp_node)) < 0)))
494 {
495 /*
496 * If here, we have an old multipath and either the mp_list
497 * is finished or the next mp_node points to a later
498 * multipath, so we need to purge this path from the
499 * multipath list
500 */
501 bgp_info_mpath_dequeue (cur_mpath);
502 mpath_changed = 1;
503 if (debug)
504 zlog_debug ("%s remove mpath nexthop %s peer %s", pfx_buf,
505 inet_ntop (AF_INET, &cur_mpath->attr->nexthop,
506 nh_buf[0], sizeof (nh_buf[0])),
507 sockunion2str (cur_mpath->peer->su_remote,
508 nh_buf[1], sizeof (nh_buf[1])));
509 cur_mpath = next_mpath;
510 }
511 else
512 {
513 /*
514 * If here, we have a path on the mp_list that was not previously
515 * a multipath (due to non-equivalance or maxpaths exceeded),
516 * or the matching multipath is sorted later in the multipath
517 * list. Before we enqueue the path on the new multipath list,
518 * make sure its not on the old_best multipath list or referenced
519 * via next_mpath:
520 * - If next_mpath points to this new path, update next_mpath to
521 * point to the multipath after this one
522 * - Dequeue the path from the multipath list just to make sure
523 */
524 new_mpath = listgetdata (mp_node);
525 list_delete_node (mp_list, mp_node);
de8d5dff
JB
526 if ((mpath_count < maxpaths) && (new_mpath != new_best) &&
527 bgp_info_nexthop_cmp (prev_mpath, new_mpath))
528 {
78d92e17
JB
529 if (new_mpath == next_mpath)
530 next_mpath = bgp_info_mpath_next (new_mpath);
531 bgp_info_mpath_dequeue (new_mpath);
532
de8d5dff
JB
533 bgp_info_mpath_enqueue (prev_mpath, new_mpath);
534 prev_mpath = new_mpath;
535 mpath_changed = 1;
536 mpath_count++;
537 if (debug)
538 zlog_debug ("%s add mpath nexthop %s peer %s", pfx_buf,
539 inet_ntop (AF_INET, &new_mpath->attr->nexthop,
540 nh_buf[0], sizeof (nh_buf[0])),
541 sockunion2str (new_mpath->peer->su_remote,
542 nh_buf[1], sizeof (nh_buf[1])));
543 }
544 mp_node = mp_next_node;
545 }
546 }
547
548 if (new_best)
549 {
550 bgp_info_mpath_count_set (new_best, mpath_count-1);
551 if (mpath_changed || (bgp_info_mpath_count (new_best) != old_mpath_count))
552 SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG);
553 }
554}
6918e74b
JB
555
556/*
557 * bgp_mp_dmed_deselect
558 *
559 * Clean up multipath information for BGP_INFO_DMED_SELECTED path that
560 * is not selected as best path
561 */
562void
563bgp_mp_dmed_deselect (struct bgp_info *dmed_best)
564{
565 struct bgp_info *mpinfo, *mpnext;
566
567 if (!dmed_best)
568 return;
569
570 for (mpinfo = bgp_info_mpath_first (dmed_best); mpinfo; mpinfo = mpnext)
571 {
572 mpnext = bgp_info_mpath_next (mpinfo);
573 bgp_info_mpath_dequeue (mpinfo);
574 }
575
576 bgp_info_mpath_count_set (dmed_best, 0);
577 UNSET_FLAG (dmed_best->flags, BGP_INFO_MULTIPATH_CHG);
578 assert (bgp_info_mpath_first (dmed_best) == 0);
579}
0b597ef0
JB
580
581/*
582 * bgp_info_mpath_aggregate_update
583 *
584 * Set the multipath aggregate attribute. We need to see if the
585 * aggregate has changed and then set the ATTR_CHANGED flag on the
586 * bestpath info so that a peer update will be generated. The
587 * change is detected by generating the current attribute,
588 * interning it, and then comparing the interned pointer with the
589 * current value. We can skip this generate/compare step if there
590 * is no change in multipath selection and no attribute change in
591 * any multipath.
592 */
593void
594bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
595 struct bgp_info *old_best)
596{
597 struct bgp_info *mpinfo;
598 struct aspath *aspath;
599 struct aspath *asmerge;
600 struct attr *new_attr, *old_attr;
601 u_char origin, attr_chg;
602 struct community *community, *commerge;
603 struct ecommunity *ecomm, *ecommerge;
604 struct attr_extra *ae;
605 struct attr attr = { 0 };
606
607 if (old_best && (old_best != new_best) &&
608 (old_attr = bgp_info_mpath_attr (old_best)))
609 {
fac3c245 610 bgp_attr_unintern (&old_attr);
0b597ef0
JB
611 bgp_info_mpath_attr_set (old_best, NULL);
612 }
613
614 if (!new_best)
615 return;
616
617 if (!bgp_info_mpath_count (new_best))
618 {
619 if ((new_attr = bgp_info_mpath_attr (new_best)))
620 {
fac3c245 621 bgp_attr_unintern (&new_attr);
0b597ef0
JB
622 bgp_info_mpath_attr_set (new_best, NULL);
623 SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
624 }
625 return;
626 }
627
628 /*
629 * Bail out here if the following is true:
630 * - MULTIPATH_CHG bit is not set on new_best, and
01d7ff0a 631 * - No change in bestpath, and
0b597ef0
JB
632 * - ATTR_CHANGED bit is not set on new_best or any of the multipaths
633 */
01d7ff0a
JB
634 if (!CHECK_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG) &&
635 (old_best == new_best))
636 {
637 attr_chg = 0;
638
639 if (CHECK_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED))
640 attr_chg = 1;
641 else
642 for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
643 mpinfo = bgp_info_mpath_next (mpinfo))
0b597ef0 644 {
01d7ff0a
JB
645 if (CHECK_FLAG (mpinfo->flags, BGP_INFO_ATTR_CHANGED))
646 {
647 attr_chg = 1;
648 break;
649 }
0b597ef0 650 }
01d7ff0a
JB
651
652 if (!attr_chg)
653 {
654 assert (bgp_info_mpath_attr (new_best));
655 return;
656 }
0b597ef0
JB
657 }
658
659 bgp_attr_dup (&attr, new_best->attr);
660
661 /* aggregate attribute from multipath constituents */
662 aspath = aspath_dup (attr.aspath);
663 origin = attr.origin;
664 community = attr.community ? community_dup (attr.community) : NULL;
665 ae = attr.extra;
666 ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL;
667
668 for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
669 mpinfo = bgp_info_mpath_next (mpinfo))
670 {
671 asmerge = aspath_aggregate (aspath, mpinfo->attr->aspath);
672 aspath_free (aspath);
673 aspath = asmerge;
674
675 if (origin < mpinfo->attr->origin)
676 origin = mpinfo->attr->origin;
677
678 if (mpinfo->attr->community)
679 {
680 if (community)
681 {
682 commerge = community_merge (community, mpinfo->attr->community);
683 community = community_uniq_sort (commerge);
684 community_free (commerge);
685 }
686 else
687 community = community_dup (mpinfo->attr->community);
688 }
689
690 ae = mpinfo->attr->extra;
691 if (ae && ae->ecommunity)
692 {
693 if (ecomm)
694 {
695 ecommerge = ecommunity_merge (ecomm, ae->ecommunity);
696 ecomm = ecommunity_uniq_sort (ecommerge);
fac3c245 697 ecommunity_free (&ecommerge);
0b597ef0
JB
698 }
699 else
700 ecomm = ecommunity_dup (ae->ecommunity);
701 }
702 }
703
704 attr.aspath = aspath;
705 attr.origin = origin;
706 if (community)
707 {
708 attr.community = community;
709 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
710 }
711 if (ecomm)
712 {
713 ae = bgp_attr_extra_get (&attr);
714 ae->ecommunity = ecomm;
715 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
716 }
717
718 /* Zap multipath attr nexthop so we set nexthop to self */
719 attr.nexthop.s_addr = 0;
720#ifdef HAVE_IPV6
721 if (attr.extra)
722 memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr));
723#endif /* HAVE_IPV6 */
724
725 /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */
726
727 new_attr = bgp_attr_intern (&attr);
728 bgp_attr_extra_free (&attr);
729
730 if (new_attr != bgp_info_mpath_attr (new_best))
731 {
732 if ((old_attr = bgp_info_mpath_attr (new_best)))
fac3c245 733 bgp_attr_unintern (&old_attr);
0b597ef0
JB
734 bgp_info_mpath_attr_set (new_best, new_attr);
735 SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED);
736 }
737 else
fac3c245 738 bgp_attr_unintern (&new_attr);
0b597ef0 739}