]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_route.c
Merge branch 'master' into evpn-session-vrf
[mirror_frr.git] / bgpd / bgp_route.c
index 99dc9d81249cab749d136a476cfd6cdcc7d66771..eca632dd448cf1601fb46375646f9682b686326b 100644 (file)
@@ -254,8 +254,9 @@ static void bgp_path_info_free(struct bgp_path_info *path)
        bgp_unlink_nexthop(path);
        bgp_path_info_extra_free(&path->extra);
        bgp_path_info_mpath_free(&path->mpath);
-       bgp_addpath_free_info_data(&path->tx_addpath,
-                                path->net ? &path->net->tx_addpath : NULL);
+       if (path->net)
+               bgp_addpath_free_info_data(&path->tx_addpath,
+                                          &path->net->tx_addpath);
 
        peer_unlock(path->peer); /* bgp_path_info peer reference */
 
@@ -1224,6 +1225,20 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p,
                }
        }
 
+       /* RFC 8212 to prevent route leaks.
+        * This specification intends to improve this situation by requiring the
+        * explicit configuration of both BGP Import and Export Policies for any
+        * External BGP (EBGP) session such as customers, peers, or
+        * confederation boundaries for all enabled address families. Through
+        * codification of the aforementioned requirement, operators will
+        * benefit from consistent behavior across different BGP
+        * implementations.
+        */
+       if (peer->bgp->ebgp_requires_policy
+           == DEFAULT_EBGP_POLICY_ENABLED)
+               if (!bgp_inbound_policy_exists(peer, filter))
+                       return RMAP_DENY;
+
        /* Route map apply. */
        if (rmap) {
                memset(&rmap_path, 0, sizeof(struct bgp_path_info));
@@ -1777,6 +1792,20 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
                }
        }
 
+       /* RFC 8212 to prevent route leaks.
+        * This specification intends to improve this situation by requiring the
+        * explicit configuration of both BGP Import and Export Policies for any
+        * External BGP (EBGP) session such as customers, peers, or
+        * confederation boundaries for all enabled address families. Through
+        * codification of the aforementioned requirement, operators will
+        * benefit from consistent behavior across different BGP
+        * implementations.
+        */
+       if (peer->bgp->ebgp_requires_policy
+           == DEFAULT_EBGP_POLICY_ENABLED)
+               if (!bgp_outbound_policy_exists(peer, filter))
+                       return 0;
+
        if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
                if (peer->sort == BGP_PEER_IBGP
                    || peer->sort == BGP_PEER_CONFED) {
@@ -2447,8 +2476,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
 
        /* advertise/withdraw type-5 routes */
        if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
-               if (advertise_type5_routes(bgp, afi) && new_select &&
-                   (!new_select->extra || !new_select->extra->parent)) {
+               if (advertise_type5_routes(bgp, afi) &&
+                   new_select &&
+                   is_route_injectable_into_evpn(new_select)) {
 
                        /* apply the route-map */
                        if (bgp->adv_cmd_rmap[afi][safi].map) {
@@ -2461,6 +2491,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
                                        bgp_evpn_advertise_type5_route(
                                                bgp, &rn->p, new_select->attr,
                                                afi, safi);
+                               else
+                                       bgp_evpn_withdraw_type5_route(
+                                               bgp, &rn->p, afi, safi);
                        } else {
                                bgp_evpn_advertise_type5_route(bgp,
                                                               &rn->p,
@@ -2468,8 +2501,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
                                                               afi, safi);
 
                        }
-               } else if (advertise_type5_routes(bgp, afi) && old_select &&
-                        (!old_select->extra || !old_select->extra->parent))
+               } else if (advertise_type5_routes(bgp, afi) &&
+                          old_select &&
+                          is_route_injectable_into_evpn(old_select))
                        bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
        }
 
@@ -3062,7 +3096,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
                goto filtered;
        }
 
-       if (bgp_mac_entry_exists(p)) {
+       if (bgp_mac_entry_exists(p) || bgp_mac_exist(&attr->rmac)) {
                reason = "self mac;";
                goto filtered;
        }
@@ -3251,7 +3285,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
                        extra = bgp_path_info_extra_get(pi);
                        if (extra->label != label) {
                                memcpy(&extra->label, label,
-                                               num_labels * sizeof(mpls_label_t));
+                                      num_labels * sizeof(mpls_label_t));
                                extra->num_labels = num_labels;
                        }
                        if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
