bird_exporter: Inconsistent state label for BIRD 2 BGP protocol with multiple AF channels

Mikhail Mayorov mm at tagan.ru
Mon Jun 1 15:22:16 CEST 2026


Hello.

This is not directly related to BIRD itself. BIRD appears to work 
correctly in this case. The question is about how |bird_exporter|exposes 
metrics for a BIRD 2 BGP protocol with multiple address-family channels.

I am using |bird_exporter| with BIRD 2 and noticed confusing behavior 
when a single BGP protocol has more than one address-family channel 
enabled, for example both |ipv4| and |ipv6|.

Versions:

|bird_exporter: 1.5.0 BIRD: 2.19.0 |

Exporter is started like this:

|bird_exporter \ -web.listen-address=localhost:9325 \ -bird.v2 \ 
-bird.socket=/path/to/bird.ctl |

BIRD shows one established BGP session with both IPv4 and IPv6 channels up:

|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 |

Actual |bird_exporter| output:

|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 |

The important part is that both |ip_version="4"| and |ip_version="6"| 
are exported for the same BGP protocol, but only one series has the BGP 
FSM state:

|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 |

The IPv6 series has |state=""|, although the BGP protocol is established 
and the IPv6 channel is UP.

Expected behavior:

Either |state="Established"| should be present on all |bird_protocol_up| 
series generated from the same established BGP protocol:

|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 |

or |state| should not be attached to per-AF |bird_protocol_up| series at 
all, and a separate protocol-level metric should expose the BGP FSM state.

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.

It would also be useful to distinguish clearly between:

  *

    protocol/session state, for example |BGP state: Established|;

  *

    channel state, for example |Channel ipv4: UP|, |Channel ipv6: UP|;

  *

    address-family label, currently exposed as |ip_version|.

A cleaner model could be something like:

|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 |

This would avoid ambiguity when one BIRD 2 protocol serves multiple 
address families.

Thank you.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://trubka.network.cz/pipermail/bird-users/attachments/20260601/1418df3f/attachment.htm>


More information about the Bird-users mailing list