During config reload the RIB may need to be resynced when the 'no evaluate' setting changes.
This changes the code to actually flush the Adj-RIB-Out of affected peers and then adjust the RIB in a 2nd step. That way there is no need to use rde_generate_updates() to remove the prefixes one by one in the NOFIB case. Also fix the loop to reinsert all prefixes to remove the prefix from the temporary list before calling prefix_evaluate(). Calling prefix_evaluate() with p as the old prefix is just wrong. It is not on the rib_entry list at that time. This can be improved further but since this code path is almost never needed (changing rib flags happens almost never) it is not urgent. -- :wq Claudio Index: rde.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v retrieving revision 1.541 diff -u -p -r1.541 rde.c --- rde.c 21 Mar 2022 10:15:34 -0000 1.541 +++ rde.c 21 Mar 2022 11:13:34 -0000 @@ -3469,7 +3469,33 @@ rde_reload_done(void) rib_free(rib); break; case RECONF_RELOAD: - rib_update(rib); + if (rib_update(rib)) { + LIST_FOREACH(peer, &peerlist, peer_l) { + /* ignore peerself*/ + if (peer->conf.id == 0) + continue; + /* skip peers using a different rib */ + if (peer->loc_rib_id != rib->id) + continue; + /* peer rib is already being flushed */ + if (peer->reconf_rib) + continue; + + if (prefix_dump_new(peer, AID_UNSPEC, + RDE_RUNNER_ROUNDS, NULL, + rde_up_flush_upcall, + rde_softreconfig_in_done, + NULL) == -1) + fatal("%s: prefix_dump_new", + __func__); + + log_peer_info(&peer->conf, + "flushing Adj-RIB-Out"); + /* account for the running flush */ + softreconfig++; + } + } + rib->state = RECONF_KEEP; /* FALLTHROUGH */ case RECONF_KEEP: @@ -3717,17 +3743,14 @@ rde_softreconfig_sync_reeval(struct rib_ if (rib->flags & F_RIB_NOEVALUATE) { /* * evaluation process is turned off - * so remove all prefixes from adj-rib-out - * also unlink nexthop if it was linked + * all dependent adj-rib-out were already flushed + * unlink nexthop if it was linked */ LIST_FOREACH(p, &re->prefix_h, entry.list.rib) { if (p->flags & PREFIX_NEXTHOP_LINKED) nexthop_unlink(p); } - if (re->active) { - rde_generate_updates(rib, NULL, re->active, 0); - re->active = NULL; - } + re->active = NULL; return; } @@ -3736,11 +3759,18 @@ rde_softreconfig_sync_reeval(struct rib_ prefixes = re->prefix_h; LIST_INIT(&re->prefix_h); + /* + * TODO: this code works but is not optimal. prefix_evaluate() + * does a lot of extra work in the worst case. Would be better + * to resort the list once and then call rde_generate_updates() + * and rde_send_kroute() once. + */ LIST_FOREACH_SAFE(p, &prefixes, entry.list.rib, next) { /* need to re-link the nexthop if not already linked */ + LIST_REMOVE(p, entry.list.rib); if ((p->flags & PREFIX_NEXTHOP_LINKED) == 0) nexthop_link(p); - prefix_evaluate(re, p, p); + prefix_evaluate(re, p, NULL); } } Index: rde.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v retrieving revision 1.248 diff -u -p -r1.248 rde.h --- rde.h 15 Mar 2022 16:50:29 -0000 1.248 +++ rde.h 21 Mar 2022 10:31:17 -0000 @@ -548,7 +548,7 @@ pt_unref(struct pt_entry *pt) extern uint16_t rib_size; struct rib *rib_new(char *, u_int, uint16_t); -void rib_update(struct rib *); +int rib_update(struct rib *); struct rib *rib_byid(uint16_t); uint16_t rib_find(char *); void rib_free(struct rib *); Index: rde_rib.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v retrieving revision 1.234 diff -u -p -r1.234 rde_rib.c --- rde_rib.c 15 Mar 2022 16:50:29 -0000 1.234 +++ rde_rib.c 21 Mar 2022 10:32:05 -0000 @@ -179,7 +179,7 @@ rib_new(char *name, u_int rtableid, uint * or RECONF_REINIT (rerun the route decision process for every element) * depending on the new flags. */ -void +int rib_update(struct rib *rib) { /* flush fib first if there was one */ @@ -198,6 +198,8 @@ rib_update(struct rib *rib) if (rib->fibstate != RECONF_REINIT && (rib->flags & (F_RIB_NOFIB | F_RIB_NOEVALUATE)) == 0) rib->fibstate = RECONF_RELOAD; + + return (rib->fibstate == RECONF_REINIT); } struct rib *