@@ -3423,7 +3457,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
        if (has_valid_label) {
                extra = bgp_path_info_extra_get(new);
                if (extra->label != label) {
-                       memcpy(&extra->label, label, num_labels * sizeof(mpls_label_t));
+                       memcpy(&extra->label, label,
+                              num_labels * sizeof(mpls_label_t));
                        extra->num_labels = num_labels;
                }
                if (!(afi == AFI_L2VPN && safi == SAFI_EVPN))
@@ -4160,6 +4195,26 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
        }
 }
 
+int bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter)
+{
+       if (peer->sort == BGP_PEER_EBGP
+           && (ROUTE_MAP_OUT_NAME(filter) || PREFIX_LIST_OUT_NAME(filter)
+               || FILTER_LIST_OUT_NAME(filter)
+               || DISTRIBUTE_OUT_NAME(filter)))
+               return 1;
+       return 0;
+}
+
+int bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter)
+{
+       if (peer->sort == BGP_PEER_EBGP
+           && (ROUTE_MAP_IN_NAME(filter) || PREFIX_LIST_IN_NAME(filter)
+               || FILTER_LIST_IN_NAME(filter)
+               || DISTRIBUTE_IN_NAME(filter)))
+               return 1;
+       return 0;
+}
+
 static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table,
                              safi_t safi)
 {
@@ -4415,10 +4470,10 @@ static struct bgp_static *bgp_static_new(void)
 
 static void bgp_static_free(struct bgp_static *bgp_static)
 {
-       if (bgp_static->rmap.name)
-               XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name);
-       if (bgp_static->eth_s_id)
-               XFREE(MTYPE_ATTR, bgp_static->eth_s_id);
+       XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name);
+       route_map_counter_decrement(bgp_static->rmap.map);
+
+       XFREE(MTYPE_ATTR, bgp_static->eth_s_id);
        XFREE(MTYPE_BGP_STATIC, bgp_static);
 }
 
