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