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);
 	}