@@ -4978,17 +5033,21 @@ static int bgp_static_set(struct vty *vty, const char *negate,
                        bgp_static->backdoor = backdoor;
 
                        if (rmap) {
-                               if (bgp_static->rmap.name)
-                                       XFREE(MTYPE_ROUTE_MAP_NAME,
-                                             bgp_static->rmap.name);
+                               XFREE(MTYPE_ROUTE_MAP_NAME,
+                                     bgp_static->rmap.name);
+                               route_map_counter_decrement(
+                                       bgp_static->rmap.map);
                                bgp_static->rmap.name =
                                        XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
                                bgp_static->rmap.map =
                                        route_map_lookup_by_name(rmap);
+                               route_map_counter_increment(
+                                       bgp_static->rmap.map);
                        } else {
-                               if (bgp_static->rmap.name)
-                                       XFREE(MTYPE_ROUTE_MAP_NAME,
-                                             bgp_static->rmap.name);
+                               XFREE(MTYPE_ROUTE_MAP_NAME,
+                                     bgp_static->rmap.name);
+                               route_map_counter_decrement(
+                                       bgp_static->rmap.map);
                                bgp_static->rmap.name = NULL;
                                bgp_static->rmap.map = NULL;
                                bgp_static->valid = 0;
@@ -5004,13 +5063,16 @@ static int bgp_static_set(struct vty *vty, const char *negate,
                        bgp_static->label_index = label_index;
 
                        if (rmap) {
-                               if (bgp_static->rmap.name)
-                                       XFREE(MTYPE_ROUTE_MAP_NAME,
-                                             bgp_static->rmap.name);
+                               XFREE(MTYPE_ROUTE_MAP_NAME,
+                                     bgp_static->rmap.name);
+                               route_map_counter_decrement(
+                                       bgp_static->rmap.map);
                                bgp_static->rmap.name =
                                        XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
                                bgp_static->rmap.map =
                                        route_map_lookup_by_name(rmap);
+                               route_map_counter_increment(
+                                       bgp_static->rmap.map);
                        }
                        bgp_node_set_bgp_static_info(rn, bgp_static);
                }
@@ -5286,13 +5348,13 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty,
                bgp_static->prd = prd;
 
                if (rmap_str) {
-                       if (bgp_static->rmap.name)
-                               XFREE(MTYPE_ROUTE_MAP_NAME,
-                                     bgp_static->rmap.name);
+                       XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name);
+                       route_map_counter_decrement(bgp_static->rmap.map);
                        bgp_static->rmap.name =
                                XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_str);
                        bgp_static->rmap.map =
                                route_map_lookup_by_name(rmap_str);
+                       route_map_counter_increment(bgp_static->rmap.map);
                }
 
                if (safi == SAFI_EVPN) {
@@ -5393,13 +5455,14 @@ static int bgp_table_map_set(struct vty *vty, afi_t afi, safi_t safi,
 
        rmap = &bgp->table_map[afi][safi];
        if (rmap_name) {
-               if (rmap->name)
-                       XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+               XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+               route_map_counter_decrement(rmap->map);
                rmap->name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
                rmap->map = route_map_lookup_by_name(rmap_name);
+               route_map_counter_increment(rmap->map);
        } else {
-               if (rmap->name)
-                       XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+               XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+               route_map_counter_decrement(rmap->map);
                rmap->name = NULL;
                rmap->map = NULL;
        }
@@ -5417,8 +5480,8 @@ static int bgp_table_map_unset(struct vty *vty, afi_t afi, safi_t safi,
        struct bgp_rmap *rmap;
 
        rmap = &bgp->table_map[afi][safi];
-       if (rmap->name)
-               XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+       XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+       route_map_counter_decrement(rmap->map);
        rmap->name = NULL;
        rmap->map = NULL;
 
@@ -5513,33 +5576,6 @@ DEFPY(ipv6_bgp_network,
                label_index ? (uint32_t)label_index : BGP_INVALID_LABEL_INDEX);
 }
 
-/* Aggreagete address:
-
-  advertise-map  Set condition to advertise attribute
-  as-set         Generate AS set path information
-  attribute-map  Set attributes of aggregate
-  route-map      Set parameters of aggregate
-  summary-only   Filter more specific routes from updates
-  suppress-map   Conditionally filter more specific routes from updates
-  <cr>
- */
-struct bgp_aggregate {
-       /* Summary-only flag. */
-       uint8_t summary_only;
-
-       /* AS set generation. */
-       uint8_t as_set;
-
-       /* Route-map for aggregated route. */
-       struct route_map *map;
-
-       /* Suppress-count. */
-       unsigned long count;
-
-       /* SAFI configuration. */
-       safi_t safi;
-};
-
 static struct bgp_aggregate *bgp_aggregate_new(void)
 {
        return XCALLOC(MTYPE_BGP_AGGREGATE, sizeof(struct bgp_aggregate));
@@ -5665,8 +5701,7 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi,
 
 /* Update an aggregate as routes are added/removed from the BGP table */
 static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
-                               struct bgp_path_info *pinew, afi_t afi,
-                               safi_t safi, struct bgp_path_info *del,
+                               afi_t afi, safi_t safi,
                                struct bgp_aggregate *aggregate)
 {
        struct bgp_table *table;
@@ -5674,13 +5709,9 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
        struct bgp_node *rn;
        uint8_t origin;
        struct aspath *aspath = NULL;
-       struct aspath *asmerge = NULL;
        struct community *community = NULL;
-       struct community *commerge = NULL;
        struct ecommunity *ecommunity = NULL;
-       struct ecommunity *ecommerge = NULL;
        struct lcommunity *lcommunity = NULL;
-       struct lcommunity *lcommerge = NULL;
        struct bgp_path_info *pi;
        unsigned long match = 0;
        uint8_t atomic_aggregate = 0;
@@ -5709,9 +5740,6 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
                        if (BGP_PATH_HOLDDOWN(pi))
                                continue;
 
-                       if (del && pi == del)
-                               continue;
-
                        if (pi->attr->flag
                            & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))
                                atomic_aggregate = 1;
@@ -5742,8 +5770,18 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
                         * route MUST have the ORIGIN attribute with the value
                         * EGP.
                         */
-                       if (origin < pi->attr->origin)
-                               origin = pi->attr->origin;
+                       switch (pi->attr->origin) {
+                       case BGP_ORIGIN_INCOMPLETE:
+                               aggregate->incomplete_origin_count++;
+                       break;
+                       case BGP_ORIGIN_EGP:
+                               aggregate->egp_origin_count++;
+                       break;
+                       default:
+                               /*Do nothing.
+                                */
+                       break;
+                       }
 
                        if (!aggregate->as_set)
                                continue;
@@ -5752,130 +5790,68 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p,
                         * as-set aggregate route generate origin, as path,
                         * and community aggregation.
                         */
-                       if (aspath) {
-                               asmerge = aspath_aggregate(aspath,
-                                                          pi->attr->aspath);
-                               aspath_free(aspath);
-                               aspath = asmerge;
-                       } else
-                               aspath = aspath_dup(pi->attr->aspath);
-
-                       if (pi->attr->community) {
-                               if (community) {
-                                       commerge = community_merge(
-                                               community, pi->attr->community);
-                                       community =
-                                               community_uniq_sort(commerge);
-                                       community_free(&commerge);
-                               } else
-                                       community = community_dup(
-                                               pi->attr->community);
-                       }
-
-                       if (pi->attr->ecommunity) {
-                               if (ecommunity) {
-                                       ecommerge = ecommunity_merge(
-                                               ecommunity,
-                                               pi->attr->ecommunity);
-                                       ecommunity =
-                                               ecommunity_uniq_sort(ecommerge);
-                                       ecommunity_free(&ecommerge);
-                               } else
-                                       ecommunity = ecommunity_dup(
-                                               pi->attr->ecommunity);
-                       }
-
-                       if (pi->attr->lcommunity) {
-                               if (lcommunity) {
-                                       lcommerge = lcommunity_merge(
-                                               lcommunity,
-                                               pi->attr->lcommunity);
-                                       lcommunity =
-                                               lcommunity_uniq_sort(lcommerge);
-                                       lcommunity_free(&lcommerge);
-                               } else
-                                       lcommunity = lcommunity_dup(
-                                               pi->attr->lcommunity);
-                       }
+                       /* Compute aggregate route's as-path.
+                        */
+                       bgp_compute_aggregate_aspath(aggregate,
+                                                    pi->attr->aspath);
+
+                       /* Compute aggregate route's community.
+                        */
+                       if (pi->attr->community)
+                               bgp_compute_aggregate_community(
+                                                       aggregate,
+                                                       pi->attr->community);
+
+                       /* Compute aggregate route's extended community.
+                        */
+                       if (pi->attr->ecommunity)
+                               bgp_compute_aggregate_ecommunity(
+                                                       aggregate,
+                                                       pi->attr->ecommunity);
+
+                       /* Compute aggregate route's large community.
+                        */
+                       if (pi->attr->lcommunity)
+                               bgp_compute_aggregate_lcommunity(
+                                                       aggregate,
+                                                       pi->attr->lcommunity);
                }
                if (match)
                        bgp_process(bgp, rn, afi, safi);
        }
        bgp_unlock_node(top);
 
