<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<style>
html {
line-height: 1.2;
font-family: serif;
font-size: 0.9em;
color: black;
background-color: white;
}
body {
margin: 0;
margin-right: auto;
max-width: 36em;
padding: 1em;
hyphens: auto;
overflow-wrap: break-word;
text-rendering: optimizeLegibility;
font-kerning: normal;
}
@media print {
body {
background-color: transparent;
color: black;
font-size: 11pt;
}
p, h2, h3 {
orphans: 3;
widows: 3;
}
h2, h3, h4 {
page-break-after: avoid;
}
}
p {
margin: 1em 0;
}
a {
color: black;
}
a:visited {
color: black;
}
img {
max-width: 100%;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 1.4em;
}
h5, h6 {
font-size: 1em;
font-style: italic;
}
h6 {
font-weight: normal;
}
ol, ul {
padding-left: 1.7em;
margin-top: 1em;
}
li > ol, li > ul {
margin-top: 0;
}
blockquote {
margin: 0.5em;
padding-left: 0.5em;
border-left: 2px solid #e6e6e6;
color: #444;
}
code {
font-family: 'Lucida Console', monospace;
font-size: 95%;
margin: 0;
}
pre {
margin: 1em 0;
overflow: auto;
max-width: unset;
width: fit-content;
}
pre code {
padding: 0;
overflow: visible;
overflow-wrap: normal;
max-width: unset;
white-space: pre-wrap;
}
pre code span {
white-space: pre;
}
.sourceCode {
background-color: transparent;
overflow: visible;
}
code.diff span.kw,
code.diff span.dt {
font-weight: bold;
}
code.diff span.va {
background-color: rgba(192, 255, 192, 64);
color: rgb(0, 64, 0);
}
code.diff span.st {
background-color: rgba(255, 192, 192, 64);
color: rgb(64, 0, 0);
}
pre.diff {
background-color: rgb(240, 240, 240);
padding: 0.4em;
border: 1pt solid grey;
}
hr {
background-color: black;
border: none;
height: 1px;
margin: 1em 0;
}
table {
margin: 1em 0;
border-collapse: collapse;
width: 100%;
overflow-x: auto;
display: block;
font-variant-numeric: lining-nums tabular-nums;
}
table caption {
margin-bottom: 0.75em;
}
tbody {
margin-top: 0.5em;
border-top: 1px solid black;
border-bottom: 1px solid black;
}
th {
border-top: 1px solid black;
padding: 0.25em 0.5em 0.25em 0.5em;
}
td {
padding: 0.125em 0.5em 0.25em 0.5em;
}
header {
margin-bottom: 4em;
text-align: center;
}
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
q { quotes: "„" "”" "»" "«"; }
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
</head>
<body>
<p>Good morning Nico,</p>
<p>On Fri, Nov 21, 2025 at 09:29:12AM +0100, Nico Schottelius wrote:</p>
<blockquote>
<p>thanks for the reply, but I am a bit puzzled, in multiple cases:</p>
</blockquote>
<p>Oh that’s ok. BIRD is complex.</p>
<blockquote>
<ul>
<li><ol type="a">
<li>active vs. all routes I was under the impression that filtering
allows me to select the best route, i.e. filters apply on “all routes”,
not on “best routes”.</li>
</ol>
Shouldn’t it be the case that filters in general operate on all, not
already filtered routes?</li>
</ul>
</blockquote>
<p>Well, well, yes and no. Filtering on …</p>
<ul>
<li>import allows you to select whether a route enters the best route
selection process</li>
<li>export to BGP, Babel, OSPF, RIP, Kernel allows you to select whether
the best route passes into the protocol</li>
<li>export to Pipe and BGP with Add Path TX allows you to select which
of the routes pass into the protocol, regardless of the best route
selected</li>
<li>export to BGP with Secondary option allows you to walk over the
route list and pick the first route to pass the filter</li>
</ul>
<p>We expect to add some more options to make this even more powerful,
e.g. an additional filter block after the iBGP nexthop resolution, or
maybe even some customization of best route selection. This should
<del>confuse people even more</del> allow people better
customization.</p>
<p>With that, if you wish to export to BGP “first which passes”, you can
use <code>secondary</code> in the channel config. You need a
<code>sorted</code> table to do that, iirc.</p>
<blockquote>
<ul>
<li><ol start="2" type="a">
<li>filter output vs. export reality Independent of whether we filter on
“all best” or “all routes”, in the CLI the filter output shown does
include the route - if the filter does not match, it also should not
print it</li>
</ol></li>
</ul>
</blockquote>
<p>Well, if you do <code>show route filter xyz</code>, then you get all
routes matching that filter. Some protocols pick them. You can do
<code>show route export bgp_to_internet.ipv6</code> to explicitly re-run
the export filter in that context.</p>
<p>I know that it is kinda confusing, and we should probably improve our
documentation to show this properly.</p>
<blockquote>
<ul>
<li><p>Route attribute background</p>
<p>Maybe for understanding <em>why</em> the route exists as it
exists:</p>
<ul>
<li>Using a match on RTS_STATIC is somewhat universal and can be used in
all of our data centers, as <em>if</em> we define a static route, we do
want to eBGP export it</li>
<li>The main reason why it was defined in this case to be static is to
allow the filter to grab it - otherwise it would actually not be needed
at all</li>
<li>The main motivation is to reduce the number of special cases for
selecting internet facing routes in the same way everywhere</li>
</ul></li>
</ul>
</blockquote>
<p>With that, I would simply lower the preference of
<code>protocol direct</code> then under 200, maybe to something like 180
which is still more than default babel but less than static, and that
should fix your problem. The direct protocol default preference is kinda
unreasonably high in your case.</p>
<blockquote>
<ul>
<li><ol start="3" type="a">
<li>Multi attribute matching So the effective route is seen via direct,
static and babel. My assumption in bird would be that I can select
(filter) the route using one of the three protocol RTS_ matches to find
and export the route.</li>
</ol></li>
</ul>
</blockquote>
<p>That is possible with the <code>sorted</code> table option and
<code>secondary</code> bgp channel option.</p>
<blockquote>
<p>So what I am trying to say is that as a user I’d expect the union of
attributes to be matching and not only the the current/best
selected.</p>
</blockquote>
<p>Then we failed to set the user expectation correctly.</p>
<blockquote>
<p>Which seems to be what the filter output in the CLI is doing, versus
what bird exports.</p>
</blockquote>
<p>Yup, because e.g. Pipe takes all while BGP takes best by default, and
the show route output does not know which export behavior you prefer. To
show only best routes, you can add <code>primary</code> to the
<code>show route</code> command.</p>
<blockquote>
<p>Does it make sense?</p>
</blockquote>
<p>Yes. Welcome to the group of people who got confused by our UI
multiple times! We should definitely make it less confusing for
future.</p>
<p>Thanks for all of this, it’s a very valuable feedback for us.<br />
Maria</p>
<p>–<br />
Maria Matejka (she/her) | BIRD Team Leader | CZ.NIC, z.s.p.o.</p>
</body>
</html>