]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: apply route-map for aggregate before attribute comparison
authorEnke Chen <enchen@paloaltonetworks.com>
Thu, 9 Jan 2025 01:34:29 +0000 (17:34 -0800)
committerDonatas Abraitis <donatas@opensourcerouting.org>
Fri, 10 Jan 2025 07:51:16 +0000 (09:51 +0200)
Currently when re-evaluating an aggregate route, the full attribute of
the aggregate route is not compared with the existing one in the BGP
table. That can result in unnecessary churns (un-install and then
install) of the aggregate route when a more specific route is added or
deleted, or when the route-map for the aggregate changes. The churn
would impact route installation and route advertisement.

The fix is to apply the route-map for the aggregate first and then
compare the attribute.

Here is an example of the churn:

debug bgp aggregate prefix 5.5.5.0/24
!
route-map set-comm permit 10
 set community 65004:200
!
router bgp 65001
 address-family ipv4 unicast
  redistribute static
  aggregate-address 5.5.5.0/24 route-map set-comm
!

Step 1:
  ip route 5.5.5.1/32 Null0

Jan  8 10:28:49 enke-vm1 bgpd[285786]: [J7PXJ-A7YA2] bgp_aggregate_install: aggregate 5.5.5.0/24, count 1
Jan  8 10:28:49 enke-vm1 bgpd[285786]: [Y444T-HEVNG]   aggregate 5.5.5.0/24: installed

Step 2:
  ip route 5.5.5.2/32 Null0

Jan  8 10:29:03 enke-vm1 bgpd[285786]: [J7PXJ-A7YA2] bgp_aggregate_install: aggregate 5.5.5.0/24, count 2
Jan  8 10:29:03 enke-vm1 bgpd[285786]: [S2EH5-EQSX6]   aggregate 5.5.5.0/24: existing, removed
Jan  8 10:29:03 enke-vm1 bgpd[285786]: [Y444T-HEVNG]   aggregate 5.5.5.0/24: installed
---

Signed-off-by: Enke Chen <enchen@paloaltonetworks.com>
bgpd/bgp_route.c

index 8c3b5e97ed7d24df7ce3197f34ffa888bd65bfc0..93d27aa167c69288c6c5541f8675f8ef8326de4d 100644 (file)
@@ -7729,44 +7729,6 @@ static bool aggr_unsuppress_path(struct bgp_aggregate *aggregate,
        return false;
 }
 
-static bool bgp_aggregate_info_same(struct bgp_path_info *pi, uint8_t origin,
-                                   struct aspath *aspath,
-                                   struct community *comm,
-                                   struct ecommunity *ecomm,
-                                   struct lcommunity *lcomm)
-{
-       static struct aspath *ae = NULL;
-       enum asnotation_mode asnotation;
-
-       asnotation = bgp_get_asnotation(NULL);
-
-       if (!aspath)
-               ae = aspath_empty(asnotation);
-
-       if (!pi)
-               return false;
-
-       if (origin != pi->attr->origin)
-               return false;
-
-       if (!aspath_cmp(pi->attr->aspath, (aspath) ? aspath : ae))
-               return false;
-
-       if (!community_cmp(bgp_attr_get_community(pi->attr), comm))
-               return false;
-
-       if (!ecommunity_cmp(bgp_attr_get_ecommunity(pi->attr), ecomm))
-               return false;
-
-       if (!lcommunity_cmp(bgp_attr_get_lcommunity(pi->attr), lcomm))
-               return false;
-
-       if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
-               return false;
-
-       return true;
-}
-
 static void bgp_aggregate_install(
        struct bgp *bgp, afi_t afi, safi_t safi, const struct prefix *p,
        uint8_t origin, struct aspath *aspath, struct community *community,
@@ -7775,14 +7737,14 @@ static void bgp_aggregate_install(
 {
        struct bgp_dest *dest;
        struct bgp_table *table;
-       struct bgp_path_info *pi, *orig, *new;
+       struct bgp_path_info *pi, *new;
        struct attr *attr;
 
        table = bgp->rib[afi][safi];
 
        dest = bgp_node_get(table, p);
 
-       for (orig = pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
+       for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
                if (pi->peer == bgp->peer_self && pi->type == ZEBRA_ROUTE_BGP
                    && pi->sub_type == BGP_ROUTE_AGGREGATE)
                        break;
@@ -7799,19 +7761,21 @@ static void bgp_aggregate_install(
                 * If the aggregate information has not changed
                 * no need to re-install it again.
                 */
-               if (pi && bgp_aggregate_info_same(pi, origin, aspath, community,
-                                                 ecommunity, lcommunity)) {
+               attr = bgp_attr_aggregate_intern(bgp, origin, aspath, community, ecommunity,
+                                                lcommunity, aggregate, atomic_aggregate, p);
+               if (!attr) {
+                       aspath_free(aspath);
+                       community_free(&community);
+                       ecommunity_free(&ecommunity);
+                       lcommunity_free(&lcommunity);
                        bgp_dest_unlock_node(dest);
+                       bgp_aggregate_delete(bgp, p, afi, safi, aggregate);
+                       return;
+               }
 
-                       if (aspath)
-                               aspath_free(aspath);
-                       if (community)
-                               community_free(&community);
-                       if (ecommunity)
-                               ecommunity_free(&ecommunity);
-                       if (lcommunity)
-                               lcommunity_free(&lcommunity);
-
+               if (pi && CHECK_FLAG(pi->flags, BGP_PATH_VALID) && attrhash_cmp(pi->attr, attr)) {
+                       bgp_attr_unintern(&attr);
+                       bgp_dest_unlock_node(dest);
                        return;
                }
 
@@ -7823,22 +7787,6 @@ static void bgp_aggregate_install(
                        bgp_process(bgp, dest, pi, afi, safi);
                }
 
-               attr = bgp_attr_aggregate_intern(
-                       bgp, origin, aspath, community, ecommunity, lcommunity,
-                       aggregate, atomic_aggregate, p);
-
-               if (!attr) {
-                       aspath_free(aspath);
-                       community_free(&community);
-                       ecommunity_free(&ecommunity);
-                       lcommunity_free(&lcommunity);
-                       bgp_dest_unlock_node(dest);
-                       bgp_aggregate_delete(bgp, p, afi, safi, aggregate);
-                       if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
-                               zlog_debug("%s: %pFX null attribute", __func__,
-                                          p);
-                       return;
-               }
 
                new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, 0,
                                bgp->peer_self, attr, dest);
@@ -7849,17 +7797,11 @@ static void bgp_aggregate_install(
                bgp_process(bgp, dest, new, afi, safi);
        } else {
        uninstall_aggregate_route:
-               for (pi = orig; pi; pi = pi->next)
-                       if (pi->peer == bgp->peer_self
-                           && pi->type == ZEBRA_ROUTE_BGP
-                           && pi->sub_type == BGP_ROUTE_AGGREGATE)
-                               break;
-
-               /* Withdraw static BGP route from routing table. */
-               if (pi) {
-                       bgp_path_info_delete(dest, pi);
-                       bgp_process(bgp, dest, pi, afi, safi);
-               }
+                       /* Withdraw the aggregate route from routing table. */
+                       if (pi) {
+                               bgp_path_info_delete(dest, pi);
+                               bgp_process(bgp, dest, pi, afi, safi);
+                       }
        }
 
        bgp_dest_unlock_node(dest);