-       if (pinew) {
-               aggregate->count++;
 
-               if (aggregate->summary_only)
-                       (bgp_path_info_extra_get(pinew))->suppress++;
+       if (aggregate->incomplete_origin_count > 0)
+               origin = BGP_ORIGIN_INCOMPLETE;
+       else if (aggregate->egp_origin_count > 0)
+               origin = BGP_ORIGIN_EGP;
 
-               if (origin < pinew->attr->origin)
-                       origin = pinew->attr->origin;
+       if (aggregate->as_set) {
+               if (aggregate->aspath)
+                       /* Retrieve aggregate route's as-path.
+                        */
+                       aspath = aspath_dup(aggregate->aspath);
 
-               if (aggregate->as_set) {
-                       if (aspath) {
-                               asmerge = aspath_aggregate(aspath,
-                                                          pinew->attr->aspath);
-                               aspath_free(aspath);
-                               aspath = asmerge;
-                       } else
-                               aspath = aspath_dup(pinew->attr->aspath);
+               if (aggregate->community)
+                       /* Retrieve aggregate route's community.
+                        */
+                       community = community_dup(aggregate->community);
 
-                       if (pinew->attr->community) {
-                               if (community) {
-                                       commerge = community_merge(
-                                               community,
-                                               pinew->attr->community);
-                                       community =
-                                               community_uniq_sort(commerge);
-                                       community_free(&commerge);
-                               } else
-                                       community = community_dup(
-                                               pinew->attr->community);
-                       }
+               if (aggregate->ecommunity)
+                       /* Retrieve aggregate route's ecommunity.
+                        */
+                       ecommunity = ecommunity_dup(aggregate->ecommunity);
 
-                       if (pinew->attr->ecommunity) {
-                               if (ecommunity) {
-                                       ecommerge = ecommunity_merge(
-                                               ecommunity,
-                                               pinew->attr->ecommunity);
-                                       ecommunity =
-                                               ecommunity_uniq_sort(ecommerge);
-                                       ecommunity_free(&ecommerge);
-                               } else
-                                       ecommunity = ecommunity_dup(
-                                               pinew->attr->ecommunity);
-                       }
-
-                       if (pinew->attr->lcommunity) {
-                               if (lcommunity) {
-                                       lcommerge = lcommunity_merge(
-                                               lcommunity,
-                                               pinew->attr->lcommunity);
-                                       lcommunity =
-                                               lcommunity_uniq_sort(lcommerge);
-                                       lcommunity_free(&lcommerge);
-                               } else
-                                       lcommunity = lcommunity_dup(
-                                               pinew->attr->lcommunity);
-                       }
-               }
+               if (aggregate->lcommunity)
+                       /* Retrieve aggregate route's lcommunity.
+                        */
+                       lcommunity = lcommunity_dup(aggregate->lcommunity);
        }
 
        bgp_aggregate_install(bgp, afi, safi, p, origin, aspath, community,
                              ecommunity, lcommunity, atomic_aggregate,
                              aggregate);
-
-       if (aggregate->count == 0) {
-               if (aspath)
-                       aspath_free(aspath);
-               if (community)
-                       community_free(&community);
-               if (ecommunity)
-                       ecommunity_free(&ecommunity);
-               if (lcommunity)
-                       lcommunity_free(&lcommunity);
-       }
 }
 
 static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
