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