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=heads#L1077

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_type=heads#L177

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

Reply via email to