@@ -5914,6 +5890,41 @@ static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
                                }
                        }
                        aggregate->count--;
+
+                       if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE)
+                               aggregate->incomplete_origin_count--;
+                       else if (pi->attr->origin == BGP_ORIGIN_EGP)
+                               aggregate->egp_origin_count--;
+
+                       if (aggregate->as_set) {
+                               /* Remove as-path from aggregate.
+                                */
+                               bgp_remove_aspath_from_aggregate(
+                                                       aggregate,
+                                                       pi->attr->aspath);
+
+                               if (pi->attr->community)
+                                       /* Remove community from aggregate.
+                                        */
+                                       bgp_remove_community_from_aggregate(
+                                                       aggregate,
+                                                       pi->attr->community);
+
+                               if (pi->attr->ecommunity)
+                                       /* Remove ecommunity from aggregate.
+                                        */
+                                       bgp_remove_ecommunity_from_aggregate(
+                                                       aggregate,
+                                                       pi->attr->ecommunity);
+
+                               if (pi->attr->lcommunity)
+                                       /* Remove lcommunity from aggregate.
+                                        */
+                                       bgp_remove_lcommunity_from_aggregate(
+                                                       aggregate,
+                                                       pi->attr->lcommunity);
+                       }
+
                }
 
                /* If this node was suppressed, process the change. */
@@ -5923,6 +5934,210 @@ static void bgp_aggregate_delete(struct bgp *bgp, struct prefix *p, afi_t afi,
        bgp_unlock_node(top);
 }
 
