<div dir="ltr"><div style="color:rgb(51,51,51);background-color:rgb(245,245,245);font-family:Menlo,Monaco,"Courier New",monospace;font-size:14px;line-height:21px;white-space:pre"><div><span style="color:rgb(119,119,119)">#</span><span style="color:rgb(170,55,49)"> </span><span style="color:rgb(170,55,49);font-weight:bold">Title</span></div><br><div>Kernel export metric change can delete a route and leave a forwarding blackhole until the next kernel scan</div><br><div><span style="color:rgb(119,119,119)">#</span><span style="color:rgb(170,55,49)"> </span><span style="color:rgb(170,55,49);font-weight:bold">Description</span></div><br><div>When a kernel-exported route changes <span style="color:rgb(119,119,119)">`</span><span style="color:rgb(156,93,39)">krt_metric</span><span style="color:rgb(119,119,119)">`</span>, BIRD may perform the update as delete-old plus add-new instead of an atomic replace. If the add operation fails, BIRD's source route and export view still show the route as exported, but the Linux FIB is missing the route until the next kernel protocol scan repairs it.</div><br><div>This creates a transient RIB/FIB divergence and forwarding blackhole.</div><br><div><span style="color:rgb(119,119,119)">#</span><span style="color:rgb(170,55,49)"> </span><span style="color:rgb(170,55,49);font-weight:bold">Version</span></div><br><div>Reproduced with:</div><br><div><span style="color:rgb(119,119,119)">```</span>text</div><div>BIRD 2.18+branch.master.f0f859c26cf9</div><div><span style="color:rgb(119,119,119)">```</span></div><br><div><span style="color:rgb(119,119,119)">#</span><span style="color:rgb(170,55,49)"> </span><span style="color:rgb(170,55,49);font-weight:bold">How to reproduce</span></div><br><div><span style="color:rgb(119,119,119)">1.</span><span style="color:rgb(75,105,198)"> Create a single-router Linux namespace or VM with one tested interface.</span></div><br><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span><span style="color:rgb(75,105,198)">text</span></div><div><span style="color:rgb(75,105,198)">                  <a href="http://10.100.0.1/24">10.100.0.1/24</a></span></div><div><span style="color:rgb(75,105,198)">                +---------------+</span></div><div><span style="color:rgb(75,105,198)">                |      r1       |</span></div><div><span style="color:rgb(75,105,198)">                |               |</span></div><div><span style="color:rgb(75,105,198)">                |     eth0      |</span></div><div><span style="color:rgb(75,105,198)">                +---------------+</span></div><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span></div><br><div><span style="color:rgb(119,119,119)">2.</span><span style="color:rgb(75,105,198)"> Configure a BIRD static blackhole source route, then rewrite it in the kernel export filter into a direct route with an interface, preferred source, and metric:</span></div><br><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span><span style="color:rgb(75,105,198)">bird</span></div><div><span style="color:rgb(75,105,198)">   protocol static static_src {</span></div><div><span style="color:rgb(75,105,198)">       ipv4;</span></div><div><span style="color:rgb(75,105,198)">       route <a href="http://198.51.100.0/24">198.51.100.0/24</a> blackhole;</span></div><div><span style="color:rgb(75,105,198)">   }</span></div><br><div><span style="color:rgb(75,105,198)">   protocol kernel krt_export {</span></div><div><span style="color:rgb(75,105,198)">       ipv4 {</span></div><div><span style="color:rgb(75,105,198)">           export filter {</span></div><div><span style="color:rgb(75,105,198)">               ifname = "eth0";</span></div><div><span style="color:rgb(75,105,198)">               krt_prefsrc = 10.100.0.1;</span></div><div><span style="color:rgb(75,105,198)">               krt_metric = 110;</span></div><div><span style="color:rgb(75,105,198)">               accept;</span></div><div><span style="color:rgb(75,105,198)">           };</span></div><div><span style="color:rgb(75,105,198)">       };</span></div><div><span style="color:rgb(75,105,198)">       scan time 2;</span></div><div><span style="color:rgb(75,105,198)">   }</span></div><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span></div><br><div><span style="color:rgb(119,119,119)">3.</span><span style="color:rgb(75,105,198)"> Confirm the route is installed in the Linux FIB:</span></div><br><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span><span style="color:rgb(75,105,198)">bash</span></div><div><span style="color:rgb(75,105,198)">   </span>ip route show <a href="http://198.51.100.0/24">198.51.100.0/24</a></div><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span></div><br><div><span style="color:rgb(119,119,119)">4.</span><span style="color:rgb(75,105,198)"> Remove address </span><span style="color:rgb(119,119,119)">`</span><span style="color:rgb(156,93,39)"><a href="http://10.100.0.1/24">10.100.0.1/24</a></span><span style="color:rgb(119,119,119)">`</span><span style="color:rgb(75,105,198)"> so that a later route add using </span><span style="color:rgb(119,119,119)">`</span><span style="color:rgb(156,93,39)">krt_prefsrc = 10.100.0.1</span><span style="color:rgb(119,119,119)">`</span><span style="color:rgb(75,105,198)"> fails:</span></div><br><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span><span style="color:rgb(75,105,198)">bash</span></div><div><span style="color:rgb(75,105,198)">   </span>ip addr del <a href="http://10.100.0.1/24">10.100.0.1/24</a> dev eth0</div><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span></div><br><div><span style="color:rgb(119,119,119)">5.</span><span style="color:rgb(75,105,198)"> Reconfigure the export filter so that the route metric changes from </span><span style="color:rgb(119,119,119)">`</span><span style="color:rgb(156,93,39)">110</span><span style="color:rgb(119,119,119)">`</span><span style="color:rgb(75,105,198)"> to </span><span style="color:rgb(119,119,119)">`</span><span style="color:rgb(156,93,39)">210</span><span style="color:rgb(119,119,119)">`</span><span style="color:rgb(75,105,198)">, without otherwise changing the source route.</span></div><br><div><span style="color:rgb(119,119,119)">6.</span><span style="color:rgb(75,105,198)"> Observe BIRD's source route and export view, then inspect the Linux FIB before the next kernel scan:</span></div><br><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span><span style="color:rgb(75,105,198)">bash</span></div><div><span style="color:rgb(75,105,198)">   </span>birdc show route <span style="color:rgb(75,105,198)">for</span> <a href="http://198.51.100.0/24">198.51.100.0/24</a> all</div><div><span style="color:rgb(75,105,198)">   </span>birdc show route <span style="color:rgb(75,105,198)">export</span> <span style="color:rgb(122,62,157)">krt_export</span> <span style="color:rgb(122,62,157)">for</span> <span style="color:rgb(122,62,157)">198</span>.<span style="color:rgb(122,62,157)">51</span>.<span style="color:rgb(122,62,157)">100</span>.<span style="color:rgb(122,62,157)">0</span>/<span style="color:rgb(122,62,157)">24</span> <span style="color:rgb(122,62,157)">all</span></div><div><span style="color:rgb(75,105,198)">   </span>ip route show <a href="http://198.51.100.0/24">198.51.100.0/24</a></div><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span></div><br><div><span style="color:rgb(119,119,119)">7.</span><span style="color:rgb(75,105,198)"> Restore the address and wait for the kernel scan to confirm that the route is repaired later:</span></div><br><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span><span style="color:rgb(75,105,198)">bash</span></div><div><span style="color:rgb(75,105,198)">   </span>ip addr add <a href="http://10.100.0.1/24">10.100.0.1/24</a> dev eth0</div><div><span style="color:rgb(75,105,198)">   </span>sleep 3</div><div><span style="color:rgb(75,105,198)">   </span>ip route show <a href="http://198.51.100.0/24">198.51.100.0/24</a></div><div><span style="color:rgb(75,105,198)">   </span><span style="color:rgb(119,119,119)">```</span></div><br><div><span style="color:rgb(119,119,119)">#</span><span style="color:rgb(170,55,49)"> </span><span style="color:rgb(170,55,49);font-weight:bold">Expected behavior</span></div><br><div>BIRD should not leave the forwarding plane without the route while its control-plane/export view says the route should be exported. If the metric-changing update cannot be installed, BIRD should either preserve the old route, retry immediately when possible, or otherwise keep the control plane and FIB from diverging until the next periodic scan.</div><br><div><span style="color:rgb(119,119,119)">#</span><span style="color:rgb(170,55,49)"> </span><span style="color:rgb(170,55,49);font-weight:bold">Actual behavior</span></div><br><div>After the metric-changing reconfiguration, before the next kernel scan:</div><br><div><span style="color:rgb(119,119,119)">```</span>text</div><div>bird_source_present=True</div><div>bird_export_present=True</div><div>bird_export_final_metric=True</div><div>bird_export_prefsrc=True</div><div>kernel_present=False</div><div>addr_present=False</div><div><span style="color:rgb(119,119,119)">```</span></div><br><div>The route is absent from the Linux FIB even though BIRD still reports that it should be exported. After the address is restored and the kernel protocol scan runs, BIRD installs the route again:</div><div><br></div><br><div><span style="color:rgb(119,119,119)">#</span><span style="color:rgb(170,55,49)"> </span><span style="color:rgb(170,55,49);font-weight:bold">Additional context</span></div><br><div>The suspected source path is in <span style="color:rgb(119,119,119)">`</span><span style="color:rgb(156,93,39)">sysdep/linux/netlink.c</span><span style="color:rgb(119,119,119)">`</span>. <span style="color:rgb(119,119,119)">`</span><span style="color:rgb(156,93,39)">nl_allow_replace()</span><span style="color:rgb(119,119,119)">`</span> disallows an atomic replace when the old and new <span style="color:rgb(119,119,119)">`</span><span style="color:rgb(156,93,39)">EA_KRT_METRIC</span><span style="color:rgb(119,119,119)">`</span> values differ under kernel protocol metric handling. <span style="color:rgb(119,119,119)">`</span><span style="color:rgb(156,93,39)">krt_replace_rte()</span><span style="color:rgb(119,119,119)">`</span> then performs delete-old followed by add-new. If add-new fails, BIRD clears synchronization state but does not immediately recover the missing FIB route; recovery waits for the next kernel scan.</div><br></div></div>