]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_mpath.c
lib: add flowspec safi to identitiy ref parsing
[mirror_frr.git] / bgpd / bgp_mpath.c
CommitLineData
8ef0791c 1/*
165b5fff
JB
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 *
896014f4
DL
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
165b5fff
JB
20 */
21
22#include <zebra.h>
23
24#include "command.h"
96450faf
JB
25#include "prefix.h"
26#include "linklist.h"
27#include "sockunion.h"
de8d5dff 28#include "memory.h"
3f9c7369 29#include "queue.h"
039f3a34 30#include "filter.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"
57d187bc 40#include "bgpd/bgp_lcommunity.h"
165b5fff
JB
41#include "bgpd/bgp_mpath.h"
42
43/*
44 * bgp_maximum_paths_set
45 *
46 * Record maximum-paths configuration for BGP instance
47 */
d62a17ae 48int bgp_maximum_paths_set(struct bgp *bgp, afi_t afi, safi_t safi, int peertype,
d7c0a89a 49 uint16_t maxpaths, uint16_t options)
165b5fff 50{
d62a17ae 51 if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
52 return -1;
53
54 switch (peertype) {
55 case BGP_PEER_IBGP:
56 bgp->maxpaths[afi][safi].maxpaths_ibgp = maxpaths;
57 bgp->maxpaths[afi][safi].ibgp_flags |= options;
58 break;
59 case BGP_PEER_EBGP:
60 bgp->maxpaths[afi][safi].maxpaths_ebgp = maxpaths;
61 break;
62 default:
63 return -1;
64 }
65
66 return 0;
165b5fff
JB
67}
68
69/*
70 * bgp_maximum_paths_unset
71 *
72 * Remove maximum-paths configuration from BGP instance
73 */
d62a17ae 74int bgp_maximum_paths_unset(struct bgp *bgp, afi_t afi, safi_t safi,
75 int peertype)
165b5fff 76{
d62a17ae 77 if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX))
78 return -1;
79
80 switch (peertype) {
81 case BGP_PEER_IBGP:
82 bgp->maxpaths[afi][safi].maxpaths_ibgp = multipath_num;
83 bgp->maxpaths[afi][safi].ibgp_flags = 0;
84 break;
85 case BGP_PEER_EBGP:
86 bgp->maxpaths[afi][safi].maxpaths_ebgp = multipath_num;
87 break;
88 default:
89 return -1;
90 }
91
92 return 0;
165b5fff 93}
96450faf 94
194a4f2c
DW
95/*
96 * bgp_interface_same
97 *
98 * Return true if ifindex for ifp1 and ifp2 are the same, else return false.
99 */
100static int bgp_interface_same(struct interface *ifp1, struct interface *ifp2)
101{
102 if (!ifp1 && !ifp2)
103 return 1;
104
105 if (!ifp1 && ifp2)
106 return 0;
107
108 if (ifp1 && !ifp2)
109 return 0;
110
111 return (ifp1->ifindex == ifp2->ifindex);
112}
113
114
96450faf 115/*
18ee8310 116 * bgp_path_info_nexthop_cmp
96450faf
JB
117 *
118 * Compare the nexthops of two paths. Return value is less than, equal to,
40381db7
DS
119 * or greater than zero if bpi1 is respectively less than, equal to,
120 * or greater than bpi2.
96450faf 121 */
40381db7
DS
122int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1,
123 struct bgp_path_info *bpi2)
96450faf 124{
d62a17ae 125 int compare;
05a38c0c 126 struct in6_addr addr1, addr2;
d62a17ae 127
40381db7 128 compare = IPV4_ADDR_CMP(&bpi1->attr->nexthop, &bpi2->attr->nexthop);
d62a17ae 129 if (!compare) {
40381db7
DS
130 if (bpi1->attr->mp_nexthop_len == bpi2->attr->mp_nexthop_len) {
131 switch (bpi1->attr->mp_nexthop_len) {
d62a17ae 132 case BGP_ATTR_NHLEN_IPV4:
133 case BGP_ATTR_NHLEN_VPNV4:
134 compare = IPV4_ADDR_CMP(
40381db7
DS
135 &bpi1->attr->mp_nexthop_global_in,
136 &bpi2->attr->mp_nexthop_global_in);
d62a17ae 137 break;
138 case BGP_ATTR_NHLEN_IPV6_GLOBAL:
139 case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
140 compare = IPV6_ADDR_CMP(
40381db7
DS
141 &bpi1->attr->mp_nexthop_global,
142 &bpi2->attr->mp_nexthop_global);
d62a17ae 143 break;
144 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
40381db7
DS
145 addr1 = (bpi1->attr->mp_nexthop_prefer_global)
146 ? bpi1->attr->mp_nexthop_global
147 : bpi1->attr->mp_nexthop_local;
148 addr2 = (bpi2->attr->mp_nexthop_prefer_global)
149 ? bpi2->attr->mp_nexthop_global
150 : bpi2->attr->mp_nexthop_local;
151
152 if (!bpi1->attr->mp_nexthop_prefer_global
153 && !bpi2->attr->mp_nexthop_prefer_global)
996c9314 154 compare = !bgp_interface_same(
40381db7
DS
155 bpi1->peer->ifp,
156 bpi2->peer->ifp);
194a4f2c 157
d62a17ae 158 if (!compare)
05a38c0c 159 compare = IPV6_ADDR_CMP(&addr1, &addr2);
d62a17ae 160 break;
161 }
162 }
163
164 /* This can happen if one IPv6 peer sends you global and
165 * link-local
166 * nexthops but another IPv6 peer only sends you global
167 */
40381db7
DS
168 else if (bpi1->attr->mp_nexthop_len
169 == BGP_ATTR_NHLEN_IPV6_GLOBAL
170 || bpi1->attr->mp_nexthop_len
d62a17ae 171 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
40381db7
DS
172 compare = IPV6_ADDR_CMP(&bpi1->attr->mp_nexthop_global,
173 &bpi2->attr->mp_nexthop_global);
d62a17ae 174 if (!compare) {
40381db7
DS
175 if (bpi1->attr->mp_nexthop_len
176 < bpi2->attr->mp_nexthop_len)
d62a17ae 177 compare = -1;
178 else
179 compare = 1;
180 }
181 }
182 }
183
184 return compare;
96450faf
JB
185}
186
187/*
18ee8310 188 * bgp_path_info_mpath_cmp
96450faf
JB
189 *
190 * This function determines our multipath list ordering. By ordering
191 * the list we can deterministically select which paths are included
192 * in the multipath set. The ordering also helps in detecting changes
193 * in the multipath selection so we can detect whether to send an
194 * update to zebra.
195 *
196 * The order of paths is determined first by received nexthop, and then
197 * by peer address if the nexthops are the same.
198 */
18ee8310 199static int bgp_path_info_mpath_cmp(void *val1, void *val2)
96450faf 200{
40381db7 201 struct bgp_path_info *bpi1, *bpi2;
d62a17ae 202 int compare;
203
40381db7
DS
204 bpi1 = val1;
205 bpi2 = val2;
d62a17ae 206
40381db7 207 compare = bgp_path_info_nexthop_cmp(bpi1, bpi2);
d62a17ae 208
209 if (!compare) {
40381db7 210 if (!bpi1->peer->su_remote && !bpi2->peer->su_remote)
d62a17ae 211 compare = 0;
40381db7 212 else if (!bpi1->peer->su_remote)
d62a17ae 213 compare = 1;
40381db7 214 else if (!bpi2->peer->su_remote)
d62a17ae 215 compare = -1;
216 else
40381db7
DS
217 compare = sockunion_cmp(bpi1->peer->su_remote,
218 bpi2->peer->su_remote);
d62a17ae 219 }
220
221 return compare;
96450faf
JB
222}
223
224/*
225 * bgp_mp_list_init
226 *
227 * Initialize the mp_list, which holds the list of multipaths
228 * selected by bgp_best_selection
229 */
d62a17ae 230void bgp_mp_list_init(struct list *mp_list)
96450faf 231{
d62a17ae 232 assert(mp_list);
233 memset(mp_list, 0, sizeof(struct list));
18ee8310 234 mp_list->cmp = bgp_path_info_mpath_cmp;
96450faf
JB
235}
236
237/*
238 * bgp_mp_list_clear
239 *
240 * Clears all entries out of the mp_list
241 */
d62a17ae 242void bgp_mp_list_clear(struct list *mp_list)
96450faf 243{
d62a17ae 244 assert(mp_list);
245 list_delete_all_node(mp_list);
96450faf
JB
246}
247
248/*
249 * bgp_mp_list_add
250 *
251 * Adds a multipath entry to the mp_list
252 */
4b7e6066 253void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo)
96450faf 254{
d62a17ae 255 assert(mp_list && mpinfo);
256 listnode_add_sort(mp_list, mpinfo);
96450faf 257}
de8d5dff
JB
258
259/*
18ee8310 260 * bgp_path_info_mpath_new
de8d5dff 261 *
18ee8310 262 * Allocate and zero memory for a new bgp_path_info_mpath element
de8d5dff 263 */
18ee8310 264static struct bgp_path_info_mpath *bgp_path_info_mpath_new(void)
de8d5dff 265{
4b7e6066
DS
266 struct bgp_path_info_mpath *new_mpath;
267 new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO,
268 sizeof(struct bgp_path_info_mpath));
d62a17ae 269 return new_mpath;
de8d5dff
JB
270}
271
272/*
18ee8310 273 * bgp_path_info_mpath_free
de8d5dff 274 *
18ee8310 275 * Release resources for a bgp_path_info_mpath element and zero out pointer
de8d5dff 276 */
18ee8310 277void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath)
de8d5dff 278{
d62a17ae 279 if (mpath && *mpath) {
280 if ((*mpath)->mp_attr)
281 bgp_attr_unintern(&(*mpath)->mp_attr);
282 XFREE(MTYPE_BGP_MPATH_INFO, *mpath);
d62a17ae 283 }
de8d5dff
JB
284}
285
286/*
18ee8310 287 * bgp_path_info_mpath_get
de8d5dff 288 *
18ee8310 289 * Fetch the mpath element for the given bgp_path_info. Used for
de8d5dff
JB
290 * doing lazy allocation.
291 */
4b7e6066 292static struct bgp_path_info_mpath *
9b6d8fcf 293bgp_path_info_mpath_get(struct bgp_path_info *path)
de8d5dff 294{
4b7e6066 295 struct bgp_path_info_mpath *mpath;
fa3bf3a2
MS
296
297 if (!path)
298 return NULL;
299
9b6d8fcf 300 if (!path->mpath) {
18ee8310 301 mpath = bgp_path_info_mpath_new();
d62a17ae 302 if (!mpath)
303 return NULL;
9b6d8fcf
DS
304 path->mpath = mpath;
305 mpath->mp_info = path;
d62a17ae 306 }
9b6d8fcf 307 return path->mpath;
de8d5dff
JB
308}
309
310/*
18ee8310 311 * bgp_path_info_mpath_enqueue
de8d5dff
JB
312 *
313 * Enqueue a path onto the multipath list given the previous multipath
314 * list entry
315 */
18ee8310 316static void bgp_path_info_mpath_enqueue(struct bgp_path_info *prev_info,
9b6d8fcf 317 struct bgp_path_info *path)
de8d5dff 318{
4b7e6066 319 struct bgp_path_info_mpath *prev, *mpath;
de8d5dff 320
18ee8310 321 prev = bgp_path_info_mpath_get(prev_info);
9b6d8fcf 322 mpath = bgp_path_info_mpath_get(path);
d62a17ae 323 if (!prev || !mpath)
324 return;
de8d5dff 325
d62a17ae 326 mpath->mp_next = prev->mp_next;
327 mpath->mp_prev = prev;
328 if (prev->mp_next)
329 prev->mp_next->mp_prev = mpath;
330 prev->mp_next = mpath;
de8d5dff 331
9b6d8fcf 332 SET_FLAG(path->flags, BGP_PATH_MULTIPATH);
de8d5dff
JB
333}
334
335/*
18ee8310 336 * bgp_path_info_mpath_dequeue
de8d5dff
JB
337 *
338 * Remove a path from the multipath list
339 */
9b6d8fcf 340void bgp_path_info_mpath_dequeue(struct bgp_path_info *path)
de8d5dff 341{
9b6d8fcf 342 struct bgp_path_info_mpath *mpath = path->mpath;
d62a17ae 343 if (!mpath)
344 return;
345 if (mpath->mp_prev)
346 mpath->mp_prev->mp_next = mpath->mp_next;
347 if (mpath->mp_next)
348 mpath->mp_next->mp_prev = mpath->mp_prev;
349 mpath->mp_next = mpath->mp_prev = NULL;
9b6d8fcf 350 UNSET_FLAG(path->flags, BGP_PATH_MULTIPATH);
de8d5dff
JB
351}
352
353/*
18ee8310 354 * bgp_path_info_mpath_next
de8d5dff 355 *
18ee8310 356 * Given a bgp_path_info, return the next multipath entry
de8d5dff 357 */
9b6d8fcf 358struct bgp_path_info *bgp_path_info_mpath_next(struct bgp_path_info *path)
de8d5dff 359{
9b6d8fcf 360 if (!path->mpath || !path->mpath->mp_next)
d62a17ae 361 return NULL;
9b6d8fcf 362 return path->mpath->mp_next->mp_info;
de8d5dff
JB
363}
364
365/*
18ee8310 366 * bgp_path_info_mpath_first
de8d5dff 367 *
18ee8310 368 * Given bestpath bgp_path_info, return the first multipath entry.
de8d5dff 369 */
9b6d8fcf 370struct bgp_path_info *bgp_path_info_mpath_first(struct bgp_path_info *path)
de8d5dff 371{
9b6d8fcf 372 return bgp_path_info_mpath_next(path);
de8d5dff
JB
373}
374
375/*
18ee8310 376 * bgp_path_info_mpath_count
de8d5dff 377 *
18ee8310 378 * Given the bestpath bgp_path_info, return the number of multipath entries
de8d5dff 379 */
9b6d8fcf 380uint32_t bgp_path_info_mpath_count(struct bgp_path_info *path)
de8d5dff 381{
9b6d8fcf 382 if (!path->mpath)
d62a17ae 383 return 0;
9b6d8fcf 384 return path->mpath->mp_count;
de8d5dff
JB
385}
386
387/*
18ee8310 388 * bgp_path_info_mpath_count_set
de8d5dff
JB
389 *
390 * Sets the count of multipaths into bestpath's mpath element
391 */
9b6d8fcf 392static void bgp_path_info_mpath_count_set(struct bgp_path_info *path,
50346a98 393 uint16_t count)
de8d5dff 394{
4b7e6066 395 struct bgp_path_info_mpath *mpath;
9b6d8fcf 396 if (!count && !path->mpath)
d62a17ae 397 return;
9b6d8fcf 398 mpath = bgp_path_info_mpath_get(path);
d62a17ae 399 if (!mpath)
400 return;
401 mpath->mp_count = count;
de8d5dff
JB
402}
403
42d436cf 404/*
405 * bgp_path_info_mpath_lb_update
406 *
407 * Update cumulative info related to link-bandwidth
408 */
409static void bgp_path_info_mpath_lb_update(struct bgp_path_info *path, bool set,
410 bool all_paths_lb, uint64_t cum_bw)
411{
412 struct bgp_path_info_mpath *mpath;
413
414 if ((mpath = path->mpath) == NULL) {
415 if (!set)
416 return;
417 mpath = bgp_path_info_mpath_get(path);
418 if (!mpath)
419 return;
420 }
421 if (set) {
f7e1c681 422 if (cum_bw)
423 SET_FLAG(mpath->mp_flags, BGP_MP_LB_PRESENT);
424 else
425 UNSET_FLAG(mpath->mp_flags, BGP_MP_LB_PRESENT);
42d436cf 426 if (all_paths_lb)
427 SET_FLAG(mpath->mp_flags, BGP_MP_LB_ALL);
428 else
429 UNSET_FLAG(mpath->mp_flags, BGP_MP_LB_ALL);
430 mpath->cum_bw = cum_bw;
431 } else {
432 mpath->mp_flags = 0;
433 mpath->cum_bw = 0;
434 }
435}
436
0b597ef0 437/*
18ee8310 438 * bgp_path_info_mpath_attr
0b597ef0 439 *
18ee8310 440 * Given bestpath bgp_path_info, return aggregated attribute set used
0b597ef0
JB
441 * for advertising the multipath route
442 */
9b6d8fcf 443struct attr *bgp_path_info_mpath_attr(struct bgp_path_info *path)
0b597ef0 444{
9b6d8fcf 445 if (!path->mpath)
d62a17ae 446 return NULL;
9b6d8fcf 447 return path->mpath->mp_attr;
0b597ef0
JB
448}
449
4e30bc2b 450/*
451 * bgp_path_info_chkwtd
452 *
f7e1c681 453 * Return if we should attempt to do weighted ECMP or not
454 * The path passed in is the bestpath.
4e30bc2b 455 */
f7e1c681 456bool bgp_path_info_mpath_chkwtd(struct bgp *bgp, struct bgp_path_info *path)
4e30bc2b 457{
f7e1c681 458 /* Check if told to ignore weights or not multipath */
459 if (bgp->lb_handling == BGP_LINK_BW_IGNORE_BW || !path->mpath)
4e30bc2b 460 return false;
f7e1c681 461
462 /* All paths in multipath should have associated weight (bandwidth)
463 * unless told explicitly otherwise.
464 */
465 if (bgp->lb_handling != BGP_LINK_BW_SKIP_MISSING &&
466 bgp->lb_handling != BGP_LINK_BW_DEFWT_4_MISSING)
467 return (path->mpath->mp_flags & BGP_MP_LB_ALL);
468
469 /* At least one path should have bandwidth. */
470 return (path->mpath->mp_flags & BGP_MP_LB_PRESENT);
4e30bc2b 471}
472
473/*
474 * bgp_path_info_mpath_attr
475 *
476 * Given bestpath bgp_path_info, return cumulative bandwidth
477 * computed for all multipaths with bandwidth info
478 */
479uint64_t bgp_path_info_mpath_cumbw(struct bgp_path_info *path)
480{
481 if (!path->mpath)
482 return 0;
483 return path->mpath->cum_bw;
484}
485
0b597ef0 486/*
18ee8310 487 * bgp_path_info_mpath_attr_set
0b597ef0
JB
488 *
489 * Sets the aggregated attribute into bestpath's mpath element
490 */
9b6d8fcf 491static void bgp_path_info_mpath_attr_set(struct bgp_path_info *path,
18ee8310 492 struct attr *attr)
0b597ef0 493{
4b7e6066 494 struct bgp_path_info_mpath *mpath;
9b6d8fcf 495 if (!attr && !path->mpath)
d62a17ae 496 return;
9b6d8fcf 497 mpath = bgp_path_info_mpath_get(path);
d62a17ae 498 if (!mpath)
499 return;
500 mpath->mp_attr = attr;
0b597ef0
JB
501}
502
de8d5dff 503/*
18ee8310 504 * bgp_path_info_mpath_update
de8d5dff
JB
505 *
506 * Compare and sync up the multipath list with the mp_list generated by
507 * bgp_best_selection
508 */
9bcb3eef 509void bgp_path_info_mpath_update(struct bgp_dest *dest,
18ee8310
DS
510 struct bgp_path_info *new_best,
511 struct bgp_path_info *old_best,
512 struct list *mp_list,
513 struct bgp_maxpaths_cfg *mpath_cfg)
de8d5dff 514{
d7c0a89a 515 uint16_t maxpaths, mpath_count, old_mpath_count;
42d436cf 516 uint32_t bwval;
b1875e65 517 uint64_t cum_bw, old_cum_bw;
d62a17ae 518 struct listnode *mp_node, *mp_next_node;
4b7e6066 519 struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath;
d62a17ae 520 int mpath_changed, debug;
b54892e0 521 char nh_buf[2][INET6_ADDRSTRLEN];
42d436cf 522 bool all_paths_lb;
d62a17ae 523 char path_buf[PATH_ADDPATH_STR_BUFFER];
524
525 mpath_changed = 0;
526 maxpaths = multipath_num;
527 mpath_count = 0;
528 cur_mpath = NULL;
529 old_mpath_count = 0;
b1875e65 530 old_cum_bw = cum_bw = 0;
d62a17ae 531 prev_mpath = new_best;
532 mp_node = listhead(mp_list);
9bcb3eef 533 debug = bgp_debug_bestpath(dest);
d62a17ae 534
d62a17ae 535 if (new_best) {
536 mpath_count++;
537 if (new_best != old_best)
18ee8310 538 bgp_path_info_mpath_dequeue(new_best);
d62a17ae 539 maxpaths = (new_best->peer->sort == BGP_PEER_IBGP)
540 ? mpath_cfg->maxpaths_ibgp
541 : mpath_cfg->maxpaths_ebgp;
542 }
543
544 if (old_best) {
18ee8310
DS
545 cur_mpath = bgp_path_info_mpath_first(old_best);
546 old_mpath_count = bgp_path_info_mpath_count(old_best);
b1875e65 547 old_cum_bw = bgp_path_info_mpath_cumbw(old_best);
18ee8310 548 bgp_path_info_mpath_count_set(old_best, 0);
42d436cf 549 bgp_path_info_mpath_lb_update(old_best, false, false, 0);
18ee8310 550 bgp_path_info_mpath_dequeue(old_best);
d62a17ae 551 }
552
553 if (debug)
554 zlog_debug(
b1875e65 555 "%pRN: starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw u%" PRIu64,
9bcb3eef
DS
556 bgp_dest_to_rnode(dest),
557 new_best ? new_best->peer->host : "NONE",
b1875e65 558 mp_list ? listcount(mp_list) : 0,
559 old_mpath_count, old_cum_bw);
d62a17ae 560
561 /*
562 * We perform an ordered walk through both lists in parallel.
563 * The reason for the ordered walk is that if there are paths
564 * that were previously multipaths and are still multipaths, the walk
565 * should encounter them in both lists at the same time. Otherwise
566 * there will be paths that are in one list or another, and we
567 * will deal with these separately.
568 *
569 * Note that new_best might be somewhere in the mp_list, so we need
570 * to skip over it
571 */
42d436cf 572 all_paths_lb = true; /* We'll reset if any path doesn't have LB. */
d62a17ae 573 while (mp_node || cur_mpath) {
4b7e6066 574 struct bgp_path_info *tmp_info;
d62a17ae 575
576 /*
577 * We can bail out of this loop if all existing paths on the
578 * multipath list have been visited (for cleanup purposes) and
579 * the maxpath requirement is fulfulled
580 */
581 if (!cur_mpath && (mpath_count >= maxpaths))
582 break;
583
584 mp_next_node = mp_node ? listnextnode(mp_node) : NULL;
18ee8310
DS
585 next_mpath =
586 cur_mpath ? bgp_path_info_mpath_next(cur_mpath) : NULL;
d62a17ae 587 tmp_info = mp_node ? listgetdata(mp_node) : NULL;
588
589 if (debug)
590 zlog_debug(
b54892e0 591 "%pRN: comparing candidate %s with existing mpath %s",
9bcb3eef 592 bgp_dest_to_rnode(dest),
d62a17ae 593 tmp_info ? tmp_info->peer->host : "NONE",
594 cur_mpath ? cur_mpath->peer->host : "NONE");
595
596 /*
597 * If equal, the path was a multipath and is still a multipath.
598 * Insert onto new multipath list if maxpaths allows.
599 */
600 if (mp_node && (listgetdata(mp_node) == cur_mpath)) {
601 list_delete_node(mp_list, mp_node);
18ee8310 602 bgp_path_info_mpath_dequeue(cur_mpath);
d62a17ae 603 if ((mpath_count < maxpaths)
fa3bf3a2 604 && prev_mpath
18ee8310
DS
605 && bgp_path_info_nexthop_cmp(prev_mpath,
606 cur_mpath)) {
607 bgp_path_info_mpath_enqueue(prev_mpath,
608 cur_mpath);
d62a17ae 609 prev_mpath = cur_mpath;
610 mpath_count++;
42d436cf 611 if (ecommunity_linkbw_present(
612 cur_mpath->attr->ecommunity, &bwval))
613 cum_bw += bwval;
614 else
615 all_paths_lb = false;
d62a17ae 616 if (debug) {
18ee8310 617 bgp_path_info_path_with_addpath_rx_str(
d62a17ae 618 cur_mpath, path_buf);
619 zlog_debug(
b54892e0 620 "%pRN: %s is still multipath, cur count %d",
9bcb3eef
DS
621 bgp_dest_to_rnode(dest),
622 path_buf, mpath_count);
d62a17ae 623 }
624 } else {
625 mpath_changed = 1;
626 if (debug) {
18ee8310 627 bgp_path_info_path_with_addpath_rx_str(
d62a17ae 628 cur_mpath, path_buf);
629 zlog_debug(
b54892e0 630 "%pRN: remove mpath %s nexthop %s, cur count %d",
9bcb3eef
DS
631 bgp_dest_to_rnode(dest),
632 path_buf,
d62a17ae 633 inet_ntop(AF_INET,
634 &cur_mpath->attr
635 ->nexthop,
636 nh_buf[0],
637 sizeof(nh_buf[0])),
638 mpath_count);
639 }
640 }
641 mp_node = mp_next_node;
642 cur_mpath = next_mpath;
643 continue;
644 }
645
646 if (cur_mpath
647 && (!mp_node
18ee8310
DS
648 || (bgp_path_info_mpath_cmp(cur_mpath,
649 listgetdata(mp_node))
d62a17ae 650 < 0))) {
651 /*
652 * If here, we have an old multipath and either the
653 * mp_list
654 * is finished or the next mp_node points to a later
655 * multipath, so we need to purge this path from the
656 * multipath list
657 */
18ee8310 658 bgp_path_info_mpath_dequeue(cur_mpath);
d62a17ae 659 mpath_changed = 1;
660 if (debug) {
18ee8310
DS
661 bgp_path_info_path_with_addpath_rx_str(
662 cur_mpath, path_buf);
d62a17ae 663 zlog_debug(
b54892e0 664 "%pRN: remove mpath %s nexthop %s, cur count %d",
9bcb3eef 665 bgp_dest_to_rnode(dest), path_buf,
d62a17ae 666 inet_ntop(AF_INET,
667 &cur_mpath->attr->nexthop,
668 nh_buf[0], sizeof(nh_buf[0])),
669 mpath_count);
670 }
671 cur_mpath = next_mpath;
672 } else {
673 /*
674 * If here, we have a path on the mp_list that was not
675 * previously
676 * a multipath (due to non-equivalance or maxpaths
677 * exceeded),
678 * or the matching multipath is sorted later in the
679 * multipath
680 * list. Before we enqueue the path on the new multipath
681 * list,
682 * make sure its not on the old_best multipath list or
683 * referenced
684 * via next_mpath:
685 * - If next_mpath points to this new path, update
686 * next_mpath to
687 * point to the multipath after this one
688 * - Dequeue the path from the multipath list just to
689 * make sure
690 */
691 new_mpath = listgetdata(mp_node);
692 list_delete_node(mp_list, mp_node);
2165e2ea
QY
693 assert(new_mpath);
694 assert(prev_mpath);
d62a17ae 695 if ((mpath_count < maxpaths) && (new_mpath != new_best)
18ee8310
DS
696 && bgp_path_info_nexthop_cmp(prev_mpath,
697 new_mpath)) {
18ee8310 698 bgp_path_info_mpath_dequeue(new_mpath);
d62a17ae 699
18ee8310
DS
700 bgp_path_info_mpath_enqueue(prev_mpath,
701 new_mpath);
d62a17ae 702 prev_mpath = new_mpath;
703 mpath_changed = 1;
704 mpath_count++;
42d436cf 705 if (ecommunity_linkbw_present(
706 new_mpath->attr->ecommunity, &bwval))
707 cum_bw += bwval;
708 else
709 all_paths_lb = false;
d62a17ae 710 if (debug) {
18ee8310 711 bgp_path_info_path_with_addpath_rx_str(
d62a17ae 712 new_mpath, path_buf);
713 zlog_debug(
b54892e0 714 "%pRN: add mpath %s nexthop %s, cur count %d",
9bcb3eef
DS
715 bgp_dest_to_rnode(dest),
716 path_buf,
d62a17ae 717 inet_ntop(AF_INET,
718 &new_mpath->attr
719 ->nexthop,
720 nh_buf[0],
721 sizeof(nh_buf[0])),
722 mpath_count);
723 }
724 }
725 mp_node = mp_next_node;
726 }
727 }
728
729 if (new_best) {
42d436cf 730 bgp_path_info_mpath_count_set(new_best, mpath_count - 1);
731 if (mpath_count <= 1 ||
732 !ecommunity_linkbw_present(
733 new_best->attr->ecommunity, &bwval))
734 all_paths_lb = false;
735 else
736 cum_bw += bwval;
737 bgp_path_info_mpath_lb_update(new_best, true,
738 all_paths_lb, cum_bw);
739
d62a17ae 740 if (debug)
741 zlog_debug(
3efd0893 742 "%pRN: New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw u%" PRIu64,
9bcb3eef 743 bgp_dest_to_rnode(dest), mpath_count,
42d436cf 744 mpath_changed ? "YES" : "NO",
745 all_paths_lb, cum_bw);
d62a17ae 746
d62a17ae 747 if (mpath_changed
18ee8310 748 || (bgp_path_info_mpath_count(new_best) != old_mpath_count))
1defdda8 749 SET_FLAG(new_best->flags, BGP_PATH_MULTIPATH_CHG);
b1875e65 750 if ((mpath_count - 1) != old_mpath_count ||
751 old_cum_bw != cum_bw)
752 SET_FLAG(new_best->flags, BGP_PATH_LINK_BW_CHG);
d62a17ae 753 }
de8d5dff 754}
6918e74b
JB
755
756/*
757 * bgp_mp_dmed_deselect
758 *
1defdda8 759 * Clean up multipath information for BGP_PATH_DMED_SELECTED path that
6918e74b
JB
760 * is not selected as best path
761 */
4b7e6066 762void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best)
6918e74b 763{
4b7e6066 764 struct bgp_path_info *mpinfo, *mpnext;
6918e74b 765
d62a17ae 766 if (!dmed_best)
767 return;
6918e74b 768
18ee8310 769 for (mpinfo = bgp_path_info_mpath_first(dmed_best); mpinfo;
d62a17ae 770 mpinfo = mpnext) {
18ee8310
DS
771 mpnext = bgp_path_info_mpath_next(mpinfo);
772 bgp_path_info_mpath_dequeue(mpinfo);
d62a17ae 773 }
6918e74b 774
18ee8310 775 bgp_path_info_mpath_count_set(dmed_best, 0);
1defdda8 776 UNSET_FLAG(dmed_best->flags, BGP_PATH_MULTIPATH_CHG);
b1875e65 777 UNSET_FLAG(dmed_best->flags, BGP_PATH_LINK_BW_CHG);
831600c3 778 assert(bgp_path_info_mpath_first(dmed_best) == NULL);
6918e74b 779}
0b597ef0
JB
780
781/*
18ee8310 782 * bgp_path_info_mpath_aggregate_update
0b597ef0
JB
783 *
784 * Set the multipath aggregate attribute. We need to see if the
785 * aggregate has changed and then set the ATTR_CHANGED flag on the
786 * bestpath info so that a peer update will be generated. The
787 * change is detected by generating the current attribute,
788 * interning it, and then comparing the interned pointer with the
789 * current value. We can skip this generate/compare step if there
790 * is no change in multipath selection and no attribute change in
791 * any multipath.
792 */
18ee8310
DS
793void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best,
794 struct bgp_path_info *old_best)
0b597ef0 795{
4b7e6066 796 struct bgp_path_info *mpinfo;
d62a17ae 797 struct aspath *aspath;
798 struct aspath *asmerge;
799 struct attr *new_attr, *old_attr;
d7c0a89a 800 uint8_t origin;
d62a17ae 801 struct community *community, *commerge;
802 struct ecommunity *ecomm, *ecommerge;
803 struct lcommunity *lcomm, *lcommerge;
804 struct attr attr = {0};
805
806 if (old_best && (old_best != new_best)
18ee8310 807 && (old_attr = bgp_path_info_mpath_attr(old_best))) {
d62a17ae 808 bgp_attr_unintern(&old_attr);
18ee8310 809 bgp_path_info_mpath_attr_set(old_best, NULL);
d62a17ae 810 }
811
812 if (!new_best)
813 return;
814
18ee8310
DS
815 if (!bgp_path_info_mpath_count(new_best)) {
816 if ((new_attr = bgp_path_info_mpath_attr(new_best))) {
d62a17ae 817 bgp_attr_unintern(&new_attr);
18ee8310 818 bgp_path_info_mpath_attr_set(new_best, NULL);
1defdda8 819 SET_FLAG(new_best->flags, BGP_PATH_ATTR_CHANGED);
d62a17ae 820 }
821 return;
822 }
823
6f4f49b2 824 attr = *new_best->attr;
d62a17ae 825
892fedb6
DA
826 if (new_best->peer
827 && CHECK_FLAG(new_best->peer->bgp->flags,
828 BGP_FLAG_MULTIPATH_RELAX_AS_SET)) {
d62a17ae 829
830 /* aggregate attribute from multipath constituents */
831 aspath = aspath_dup(attr.aspath);
832 origin = attr.origin;
833 community =
834 attr.community ? community_dup(attr.community) : NULL;
835 ecomm = (attr.ecommunity) ? ecommunity_dup(attr.ecommunity)
836 : NULL;
837 lcomm = (attr.lcommunity) ? lcommunity_dup(attr.lcommunity)
838 : NULL;
839
18ee8310
DS
840 for (mpinfo = bgp_path_info_mpath_first(new_best); mpinfo;
841 mpinfo = bgp_path_info_mpath_next(mpinfo)) {
d62a17ae 842 asmerge =
843 aspath_aggregate(aspath, mpinfo->attr->aspath);
844 aspath_free(aspath);
845 aspath = asmerge;
846
847 if (origin < mpinfo->attr->origin)
848 origin = mpinfo->attr->origin;
849
850 if (mpinfo->attr->community) {
851 if (community) {
852 commerge = community_merge(
853 community,
854 mpinfo->attr->community);
855 community =
856 community_uniq_sort(commerge);
3c1f53de 857 community_free(&commerge);
d62a17ae 858 } else
859 community = community_dup(
860 mpinfo->attr->community);
861 }
862
863 if (mpinfo->attr->ecommunity) {
864 if (ecomm) {
865 ecommerge = ecommunity_merge(
866 ecomm,
867 mpinfo->attr->ecommunity);
868 ecomm = ecommunity_uniq_sort(ecommerge);
869 ecommunity_free(&ecommerge);
870 } else
871 ecomm = ecommunity_dup(
872 mpinfo->attr->ecommunity);
873 }
874 if (mpinfo->attr->lcommunity) {
875 if (lcomm) {
876 lcommerge = lcommunity_merge(
877 lcomm,
878 mpinfo->attr->lcommunity);
879 lcomm = lcommunity_uniq_sort(lcommerge);
880 lcommunity_free(&lcommerge);
881 } else
882 lcomm = lcommunity_dup(
883 mpinfo->attr->lcommunity);
884 }
885 }
886
887 attr.aspath = aspath;
888 attr.origin = origin;
889 if (community) {
890 attr.community = community;
891 attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
892 }
893 if (ecomm) {
894 attr.ecommunity = ecomm;
895 attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
896 }
44f12f20
RW
897 if (lcomm) {
898 attr.lcommunity = lcomm;
899 attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES);
900 }
d62a17ae 901
902 /* Zap multipath attr nexthop so we set nexthop to self */
975a328e 903 attr.nexthop.s_addr = INADDR_ANY;
d62a17ae 904 memset(&attr.mp_nexthop_global, 0, sizeof(struct in6_addr));
905
906 /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */
907 }
908
909 new_attr = bgp_attr_intern(&attr);
910
18ee8310
DS
911 if (new_attr != bgp_path_info_mpath_attr(new_best)) {
912 if ((old_attr = bgp_path_info_mpath_attr(new_best)))
d62a17ae 913 bgp_attr_unintern(&old_attr);
18ee8310 914 bgp_path_info_mpath_attr_set(new_best, new_attr);
1defdda8 915 SET_FLAG(new_best->flags, BGP_PATH_ATTR_CHANGED);
d62a17ae 916 } else
917 bgp_attr_unintern(&new_attr);
0b597ef0 918}