+static void bgp_add_route_to_aggregate(struct bgp *bgp, struct prefix *aggr_p,
+                                      struct bgp_path_info *pinew, afi_t afi,
+                                      safi_t safi,
+                                      struct bgp_aggregate *aggregate)
+{
+       uint8_t origin;
+       struct aspath *aspath = NULL;
+       uint8_t atomic_aggregate = 0;
+       struct community *community = NULL;
+       struct ecommunity *ecommunity = NULL;
+       struct lcommunity *lcommunity = NULL;
+
+       /* ORIGIN attribute: If at least one route among routes that are
+        * aggregated has ORIGIN with the value INCOMPLETE, then the
+        * aggregated route must have the ORIGIN attribute with the value
+        * INCOMPLETE. Otherwise, if at least one route among routes that
+        * are aggregated has ORIGIN with the value EGP, then the aggregated
+        * route must have the origin attribute with the value EGP. In all
+        * other case the value of the ORIGIN attribute of the aggregated
+        * route is INTERNAL.
+        */
+       origin = BGP_ORIGIN_IGP;
+
+       aggregate->count++;
+
+       if (aggregate->summary_only)
+               (bgp_path_info_extra_get(pinew))->suppress++;
+
+       switch (pinew->attr->origin) {
+       case BGP_ORIGIN_INCOMPLETE:
+               aggregate->incomplete_origin_count++;
+       break;
+       case BGP_ORIGIN_EGP:
+               aggregate->egp_origin_count++;
+       break;
+       default:
+               /* Do nothing.
+                */
+       break;
+       }
+
+       if (aggregate->incomplete_origin_count > 0)
+               origin = BGP_ORIGIN_INCOMPLETE;
+       else if (aggregate->egp_origin_count > 0)
+               origin = BGP_ORIGIN_EGP;
+
+       if (aggregate->as_set) {
+               /* Compute aggregate route's as-path.
+                */
+               bgp_compute_aggregate_aspath(aggregate,
+                                            pinew->attr->aspath);
+
+               /* Compute aggregate route's community.
+                */
+               if (pinew->attr->community)
+                       bgp_compute_aggregate_community(
+                                               aggregate,
+                                               pinew->attr->community);
+
+               /* Compute aggregate route's extended community.
+                */
+               if (pinew->attr->ecommunity)
+                       bgp_compute_aggregate_ecommunity(
+                                       aggregate,
+                                       pinew->attr->ecommunity);
+
+               /* Compute aggregate route's large community.
+                */
+               if (pinew->attr->lcommunity)
+                       bgp_compute_aggregate_lcommunity(
+                                       aggregate,
+                                       pinew->attr->lcommunity);
+
+               /* Retrieve aggregate route's as-path.
+                */
+               if (aggregate->aspath)
+                       aspath = aspath_dup(aggregate->aspath);
+
+               /* Retrieve aggregate route's community.
+                */
+               if (aggregate->community)
+                       community = community_dup(aggregate->community);
+
+               /* Retrieve aggregate route's ecommunity.
+                */
+               if (aggregate->ecommunity)
+                       ecommunity = ecommunity_dup(aggregate->ecommunity);
+
+               /* Retrieve aggregate route's lcommunity.
+                */
+               if (aggregate->lcommunity)
+                       lcommunity = lcommunity_dup(aggregate->lcommunity);
+       }
+
+       bgp_aggregate_install(bgp, afi, safi, aggr_p, origin,
+                             aspath, community, ecommunity,
+                             lcommunity, atomic_aggregate, aggregate);
+}
+
+static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi,
+                                           safi_t safi,
+                                           struct bgp_path_info *pi,
+                                           struct bgp_aggregate *aggregate,
+                                           struct prefix *aggr_p)
+{
+       uint8_t origin;
+       struct aspath *aspath = NULL;
+       uint8_t atomic_aggregate = 0;
+       struct community *community = NULL;
+       struct ecommunity *ecommunity = NULL;
+       struct lcommunity *lcommunity = NULL;
+       unsigned long match = 0;
+
+       if (BGP_PATH_HOLDDOWN(pi))
+               return;
+
+       if (pi->sub_type == BGP_ROUTE_AGGREGATE)
+               return;
+
+       if (aggregate->summary_only
+               && pi->extra
+               && pi->extra->suppress > 0) {
+               pi->extra->suppress--;
+
+               if (pi->extra->suppress == 0) {
+                       bgp_path_info_set_flag(pi->net, pi,
+                                              BGP_PATH_ATTR_CHANGED);
+                       match++;
+               }
+       }
+
+       if (aggregate->count > 0)
+               aggregate->count--;
+
+       if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE)
+               aggregate->incomplete_origin_count--;
+       else if (pi->attr->origin == BGP_ORIGIN_EGP)
+               aggregate->egp_origin_count--;
+
+       if (aggregate->as_set) {
+               /* Remove as-path from aggregate.
+                */
+               bgp_remove_aspath_from_aggregate(aggregate,
+                                                pi->attr->aspath);
+
+               if (pi->attr->community)
+                       /* Remove community from aggregate.
+                        */
+                       bgp_remove_community_from_aggregate(
+                                                       aggregate,
+                                                       pi->attr->community);
+
+               if (pi->attr->ecommunity)
+                       /* Remove ecommunity from aggregate.
+                        */
+                       bgp_remove_ecommunity_from_aggregate(
+                                                       aggregate,
+                                                       pi->attr->ecommunity);
+
+               if (pi->attr->lcommunity)
+                       /* Remove lcommunity from aggregate.
+                        */
+                       bgp_remove_lcommunity_from_aggregate(
+                                                       aggregate,
+                                                       pi->attr->lcommunity);
+       }
+
+       /* If this node was suppressed, process the change. */
+       if (match)
+               bgp_process(bgp, pi->net, afi, safi);
+
+       origin = BGP_ORIGIN_IGP;
+       if (aggregate->incomplete_origin_count > 0)
+               origin = BGP_ORIGIN_INCOMPLETE;
+       else if (aggregate->egp_origin_count > 0)
+               origin = BGP_ORIGIN_EGP;
+
+       if (aggregate->as_set) {
+               /* Retrieve aggregate route's as-path.
+                */
+               if (aggregate->aspath)
+                       aspath = aspath_dup(aggregate->aspath);
+
+               /* Retrieve aggregate route's community.
+                */
+               if (aggregate->community)
+                       community = community_dup(aggregate->community);
+
+               /* Retrieve aggregate route's ecommunity.
+                */
+               if (aggregate->ecommunity)
+                       ecommunity = ecommunity_dup(aggregate->ecommunity);
+
+               /* Retrieve aggregate route's lcommunity.
+                */
+               if (aggregate->lcommunity)
+                       lcommunity = lcommunity_dup(aggregate->lcommunity);
+       }
+
+       bgp_aggregate_install(bgp, afi, safi, aggr_p, origin,
+                             aspath, community, ecommunity,
+                             lcommunity, atomic_aggregate, aggregate);
+}
+
 void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p,
                             struct bgp_path_info *pi, afi_t afi, safi_t safi)
 {
@@ -5949,9 +6164,8 @@ void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p,
        for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) {
                aggregate = bgp_node_get_bgp_aggregate_info(rn);
                if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) {
-                       bgp_aggregate_delete(bgp, &rn->p, afi, safi, aggregate);
-                       bgp_aggregate_route(bgp, &rn->p, pi, afi, safi, NULL,
-                                           aggregate);
+                       bgp_add_route_to_aggregate(bgp, &rn->p, pi, afi,
+                                                  safi, aggregate);
                }
        }
        bgp_unlock_node(child);
