Download raw body.
bgpd: fix for bgpctl show rib out <IP>
There is an error when it comes to handling
bgpctl show rib out <IP>
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)));
bgpd: fix for bgpctl show rib out <IP>