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 *