1 /* $OpenBSD: rde_decide.c,v 1.103 2024/08/14 19:09:51 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 23 #include <string.h> 24 25 #include "bgpd.h" 26 #include "rde.h" 27 #include "log.h" 28 29 int prefix_cmp(struct prefix *, struct prefix *, int *); 30 void prefix_set_dmetric(struct prefix *, struct prefix *); 31 void prefix_insert(struct prefix *, struct prefix *, struct rib_entry *); 32 void prefix_remove(struct prefix *, struct rib_entry *); 33 /* 34 * Decision Engine RFC implementation: 35 * Phase 1: 36 * - calculate LOCAL_PREF if needed -- EBGP or IGP learnt routes 37 * - IBGP routes may either use LOCAL_PREF or the local system computes 38 * the degree of preference 39 * - If the route is ineligible, the route MAY NOT serve as an input to 40 * the next phase of route selection 41 * - if the route is eligible the computed value MUST be used as the 42 * LOCAL_PREF value in any IBGP readvertisement 43 * 44 * Phase 2: 45 * - If the NEXT_HOP attribute of a BGP route depicts an address that is 46 * not resolvable the BGP route MUST be excluded from the Phase 2 decision 47 * function. 48 * - If the AS_PATH attribute of a BGP route contains an AS loop, the BGP 49 * route should be excluded from the Phase 2 decision function. 50 * - The local BGP speaker identifies the route that has: 51 * a) the highest degree of preference of any route to the same set 52 * of destinations 53 * b) is the only route to that destination 54 * c) is selected as a result of the Phase 2 tie breaking rules 55 * - The local speaker MUST determine the immediate next-hop address from 56 * the NEXT_HOP attribute of the selected route. 57 * - If either the immediate next hop or the IGP cost to the NEXT_HOP changes, 58 * Phase 2 Route Selection MUST be performed again. 59 * 60 * Route Resolvability Condition 61 * - A route Rte1, referencing only the intermediate network address, is 62 * considered resolvable if the Routing Table contains at least one 63 * resolvable route Rte2 that matches Rte1's intermediate network address 64 * and is not recursively resolved through Rte1. 65 * - Routes referencing interfaces are considered resolvable if the state of 66 * the referenced interface is up and IP processing is enabled. 67 * 68 * Breaking Ties (Phase 2) 69 * 1. Remove from consideration all routes which are not tied for having the 70 * smallest number of AS numbers present in their AS_PATH attributes. 71 * Note, that when counting this number, an AS_SET counts as 1 72 * 2. Remove from consideration all routes which are not tied for having the 73 * lowest Origin number in their Origin attribute. 74 * 3. Remove from consideration routes with less-preferred MULTI_EXIT_DISC 75 * attributes. MULTI_EXIT_DISC is only comparable between routes learned 76 * from the same neighboring AS. 77 * 4. If at least one of the candidate routes was received via EBGP, 78 * remove from consideration all routes which were received via IBGP. 79 * 5. Remove from consideration any routes with less-preferred interior cost. 80 * If the NEXT_HOP hop for a route is reachable, but no cost can be 81 * determined, then this step should be skipped. 82 * 6. Remove from consideration all routes other than the route that was 83 * advertised by the BGP speaker whose BGP Identifier has the lowest value. 84 * 7. Prefer the route received from the lowest peer address. 85 * 86 * Phase 3: Route Dissemination 87 * - All routes in the Loc-RIB are processed into Adj-RIBs-Out according 88 * to configured policy. A route SHALL NOT be installed in the Adj-Rib-Out 89 * unless the destination and NEXT_HOP described by this route may be 90 * forwarded appropriately by the Routing Table. 91 */ 92 93 /* 94 * Decision Engine OUR implementation: 95 * The filtering is done first. The filtering calculates the preference and 96 * stores it in LOCAL_PREF (Phase 1). 97 * Ineligible routes are flagged as ineligible via nexthop_add(). 98 * Phase 3 is done together with Phase 2. 99 * In following cases a prefix needs to be reevaluated: 100 * - update of a prefix (prefix_update) 101 * - withdraw of a prefix (prefix_withdraw) 102 * - state change of the nexthop (nexthop-{in}validate) 103 * - state change of session (session down) 104 */ 105 106 /* 107 * Compare two prefixes with equal pt_entry. Returns an integer greater than or 108 * less than 0, according to whether the prefix p1 is more or less preferred 109 * than the prefix p2. p1 should be used for the new prefix and p2 for a 110 * already added prefix. The absolute value returned specifies the similarity 111 * of the prefixes. 112 * 1: prefixes differ because of validity 113 * 2: prefixes don't belong in any multipath set 114 * 3: prefixes belong only in the as-wide multipath set 115 * 4: prefixes belong in both the ecmp and as-wide multipath set 116 * TODO: maybe we also need a strict ecmp set that requires 117 * prefixes to e.g. equal ASPATH or equal neighbor-as (like for MED). 118 */ 119 int 120 prefix_cmp(struct prefix *p1, struct prefix *p2, int *testall) 121 { 122 struct rde_aspath *asp1, *asp2; 123 struct rde_peer *peer1, *peer2; 124 struct attr *a; 125 uint32_t p1id, p2id; 126 int p1cnt, p2cnt, i; 127 int rv = 1; 128 129 /* 130 * If a match happens before the MED check then the list is 131 * correctly sorted. If a match happens after MED then further 132 * elements may need to be checked to ensure that all paths 133 * which could affect this path were considered. This only 134 * matters for strict MED evaluation and in that case testall 135 * is set to 1. If the check happens to be on the MED check 136 * itself testall is set to 2. 137 */ 138 *testall = 0; 139 140 if (p1 == NULL) 141 return -rv; 142 if (p2 == NULL) 143 return rv; 144 145 asp1 = prefix_aspath(p1); 146 asp2 = prefix_aspath(p2); 147 peer1 = prefix_peer(p1); 148 peer2 = prefix_peer(p2); 149 150 /* 1. check if prefix is eligible a.k.a reachable */ 151 if (!prefix_eligible(p2)) 152 return rv; 153 if (!prefix_eligible(p1)) 154 return -rv; 155 156 /* bump rv, from here on prefix is considered valid */ 157 rv++; 158 159 /* 2. local preference of prefix, bigger is better */ 160 if (asp1->lpref > asp2->lpref) 161 return rv; 162 if (asp1->lpref < asp2->lpref) 163 return -rv; 164 165 /* 3. aspath count, the shorter the better */ 166 if (asp1->aspath->ascnt < asp2->aspath->ascnt) 167 return rv; 168 if (asp1->aspath->ascnt > asp2->aspath->ascnt) 169 return -rv; 170 171 /* 4. origin, the lower the better */ 172 if (asp1->origin < asp2->origin) 173 return rv; 174 if (asp1->origin > asp2->origin) 175 return -rv; 176 177 /* 178 * 5. MED decision 179 * Only comparable between the same neighboring AS or if 180 * 'rde med compare always' is set. In the first case 181 * set the testall flag since further elements need to be 182 * evaluated as well. 183 */ 184 if ((rde_decisionflags() & BGPD_FLAG_DECISION_MED_ALWAYS) || 185 aspath_neighbor(asp1->aspath) == aspath_neighbor(asp2->aspath)) { 186 if (!(rde_decisionflags() & BGPD_FLAG_DECISION_MED_ALWAYS)) 187 *testall = 2; 188 /* lowest value wins */ 189 if (asp1->med < asp2->med) 190 return rv; 191 if (asp1->med > asp2->med) 192 return -rv; 193 } 194 195 if (!(rde_decisionflags() & BGPD_FLAG_DECISION_MED_ALWAYS)) 196 *testall = 1; 197 198 /* 199 * 6. EBGP is cooler than IBGP 200 * It is absolutely important that the ebgp value in peer_config.ebgp 201 * is bigger than all other ones (IBGP, confederations) 202 */ 203 if (peer1->conf.ebgp != peer2->conf.ebgp) { 204 if (peer1->conf.ebgp) /* peer1 is EBGP other is lower */ 205 return rv; 206 else if (peer2->conf.ebgp) /* peer2 is EBGP */ 207 return -rv; 208 } 209 210 /* bump rv, as-wide multipath */ 211 rv++; 212 213 /* 214 * 7. local tie-breaker, this weight is here to tip equal long AS 215 * paths in one or the other direction. It happens more and more 216 * that AS paths are equally long and so traffic engineering needs 217 * a metric that weights a prefix at a very late stage in the 218 * decision process. 219 */ 220 if (asp1->weight > asp2->weight) 221 return rv; 222 if (asp1->weight < asp2->weight) 223 return -rv; 224 225 /* 8. nexthop costs. NOT YET -> IGNORE */ 226 227 /* bump rv, equal cost multipath */ 228 rv++; 229 230 /* 231 * 9. older route (more stable) wins but only if route-age 232 * evaluation is enabled. 233 */ 234 if (rde_decisionflags() & BGPD_FLAG_DECISION_ROUTEAGE) { 235 if (p1->lastchange < p2->lastchange) /* p1 is older */ 236 return rv; 237 if (p1->lastchange > p2->lastchange) 238 return -rv; 239 } 240 241 /* 10. lowest BGP Id wins, use ORIGINATOR_ID if present */ 242 if ((a = attr_optget(asp1, ATTR_ORIGINATOR_ID)) != NULL) { 243 memcpy(&p1id, a->data, sizeof(p1id)); 244 p1id = ntohl(p1id); 245 } else 246 p1id = peer1->remote_bgpid; 247 if ((a = attr_optget(asp2, ATTR_ORIGINATOR_ID)) != NULL) { 248 memcpy(&p2id, a->data, sizeof(p2id)); 249 p2id = ntohl(p2id); 250 } else 251 p2id = peer2->remote_bgpid; 252 if (p1id < p2id) 253 return rv; 254 if (p1id > p2id) 255 return -rv; 256 257 /* 11. compare CLUSTER_LIST length, shorter is better */ 258 p1cnt = p2cnt = 0; 259 if ((a = attr_optget(asp1, ATTR_CLUSTER_LIST)) != NULL) 260 p1cnt = a->len / sizeof(uint32_t); 261 if ((a = attr_optget(asp2, ATTR_CLUSTER_LIST)) != NULL) 262 p2cnt = a->len / sizeof(uint32_t); 263 if (p1cnt < p2cnt) 264 return rv; 265 if (p1cnt > p2cnt) 266 return -rv; 267 268 /* 12. lowest peer address wins (IPv4 is better than IPv6) */ 269 if (peer1->remote_addr.aid < peer2->remote_addr.aid) 270 return rv; 271 if (peer1->remote_addr.aid > peer2->remote_addr.aid) 272 return -rv; 273 switch (peer1->remote_addr.aid) { 274 case AID_INET: 275 i = memcmp(&peer1->remote_addr.v4, &peer2->remote_addr.v4, 276 sizeof(struct in_addr)); 277 break; 278 case AID_INET6: 279 i = memcmp(&peer1->remote_addr.v6, &peer2->remote_addr.v6, 280 sizeof(struct in6_addr)); 281 break; 282 default: 283 fatalx("%s: unknown af", __func__); 284 } 285 if (i < 0) 286 return rv; 287 if (i > 0) 288 return -rv; 289 290 /* RFC7911 does not specify this but something like this is needed. */ 291 /* 13. lowest path identifier wins */ 292 if (p1->path_id < p2->path_id) 293 return rv; 294 if (p1->path_id > p2->path_id) 295 return -rv; 296 297 fatalx("Uh, oh a politician in the decision process"); 298 } 299 300 /* 301 * set the dmetric value of np based on the return value of 302 * prefix_evaluate(pp, np) or set it to either PREFIX_DMETRIC_BEST 303 * or PREFIX_DMETRIC_INVALID for the first element. 304 */ 305 void 306 prefix_set_dmetric(struct prefix *pp, struct prefix *np) 307 { 308 int testall; 309 310 if (np != NULL) { 311 if (pp == NULL) 312 np->dmetric = prefix_eligible(np) ? 313 PREFIX_DMETRIC_BEST : PREFIX_DMETRIC_INVALID; 314 else 315 np->dmetric = prefix_cmp(pp, np, &testall); 316 if (np->dmetric < 0) { 317 struct bgpd_addr addr; 318 pt_getaddr(np->pt, &addr); 319 log_debug("bad dmetric in decision process: %s/%u", 320 log_addr(&addr), np->pt->prefixlen); 321 } 322 } 323 } 324 325 /* 326 * Insert a prefix keeping the total order of the list. For routes 327 * that may depend on a MED selection the set is scanned until the 328 * condition is cleared. If a MED inversion is detected the respective 329 * prefix is taken of the rib list and put onto a redo queue. All 330 * prefixes on the redo queue are re-inserted at the end. 331 */ 332 void 333 prefix_insert(struct prefix *new, struct prefix *ep, struct rib_entry *re) 334 { 335 struct prefix_queue redo = TAILQ_HEAD_INITIALIZER(redo); 336 struct prefix *xp, *np, *insertp = ep; 337 int testall, preferred, selected = 0, removed = 0; 338 339 /* start scan at the entry point (ep) or the head if ep == NULL */ 340 if (ep == NULL) 341 ep = TAILQ_FIRST(&re->prefix_h); 342 343 for (xp = ep; xp != NULL; xp = np) { 344 np = TAILQ_NEXT(xp, entry.list.rib); 345 346 if ((preferred = (prefix_cmp(new, xp, &testall) > 0))) { 347 /* new is preferred over xp */ 348 if (testall == 2) { 349 /* 350 * MED inversion, take out prefix and 351 * put it onto redo queue. 352 */ 353 TAILQ_REMOVE(&re->prefix_h, xp, entry.list.rib); 354 TAILQ_INSERT_TAIL(&redo, xp, entry.list.rib); 355 removed = 1; 356 continue; 357 } 358 359 if (testall == 1) { 360 /* 361 * lock insertion point and 362 * continue on with scan 363 */ 364 selected = 1; 365 } 366 } else { 367 /* 368 * xp is preferred over new. 369 * Remember insertion point for later unless the 370 * traverse is just looking for a possible MED 371 * inversion (selected == 1). 372 * If the last comparison's tie-breaker was the MED 373 * check reset selected and with it insertp since 374 * this was an actual MED priority inversion. 375 */ 376 if (testall == 2) 377 selected = 0; 378 if (!selected) 379 insertp = xp; 380 } 381 382 /* 383 * If previous element(s) got removed, fixup the 384 * dmetric, now that it is clear that this element 385 * is on the list. 386 */ 387 if (removed) { 388 prefix_set_dmetric(TAILQ_PREV(xp, prefix_queue, 389 entry.list.rib), xp); 390 removed = 0; 391 } 392 393 if (preferred && testall == 0) 394 break; /* we're done */ 395 } 396 397 if (insertp == NULL) { 398 TAILQ_INSERT_HEAD(&re->prefix_h, new, entry.list.rib); 399 } else { 400 TAILQ_INSERT_AFTER(&re->prefix_h, insertp, new, entry.list.rib); 401 } 402 403 prefix_set_dmetric(insertp, new); 404 prefix_set_dmetric(new, TAILQ_NEXT(new, entry.list.rib)); 405 406 /* Fixup MED order again. All elements are < new */ 407 while (!TAILQ_EMPTY(&redo)) { 408 xp = TAILQ_FIRST(&redo); 409 TAILQ_REMOVE(&redo, xp, entry.list.rib); 410 411 prefix_insert(xp, new, re); 412 } 413 } 414 415 /* 416 * Remove a prefix from the RIB list ensuring that the total order of the 417 * list remains intact. All routes that differ in the MED are taken of the 418 * list and put on the redo list. To figure out if a route could cause a 419 * resort because of a MED check the next prefix of the to-remove prefix 420 * is compared with the old prefix. A full scan is only done if the next 421 * route differs because of the MED or later checks. 422 * Again at the end all routes on the redo queue are reinserted. 423 */ 424 void 425 prefix_remove(struct prefix *old, struct rib_entry *re) 426 { 427 struct prefix_queue redo = TAILQ_HEAD_INITIALIZER(redo); 428 struct prefix *xp, *np, *pp; 429 int testall, removed = 0; 430 431 xp = TAILQ_NEXT(old, entry.list.rib); 432 pp = TAILQ_PREV(old, prefix_queue, entry.list.rib); 433 TAILQ_REMOVE(&re->prefix_h, old, entry.list.rib); 434 435 /* check if a MED inversion could be possible */ 436 prefix_cmp(old, xp, &testall); 437 if (testall > 0) { 438 /* maybe MED route, scan tail for other possible routes */ 439 for (; xp != NULL; xp = np) { 440 np = TAILQ_NEXT(xp, entry.list.rib); 441 442 /* only interested in the testall result */ 443 prefix_cmp(old, xp, &testall); 444 if (testall == 2) { 445 /* 446 * possible MED inversion, take out prefix and 447 * put it onto redo queue. 448 */ 449 TAILQ_REMOVE(&re->prefix_h, xp, entry.list.rib); 450 TAILQ_INSERT_TAIL(&redo, xp, entry.list.rib); 451 removed = 1; 452 continue; 453 } 454 /* 455 * If previous element(s) got removed, fixup the 456 * dmetric, now that it is clear that this element 457 * is on the list. 458 */ 459 if (removed) { 460 prefix_set_dmetric(TAILQ_PREV(xp, prefix_queue, 461 entry.list.rib), xp); 462 removed = 0; 463 } 464 if (testall == 0) 465 break; /* we're done */ 466 } 467 } 468 469 if (pp) 470 prefix_set_dmetric(pp, TAILQ_NEXT(pp, entry.list.rib)); 471 else 472 prefix_set_dmetric(NULL, TAILQ_FIRST(&re->prefix_h)); 473 474 /* Fixup MED order again, reinsert prefixes from the start */ 475 while (!TAILQ_EMPTY(&redo)) { 476 xp = TAILQ_FIRST(&redo); 477 TAILQ_REMOVE(&redo, xp, entry.list.rib); 478 479 prefix_insert(xp, NULL, re); 480 } 481 } 482 483 /* helper function to check if a prefix is valid to be selected */ 484 int 485 prefix_eligible(struct prefix *p) 486 { 487 struct rde_aspath *asp = prefix_aspath(p); 488 489 /* prefix itself is marked ineligible */ 490 if (prefix_filtered(p)) 491 return 0; 492 493 /* The aspath needs to be loop and error free */ 494 if (asp == NULL || 495 asp->flags & (F_ATTR_LOOP|F_ATTR_OTC_LEAK|F_ATTR_PARSE_ERR)) 496 return 0; 497 498 /* The nexthop must be valid. */ 499 if (!prefix_nhvalid(p)) 500 return 0; 501 502 return 1; 503 } 504 505 struct prefix * 506 prefix_best(struct rib_entry *re) 507 { 508 struct prefix *xp; 509 struct rib *rib; 510 511 rib = re_rib(re); 512 if (rib->flags & F_RIB_NOEVALUATE) 513 /* decision process is turned off */ 514 return NULL; 515 516 xp = TAILQ_FIRST(&re->prefix_h); 517 if (xp != NULL && !prefix_eligible(xp)) 518 xp = NULL; 519 return xp; 520 } 521 522 /* 523 * Find the correct place to insert the prefix in the prefix list. 524 * If the active prefix has changed we need to send an update also special 525 * treatment is needed if 'rde evaluate all' is used on some peers. 526 * To re-evaluate a prefix just call prefix_evaluate with old and new pointing 527 * to the same prefix. 528 */ 529 void 530 prefix_evaluate(struct rib_entry *re, struct prefix *new, struct prefix *old) 531 { 532 struct prefix *newbest, *oldbest; 533 struct rib *rib; 534 535 rib = re_rib(re); 536 if (rib->flags & F_RIB_NOEVALUATE) { 537 /* decision process is turned off */ 538 if (old != NULL) 539 TAILQ_REMOVE(&re->prefix_h, old, entry.list.rib); 540 if (new != NULL) { 541 TAILQ_INSERT_HEAD(&re->prefix_h, new, entry.list.rib); 542 new->dmetric = PREFIX_DMETRIC_INVALID; 543 } 544 return; 545 } 546 547 oldbest = prefix_best(re); 548 if (old != NULL) 549 prefix_remove(old, re); 550 if (new != NULL) 551 prefix_insert(new, NULL, re); 552 newbest = prefix_best(re); 553 554 /* 555 * If the active prefix changed or the active prefix was removed 556 * and added again then generate an update. 557 */ 558 if (oldbest != newbest || (old != NULL && newbest == old)) { 559 /* 560 * Send update withdrawing oldbest and adding newbest 561 * but remember that newbest may be NULL aka ineligible. 562 * Additional decision may be made by the called functions. 563 */ 564 if ((rib->flags & F_RIB_NOFIB) == 0) 565 rde_send_kroute(rib, newbest, oldbest); 566 rde_generate_updates(re, new, old, EVAL_DEFAULT); 567 return; 568 } 569 570 /* 571 * If there are peers with 'rde evaluate all' every update needs 572 * to be passed on (not only a change of the best prefix). 573 * rde_generate_updates() will then take care of distribution. 574 */ 575 if (rde_evaluate_all()) { 576 if (new != NULL && !prefix_eligible(new)) 577 new = NULL; 578 if (new != NULL || old != NULL) 579 rde_generate_updates(re, new, old, EVAL_ALL); 580 } 581 } 582 583 void 584 prefix_evaluate_nexthop(struct prefix *p, enum nexthop_state state, 585 enum nexthop_state oldstate) 586 { 587 struct rib_entry *re = prefix_re(p); 588 struct prefix *newbest, *oldbest, *new, *old; 589 struct rib *rib; 590 591 /* Skip non local-RIBs or RIBs that are flagged as noeval. */ 592 rib = re_rib(re); 593 if (rib->flags & F_RIB_NOEVALUATE) { 594 log_warnx("%s: prefix with F_RIB_NOEVALUATE hit", __func__); 595 return; 596 } 597 598 if (oldstate == state) { 599 /* 600 * The state of the nexthop did not change. The only 601 * thing that may have changed is the true_nexthop 602 * or other internal infos. This will not change 603 * the routing decision so shortcut here. 604 * XXX needs to be changed for ECMP 605 */ 606 if (state == NEXTHOP_REACH) { 607 if ((rib->flags & F_RIB_NOFIB) == 0 && 608 p == prefix_best(re)) 609 rde_send_kroute(rib, p, NULL); 610 } 611 return; 612 } 613 614 /* 615 * Re-evaluate the prefix by removing the prefix then updating the 616 * nexthop state and reinserting the prefix again. 617 */ 618 old = p; 619 oldbest = prefix_best(re); 620 prefix_remove(p, re); 621 622 if (state == NEXTHOP_REACH) 623 p->nhflags |= NEXTHOP_VALID; 624 else 625 p->nhflags &= ~NEXTHOP_VALID; 626 627 prefix_insert(p, NULL, re); 628 newbest = prefix_best(re); 629 new = p; 630 if (!prefix_eligible(new)) 631 new = NULL; 632 633 /* 634 * If the active prefix changed or the active prefix was removed 635 * and added again then generate an update. 636 */ 637 if (oldbest != newbest || newbest == p) { 638 /* 639 * Send update withdrawing oldbest and adding newbest 640 * but remember that newbest may be NULL aka ineligible. 641 * Additional decision may be made by the called functions. 642 */ 643 if ((rib->flags & F_RIB_NOFIB) == 0) 644 rde_send_kroute(rib, newbest, oldbest); 645 rde_generate_updates(re, new, old, EVAL_DEFAULT); 646 return; 647 } 648 649 /* 650 * If there are peers with 'rde evaluate all' every update needs 651 * to be passed on (not only a change of the best prefix). 652 * rde_generate_updates() will then take care of distribution. 653 */ 654 if (rde_evaluate_all()) 655 rde_generate_updates(re, new, old, EVAL_ALL); 656 } 657