Commit d1d95f7983 for frr
commit d1d95f79834e13c39d9c4c7c67095f858c89fcb6
Author: Minghan Chan <mhchann082@gmail.com>
Date: Fri Oct 16 14:35:10 2026 +0800
bgpd: size the BGP-LS IGP Metric TLV by the IGP
bgp_ls_populate_link_attr() picks the length of the IGP Metric TLV
(1095) from the value: 1 octet up to 255, 2 octets up to 65535 and 3
above. RFC 9552 section 5.3.2.4 ties the length to the metric width of
the IGP instead: 1 octet is the IS-IS small metric, whose two high bits
the receiver ignores, OSPF link metrics are 2 octets and IS-IS wide
metrics 3 octets. A conforming receiver thus reads an OSPF cost of 64
to 255 as 0 to 63, and an IS-IS wide metric up to 65535 arrives in the
small metric or the OSPF format.
Take the length from the origin of the link: 2 octets for OSPFv2 and 3
for IS-IS, since isisd puts only wide metric links in the TED (see
lsp_to_edge_cb()). Other origins keep the previous behavior.
Fixes: https://github.com/FRRouting/frr/issues/23710
Signed-off-by: Minghan Chan <mhchann082@gmail.com>
diff --git a/bgpd/bgp_ls_ted.c b/bgpd/bgp_ls_ted.c
index 993f5dcd70..d793ade189 100644
--- a/bgpd/bgp_ls_ted.c
+++ b/bgpd/bgp_ls_ted.c
@@ -220,13 +220,31 @@ int bgp_ls_populate_link_attr(struct ls_attributes *ls_attr, struct bgp_ls_attr
/* IGP Metric (TLV 1095) */
if (CHECK_FLAG(ls_attr->flags, LS_ATTR_METRIC)) {
- /* IGP metric can be 1, 2, or 3 bytes */
- if (ls_attr->metric <= 0xFF)
- attr->igp_metric_len = 1;
- else if (ls_attr->metric <= 0xFFFF)
+ /*
+ * RFC 9552 section 5.3.2.4: the length is given by the metric
+ * width of the IGP, not by the value. A receiver ignores the
+ * two high bits of a 1 octet metric (IS-IS small metric).
+ */
+ switch (ls_attr->adv.origin) {
+ case OSPFv2:
attr->igp_metric_len = 2;
- else
+ break;
+ case ISIS_L1:
+ case ISIS_L2:
+ /* isisd puts only wide metric links in the TED */
attr->igp_metric_len = 3;
+ break;
+ case LS_UNKNOWN:
+ case DIRECT:
+ case STATIC:
+ if (ls_attr->metric <= 0xFF)
+ attr->igp_metric_len = 1;
+ else if (ls_attr->metric <= 0xFFFF)
+ attr->igp_metric_len = 2;
+ else
+ attr->igp_metric_len = 3;
+ break;
+ }
attr->igp_metric = ls_attr->metric;
SET_FLAG(attr->present_tlvs, BGP_LS_ATTR_IGP_METRIC_BIT);
}