In Rev 1.511 I moved peer related checks from inside up_generate_updates()
authorclaudio <claudio@openbsd.org>
Thu, 17 Jun 2021 08:43:06 +0000 (08:43 +0000)
committerclaudio <claudio@openbsd.org>
Thu, 17 Jun 2021 08:43:06 +0000 (08:43 +0000)
to rde_generate_updates() but forgot to add the same checks to
rde_softreconfig_out(). As a result a config reload could result in
prefixes for a not-negotiated address family to leak into the Adj-RIB-Out.
Adjust both rde_generate_updates() and rde_softreconfig_out() to use the
same filter logic.
Also adjust rde_up_flush_upcall() to pass the peer as argument instead of
using prefix_peer(). The up_generate_updates() call there does not need
any filtering since the walker runs on the Adj-RIB-Out and just withdraws
everything.
OK job@ on a previous diff

usr.sbin/bgpd/rde.c

index 11d7d57..cd0add1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.c,v 1.524 2021/05/27 16:32:13 claudio Exp $ */
+/*     $OpenBSD: rde.c,v 1.525 2021/06/17 08:43:06 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -2908,9 +2908,6 @@ rde_generate_updates(struct rib *rib, struct prefix *new, struct prefix *old,
                        continue;
                if (peer->state != PEER_UP)
                        continue;
-               if ((peer->flags & PEERFLAG_EVALUATE_ALL) == 0 && eval_all)
-                       /* skip default peers if the best path didn't change */
-                       continue;
                /* skip peers using a different rib */
                if (peer->loc_rib_id != rib->id)
                        continue;
@@ -2921,15 +2918,21 @@ rde_generate_updates(struct rib *rib, struct prefix *new, struct prefix *old,
                if (peer->export_type == EXPORT_NONE ||
                    peer->export_type == EXPORT_DEFAULT_ROUTE)
                        continue;
+               /* skip regular peers if the best path didn't change */
+               if ((peer->flags & PEERFLAG_EVALUATE_ALL) == 0 && eval_all)
+                       continue;
 
                up_generate_updates(out_rules, peer, new, old);
        }
 }
 
+/* flush Adj-RIB-Out by withdrawing all prefixes */
 static void
 rde_up_flush_upcall(struct prefix *p, void *ptr)
 {
-       up_generate_updates(out_rules, prefix_peer(p), NULL, p);
+       struct rde_peer *peer = ptr;
+
+       up_generate_updates(out_rules, peer, NULL, p);
 }
 
 u_char queue_buf[4096];
@@ -3310,7 +3313,7 @@ rde_reload_done(void)
 
                if (peer->reconf_rib) {
                        if (prefix_dump_new(peer, AID_UNSPEC,
-                           RDE_RUNNER_ROUNDS, NULL, rde_up_flush_upcall,
+                           RDE_RUNNER_ROUNDS, peer, 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");
@@ -3561,15 +3564,34 @@ rde_softreconfig_out(struct rib_entry *re, void *bula)
 {
        struct prefix           *p = re->active;
        struct rde_peer         *peer;
+       u_int8_t                 aid = re->prefix->aid;
 
        if (p == NULL)
                /* no valid path for prefix */
                return;
 
        LIST_FOREACH(peer, &peerlist, peer_l) {
-               if (peer->loc_rib_id == re->rib_id && peer->reconf_out)
-                       /* Regenerate all updates. */
-                       up_generate_updates(out_rules, peer, p, p);
+               /* skip ourself */
+               if (peer == peerself)
+                       continue;
+               if (peer->state != PEER_UP)
+                       continue;
+               /* skip peers using a different rib */
+               if (peer->loc_rib_id != p->re->rib_id)
+                       continue;
+               /* check if peer actually supports the address family */
+               if (peer->capa.mp[aid] == 0)
+                       continue;
+               /* skip peers with special export types */
+               if (peer->export_type == EXPORT_NONE ||
+                   peer->export_type == EXPORT_DEFAULT_ROUTE)
+                       continue;
+               /* skip peers which don't need to reconfigure */
+               if (peer->reconf_out == 0)
+                       continue;
+
+               /* Regenerate all updates. */
+               up_generate_updates(out_rules, peer, p, p);
        }
 }