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 *

Reply via email to