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