From: Theo Buehler Subject: Re: bgpd: fix for bgpctl show rib out To: tech@openbsd.org Date: Wed, 20 May 2026 11:50:05 +0200 On Wed, May 20, 2026 at 11:44:18AM +0200, Claudio Jeker wrote: > There is an error when it comes to handling > bgpctl show rib out > queries. If the IP to lookup up is covered by a not exported route but > instead by a less specific one the lookup fails. > > For example in this setup where the /26 route is filtered: > bgpctl show rib > flags vs destination gateway lpref med aspath origin > AI*> N-? 192.0.2.0/24 0.0.0.0 100 0 i > AI*> N-? 192.0.2.0/26 0.0.0.0 100 0 i > bgpctl show rib out > flags vs destination gateway lpref med aspath origin > AI* N-? 192.0.2.0/24 10.83.0.138 100 0 i > bgpctl show rib out 192.0.2.0/24 > flags vs destination gateway lpref med aspath origin > AI* N-? 192.0.2.0/24 10.83.0.138 100 0 i > > but > bgpctl show rib out 192.0.2.1 > flags vs destination gateway lpref med aspath origin > > The last command fails even though there is a route for 192.0.2.1 it just > hides behind 192.0.2.0/26. > > The diff below fixes this. In the pt_lookup() case one needs to walk up > all possible prefixes to see if a covering route is actually exported. > > Not super fond of this diff since it adds yet another loop into a nested > mess. This should all be refactored but I'm not doing that right now. Yeah, well... Diff makes sense and if it works that's better than leaving it broken. ok tb > -- > :wq Claudio > > Index: rde.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v > diff -u -p -r1.700 rde.c > --- rde.c 13 May 2026 14:01:29 -0000 1.700 > +++ rde.c 18 May 2026 11:36:40 -0000 > @@ -3276,7 +3276,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req > struct rib_entry *re; > struct adjout_prefix *p; > u_int error; > - uint8_t hostplen, plen; > + int hostplen, plen; > uint16_t rid; > > if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { > @@ -3342,6 +3342,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req > > do { > struct pt_entry *pte; > + int found; > > if (req->flags & F_SHORTER) { > for (plen = 0; plen <= req->prefixlen; > @@ -3370,13 +3371,28 @@ rde_dump_ctx_new(struct ctl_show_rib_req > if (pte == NULL) > continue; > > - /* dump all matching paths */ > - for (p = adjout_prefix_first(peer, pte); > - p != NULL; > - p = adjout_prefix_next(peer, pte, p)) { > - rde_dump_adjout_upcall(peer, pte, p, > - ctx); > - } > + do { > + /* dump all matching paths */ > + found = 0; > + for (p = adjout_prefix_first(peer, pte); > + p != NULL; > + p = adjout_prefix_next(peer, pte, > + p)) { > + rde_dump_adjout_upcall(peer, > + pte, p, ctx); > + found = 1; > + } > + if (!found && > + req->prefixlen == hostplen) { > + for (plen = pte->prefixlen - 1; > + plen >= 0; plen--) { > + pte = pt_get( > + &req->prefix, plen); > + if (pte != NULL) > + break; > + } > + } > + } while (!found && pte != NULL); > } while ((peer = peer_match(&req->neighbor, > peer->conf.id))); > >