@@ -5980,9 +6194,8 @@ void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p,
        for (rn = child; rn; rn = bgp_node_parent_nolock(rn)) {
                aggregate = bgp_node_get_bgp_aggregate_info(rn);
                if (aggregate != NULL && rn->p.prefixlen < p->prefixlen) {
-                       bgp_aggregate_delete(bgp, &rn->p, afi, safi, aggregate);
-                       bgp_aggregate_route(bgp, &rn->p, NULL, afi, safi, del,
-                                           aggregate);
+                       bgp_remove_route_from_aggregate(bgp, afi, safi,
+                                                       del, aggregate, &rn->p);
                }
        }
        bgp_unlock_node(child);
@@ -6024,6 +6237,59 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str,
 
        /* Unlock aggregate address configuration. */
        bgp_node_set_bgp_aggregate_info(rn, NULL);
+
+       if (aggregate->community)
+               community_free(&aggregate->community);
+
+       if (aggregate->community_hash) {
+               /* Delete all communities in the hash.
+                */
+               hash_clean(aggregate->community_hash,
+                          bgp_aggr_community_remove);
+               /* Free up the community_hash.
+                */
+               hash_free(aggregate->community_hash);
+       }
+
+       if (aggregate->ecommunity)
+               ecommunity_free(&aggregate->ecommunity);
+
+       if (aggregate->ecommunity_hash) {
+               /* Delete all ecommunities in the hash.
+                */
+               hash_clean(aggregate->ecommunity_hash,
+                          bgp_aggr_ecommunity_remove);
+               /* Free up the ecommunity_hash.
+                */
+               hash_free(aggregate->ecommunity_hash);
+       }
+
+       if (aggregate->lcommunity)
+               lcommunity_free(&aggregate->lcommunity);
+
+       if (aggregate->lcommunity_hash) {
+               /* Delete all lcommunities in the hash.
+                */
+               hash_clean(aggregate->lcommunity_hash,
+                          bgp_aggr_lcommunity_remove);
+               /* Free up the lcommunity_hash.
+                */
+               hash_free(aggregate->lcommunity_hash);
+       }
+
+       if (aggregate->aspath)
+               aspath_free(aggregate->aspath);
+
+       if (aggregate->aspath_hash) {
+               /* Delete all as-paths in the hash.
+                */
+               hash_clean(aggregate->aspath_hash,
+                          bgp_aggr_aspath_remove);
+               /* Free up the aspath_hash.
+                */
+               hash_free(aggregate->aspath_hash);
+       }
+
        bgp_aggregate_free(aggregate);
        bgp_unlock_node(rn);
        bgp_unlock_node(rn);
