Commit d3dfbc25b4 for frr
commit d3dfbc25b4bb85b63bd950d22bdf44325da24d23
Author: Philippe Guibert <philippe.guibert@6wind.com>
Date: Mon Oct 12 16:11:55 2026 +0200
bgpd: keep the aigp set by an outbound route-map
The AIGP metric set by an outbound route-map is not advertised when the
nexthop is changed. In bgp_aigp, r6 receives 10.0.0.71/32 from r7 with
an AIGP metric of 71, on a connected link. Add 'set aigp-metric 100' to
the outbound route-map of r6 towards r4:
> route-map set-nexthop permit 10
> set ip next-hop peer-address
> set aigp-metric 100
r4 still receives the AIGP metric of r7:
> r4# show bgp ipv4 unicast 10.0.0.71/32
> BGP routing table entry for 10.0.0.71/32, version 8
> Paths: (1 available, best #1, table default)
> Advertised to peers:
> 192.168.24.2
> Local
> 10.0.0.6 (metric 20) from 10.0.0.6 (10.0.0.73)
> Origin incomplete, metric 71, localpref 100, aigp-metric 71, valid, internal, best (First path received)
> Originator: 10.0.0.73, Cluster list: 10.0.6.6
> Last update: Mon Nov 9 10:40:13 2026
RFC 7311 section 3.4.3 requires that a speaker which changes the
nexthop increases the AIGP metric by a non-zero distance to the previous
nexthop, either the IGP distance or a value set by policy. On a
connected link, the IGP metric to the nexthop is 0, so the policy is the
only way to increase it.
subgroup_announce_check() applies the outbound route-map, then, as the
nexthop is changed, overwrites the AIGP metric of the advertised
attribute with bgp_aigp_metric_total(). This function reads the AIGP
metric of the received path (71), and not the one set by the route-map
(100), then adds the IGP metric to the nexthop (0).
Fix this by passing the attribute to use to bgp_aigp_metric_total().
subgroup_announce_check() passes the attribute modified by the outbound
route-map, and r4 receives 100. The best path selection still uses the
attribute of the path.
Fixes: fc82d7750f3c ("bgpd: fix AIGP calculation in route advertisement")
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 88e1877dd0..30093c59bf 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -752,9 +752,9 @@ static inline uint64_t bgp_attr_get_aigp_metric(const struct attr *attr)
extern void bgp_attr_set_aigp_metric(struct attr *attr, uint64_t aigp);
extern void bgp_attr_unset_aigp_metric(struct attr *attr);
-static inline uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi)
+static inline uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi, const struct attr *attr)
{
- uint64_t aigp = bgp_attr_get_aigp_metric(bpi->attr);
+ uint64_t aigp = bgp_attr_get_aigp_metric(attr);
/* Don't increment if it's locally sourced */
if (bpi->peer == bpi->peer->bgp->peer_self)
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 3a515be972..b072ce96a9 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1419,8 +1419,8 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
/* 4. Tie-breaker - AIGP (Metric TLV) attribute */
if (bgp_attr_exists(newattr, BGP_ATTR_AIGP) && bgp_attr_exists(existattr, BGP_ATTR_AIGP) &&
CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP)) {
- uint64_t new_aigp = bgp_aigp_metric_total(new);
- uint64_t exist_aigp = bgp_aigp_metric_total(exist);
+ uint64_t new_aigp = bgp_aigp_metric_total(new, new->attr);
+ uint64_t exist_aigp = bgp_aigp_metric_total(exist, exist->attr);
if (new_aigp < exist_aigp) {
*reason = bgp_path_selection_aigp;
@@ -3378,7 +3378,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
if (AIGP_TRANSMIT_ALLOWED(peer)) {
if (nh_reset ||
CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_NEXTHOP_PEER_ADDRESS)) {
- uint64_t aigp = bgp_aigp_metric_total(pi);
+ uint64_t aigp = bgp_aigp_metric_total(pi, attr);
bgp_attr_set_aigp_metric(attr, aigp);
}