Bug: Cannot export static route on FreeBSD running bird 3.1
I'm running the following configuration that simply exports a static route to the kernel on FreeBSD with bird v3.1: protocol device { scan time 60; } protocol static { ipv4; route 10.119.0.0/24 via "en6"; } protocol kernel { ipv4 { export all; }; } For some reason, this doesn't export the route. Looking at the bird logs, for some reason the kernel protocol seems to reject the route: bird: 2025-08-10 20:08:30.783 [0001] <TRACE> kernel1: Pruning table master4 bird: 2025-08-10 20:08:30.783 [0001] <TRACE> kernel1.ipv4: route refresh end: rr 1 set 1 valid 1 pruning 0 pruned 0 bird: 2025-08-10 20:08:30.783 [0001] <TRACE> kernel1.ipv4: Feeding 10.119.0.0/24 bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1.ipv4 < rejected by protocol 10.119.0.0/24 ptr 000000016d18ec30 (0) src 0L 3G 0S id 1 unicast bird: 2025-08-10 20:08:30.784 [0002] <TRACE> kernel1.ipv4: table prune after refresh begin: rr 1 set 1 valid 1 pruning 1 pruned 0 bird: 2025-08-10 20:08:30.784 [0002] <TRACE> kernel1.ipv4: table prune after refresh end: rr 0 set 1 valid 1 pruning 1 pruned 1 bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1.ipv4 < idempotent withdraw (filtered on export) 10.119.0.0/24 ptr 0000000102e58050 (0) src 0L 3G 0S id 1 unicast bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1.ipv4: Export state changed from PARTIAL to READY bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1.ipv4: Fed up bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1: Table master4 pruned bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1.ipv4: Export drained During a debuggin session, I've traced it to the following lines things: It seems to be rejected in nest/rt-table.c, function export_filter because p->preexport returns -1 https://gitlab.nic.cz/labs/bird/-/blob/stable-v3.1/nest/rt-table.c?ref_type=... Tracing that further, the actual reason it does get rejected seems to come from here in krt_capable: https://gitlab.nic.cz/labs/bird/-/blob/stable-v3.1/sysdep/bsd/krt-sock.c?ref... A debugging printf showed !NEXTHOP_ONE(nh) is always false. As far as I understand, NEXTHOP_ONE returns true if there is just one nexthop, so !NEXTHOP_ONE(nh) effectively demands multiple nexthops. This contradicts the comment that no multipath is supported. Furthermore, looking at the last commit touching that line, the condition used to be !a->nh.next, which reads to me as checking that there is just one nexthop. I suspect the condition there is probably wrong and should say NEXTHOP_ONE(nh) without negation? Changing that made bird export the route just fine in a quick test. Does that make any sense? Yuri
Hello Yuri, that really looks like an oversight on our side. Right now we are running in a somewhat "holiday" mode, but I will put it in our backlog. We will get to it as soon as we can. Thanks a lot for the thorough report and have a nice week! David David Petera (he/him) | BIRD Tech Support | CZ.NIC, z.s.p.o. On 8/10/25 20:25, Yuri Honegger via Bird-users wrote:
I'm running the following configuration that simply exports a static route to the kernel on FreeBSD with bird v3.1:
protocol device { scan time 60; }
protocol static { ipv4; route 10.119.0.0/24 via "en6"; }
protocol kernel { ipv4 { export all; }; }
For some reason, this doesn't export the route. Looking at the bird logs, for some reason the kernel protocol seems to reject the route:
bird: 2025-08-10 20:08:30.783 [0001] <TRACE> kernel1: Pruning table master4 bird: 2025-08-10 20:08:30.783 [0001] <TRACE> kernel1.ipv4: route refresh end: rr 1 set 1 valid 1 pruning 0 pruned 0 bird: 2025-08-10 20:08:30.783 [0001] <TRACE> kernel1.ipv4: Feeding 10.119.0.0/24 bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1.ipv4 < rejected by protocol 10.119.0.0/24 ptr 000000016d18ec30 (0) src 0L 3G 0S id 1 unicast bird: 2025-08-10 20:08:30.784 [0002] <TRACE> kernel1.ipv4: table prune after refresh begin: rr 1 set 1 valid 1 pruning 1 pruned 0 bird: 2025-08-10 20:08:30.784 [0002] <TRACE> kernel1.ipv4: table prune after refresh end: rr 0 set 1 valid 1 pruning 1 pruned 1 bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1.ipv4 < idempotent withdraw (filtered on export) 10.119.0.0/24 ptr 0000000102e58050 (0) src 0L 3G 0S id 1 unicast bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1.ipv4: Export state changed from PARTIAL to READY bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1.ipv4: Fed up bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1: Table master4 pruned bird: 2025-08-10 20:08:30.784 [0001] <TRACE> kernel1.ipv4: Export drained
During a debuggin session, I've traced it to the following lines things: It seems to be rejected in nest/rt-table.c, function export_filter because p->preexport returns -1 https://gitlab.nic.cz/labs/bird/-/blob/stable-v3.1/nest/rt-table.c?ref_type=...
Tracing that further, the actual reason it does get rejected seems to come from here in krt_capable: https://gitlab.nic.cz/labs/bird/-/blob/stable-v3.1/sysdep/bsd/krt-sock.c?ref...
A debugging printf showed !NEXTHOP_ONE(nh) is always false. As far as I understand, NEXTHOP_ONE returns true if there is just one nexthop, so !NEXTHOP_ONE(nh) effectively demands multiple nexthops. This contradicts the comment that no multipath is supported. Furthermore, looking at the last commit touching that line, the condition used to be !a->nh.next, which reads to me as checking that there is just one nexthop. I suspect the condition there is probably wrong and should say NEXTHOP_ONE(nh) without negation? Changing that made bird export the route just fine in a quick test.
Does that make any sense?
Yuri
participants (2)
-
David Petera -
Yuri Honegger