From: Claudio Jeker Subject: bgpd: fix for bgpctl show rib out To: tech@openbsd.org Date: Wed, 20 May 2026 11:44:18 +0200 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. -- :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)));