<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p class="isSelectedEnd"><span>Hello.</span></p>
    <p><span>This is not directly related to BIRD itself. BIRD appears
        to work correctly in this case. The question is about how </span><code
        dir="ltr"><span>bird_exporter</span></code><span> exposes
        metrics for a BIRD 2 BGP protocol with multiple address-family
        channels.</span></p>
    <p>I am using <code>bird_exporter</code> with BIRD 2 and noticed
      confusing behavior when a single BGP protocol has more than one
      address-family channel enabled, for example both <code>ipv4</code>
      and <code>ipv6</code>.</p>
    <p>Versions:</p>
    <pre><code class="language-text">bird_exporter: 1.5.0
BIRD: 2.19.0
</code></pre>
    <p>Exporter is started like this:</p>
    <pre><code class="language-bash">bird_exporter \
  -web.listen-address=localhost:9325 \
  -bird.v2 \
  -bird.socket=/path/to/bird.ctl
</code></pre>
    <p>BIRD shows one established BGP session with both IPv4 and IPv6
      channels up:</p>
    <pre><code class="language-text">Name              Proto  State  Info
example_peer      BGP    up     Established

BGP state: Established
Neighbor address: 2001:db8::1
Source address:   2001:db8::2

Local capabilities:
  Multiprotocol
    AF announced: ipv4 ipv6

Neighbor capabilities:
  Multiprotocol
    AF announced: ipv4 ipv6

Channel ipv4
  State: UP
  Table: master4
  Routes: 10 imported, 0 filtered, 6000 exported, 10 preferred

Channel ipv6
  State: UP
  Table: master6
  Routes: 0 imported, 0 filtered, 200 exported, 0 preferred
</code></pre>
    <p>Actual <code>bird_exporter</code> output:</p>
    <pre><code class="language-text">bird_protocol_up{export_filter="(unnamed)",import_filter="(unnamed)",ip_version="4",name="example_peer",proto="BGP",state="Established"} 1
bird_protocol_up{export_filter="(unnamed)",import_filter="(unnamed)",ip_version="6",name="example_peer",proto="BGP",state=""} 1

bird_protocol_uptime{export_filter="(unnamed)",import_filter="(unnamed)",ip_version="4",name="example_peer",proto="BGP"} 397
bird_protocol_uptime{export_filter="(unnamed)",import_filter="(unnamed)",ip_version="6",name="example_peer",proto="BGP"} 397

bird_protocol_prefix_export_count{export_filter="(unnamed)",import_filter="(unnamed)",ip_version="4",name="example_peer",proto="BGP"} 6000
bird_protocol_prefix_export_count{export_filter="(unnamed)",import_filter="(unnamed)",ip_version="6",name="example_peer",proto="BGP"} 200

bird_protocol_prefix_import_count{export_filter="(unnamed)",import_filter="(unnamed)",ip_version="4",name="example_peer",proto="BGP"} 10
bird_protocol_prefix_import_count{export_filter="(unnamed)",import_filter="(unnamed)",ip_version="6",name="example_peer",proto="BGP"} 0

bird_protocol_prefix_preferred_count{export_filter="(unnamed)",import_filter="(unnamed)",ip_version="4",name="example_peer",proto="BGP"} 10
bird_protocol_prefix_preferred_count{export_filter="(unnamed)",import_filter="(unnamed)",ip_version="6",name="example_peer",proto="BGP"} 0
</code></pre>
    <p>The important part is that both <code>ip_version="4"</code> and
      <code>ip_version="6"</code> are exported for the same BGP
      protocol, but only one series has the BGP FSM state:</p>
    <pre><code class="language-text">bird_protocol_up{ip_version="4",name="example_peer",proto="BGP",state="Established"} 1
bird_protocol_up{ip_version="6",name="example_peer",proto="BGP",state=""} 1
</code></pre>
    <p>The IPv6 series has <code>state=""</code>, although the BGP
      protocol is established and the IPv6 channel is UP.</p>
    <p>Expected behavior:</p>
    <p>Either <code>state="Established"</code> should be present on all
      <code>bird_protocol_up</code> series generated from the same
      established BGP protocol:</p>
    <pre><code class="language-text">bird_protocol_up{ip_version="4",name="example_peer",proto="BGP",state="Established"} 1
bird_protocol_up{ip_version="6",name="example_peer",proto="BGP",state="Established"} 1
</code></pre>
    <p>or <code>state</code> should not be attached to per-AF <code>bird_protocol_up</code>
      series at all, and a separate protocol-level metric should expose
      the BGP FSM state.</p>
    <p>The current behavior is confusing for monitoring systems, because
      the same BGP protocol appears as partly established and partly
      without state, although both address-family channels are UP.</p>
    <p>It would also be useful to distinguish clearly between:</p>
    <ul>
      <li>
        <p>protocol/session state, for example <code>BGP state:
            Established</code>;</p>
      </li>
      <li>
        <p>channel state, for example <code>Channel ipv4: UP</code>, <code>Channel
            ipv6: UP</code>;</p>
      </li>
      <li>
        <p>address-family label, currently exposed as <code>ip_version</code>.</p>
      </li>
    </ul>
    <p>A cleaner model could be something like:</p>
    <pre><code class="language-text">bird_protocol_up{name="example_peer",proto="BGP",state="Established"} 1

bird_protocol_channel_up{name="example_peer",proto="BGP",channel="ipv4"} 1
bird_protocol_channel_up{name="example_peer",proto="BGP",channel="ipv6"} 1
</code></pre>
    <p>This would avoid ambiguity when one BIRD 2 protocol serves
      multiple address families.</p>
    <p>Thank you.</p>
    <p><br>
    </p>
  </body>
</html>