@@ -6077,7 +6343,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
        bgp_node_set_bgp_aggregate_info(rn, aggregate);
 
        /* Aggregate address insert into BGP routing table. */
-       bgp_aggregate_route(bgp, &p, NULL, afi, safi, NULL, aggregate);
+       bgp_aggregate_route(bgp, &p, afi, safi, aggregate);
 
        return CMD_SUCCESS;
 }
@@ -8387,11 +8653,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
                                json_pmsi = json_object_new_object();
                                json_object_string_add(json_pmsi,
                                                       "tunnelType", str);
+                               json_object_int_add(json_pmsi,
+                                               "label",
+                                               label2vni(&attr->label));
                                json_object_object_add(json_path, "pmsi",
                                                       json_pmsi);
                        } else
-                               vty_out(vty, "      PMSI Tunnel Type: %s\n",
-                                       str);
+                               vty_out(vty,
+                                       "      PMSI Tunnel Type: %s, label: %d\n",
+                                       str, label2vni(&attr->label));
                }
 
        }
@@ -11183,8 +11453,7 @@ static int bgp_distance_unset(struct vty *vty, const char *distance_str,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       if (bdistance->access_list)
-               XFREE(MTYPE_AS_LIST, bdistance->access_list);
+       XFREE(MTYPE_AS_LIST, bdistance->access_list);
        bgp_distance_free(bdistance);
 
        bgp_node_set_bgp_path_info(rn, NULL);
@@ -11624,10 +11893,10 @@ DEFUN (clear_ip_bgp_dampening_address_mask,
                                    NULL, 0);
 }
 
-static void show_bgp_peerhash_entry(struct hash_backet *backet, void *arg)
+static void show_bgp_peerhash_entry(struct hash_bucket *bucket, void *arg)
 {
        struct vty *vty = arg;
-       struct peer *peer = backet->data;
+       struct peer *peer = bucket->data;
        char buf[SU_ADDRSTRLEN];
 
        vty_out(vty, "\tPeer: %s %s\n", peer->host,
@@ -11771,10 +12040,8 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
                                decode_label(&bgp_static->label), esi, buf2,
                                macrouter);
 
-                       if (macrouter)
-                               XFREE(MTYPE_TMP, macrouter);
-                       if (esi)
-                               XFREE(MTYPE_TMP, esi);
+                       XFREE(MTYPE_TMP, macrouter);
+                       XFREE(MTYPE_TMP, esi);
                }
        }
 }