1 /* Community attribute related functions.
2 * Copyright (C) 1998, 2001 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include "bgpd/bgp_memory.h"
30 #include "bgpd/bgp_community.h"
31 #include "bgpd/bgp_community_alias.h"
33 /* Hash of community attribute. */
34 static struct hash
*comhash
;
36 /* Allocate a new communities value. */
37 static struct community
*community_new(void)
39 return XCALLOC(MTYPE_COMMUNITY
, sizeof(struct community
));
42 /* Free communities value. */
43 void community_free(struct community
**com
)
48 XFREE(MTYPE_COMMUNITY_VAL
, (*com
)->val
);
49 XFREE(MTYPE_COMMUNITY_STR
, (*com
)->str
);
52 json_object_free((*com
)->json
);
56 XFREE(MTYPE_COMMUNITY
, (*com
));
59 /* Add one community value to the community. */
60 void community_add_val(struct community
*com
, uint32_t val
)
64 com
->val
= XREALLOC(MTYPE_COMMUNITY_VAL
, com
->val
,
67 com
->val
= XMALLOC(MTYPE_COMMUNITY_VAL
, com_length(com
));
70 memcpy(com_lastval(com
), &val
, sizeof(uint32_t));
73 /* Delete one community. */
74 void community_del_val(struct community
*com
, uint32_t *val
)
82 while (i
< com
->size
) {
83 if (memcmp(com
->val
+ i
, val
, sizeof(uint32_t)) == 0) {
84 c
= com
->size
- i
- 1;
87 memmove(com
->val
+ i
, com
->val
+ (i
+ 1),
93 com
->val
= XREALLOC(MTYPE_COMMUNITY_VAL
,
94 com
->val
, com_length(com
));
96 XFREE(MTYPE_COMMUNITY_VAL
, com
->val
);
104 /* Delete all communities listed in com2 from com1 */
105 struct community
*community_delete(struct community
*com1
,
106 struct community
*com2
)
110 while (i
< com2
->size
) {
111 community_del_val(com1
, com2
->val
+ i
);
118 /* Callback function from qsort(). */
119 static int community_compare(const void *a1
, const void *a2
)
124 memcpy(&v1
, a1
, sizeof(uint32_t));
125 memcpy(&v2
, a2
, sizeof(uint32_t));
136 bool community_include(struct community
*com
, uint32_t val
)
142 for (i
= 0; i
< com
->size
; i
++)
143 if (memcmp(&val
, com_nthval(com
, i
), sizeof(uint32_t)) == 0)
148 uint32_t community_val_get(struct community
*com
, int i
)
153 p
= (uint8_t *)com
->val
;
154 p
+= (i
* COMMUNITY_SIZE
);
156 memcpy(&val
, p
, sizeof(uint32_t));
161 /* Sort and uniq given community. */
162 struct community
*community_uniq_sort(struct community
*com
)
165 struct community
*new;
171 new = community_new();
174 for (i
= 0; i
< com
->size
; i
++) {
175 val
= community_val_get(com
, i
);
177 if (!community_include(new, val
))
178 community_add_val(new, val
);
181 qsort(new->val
, new->size
, sizeof(uint32_t), community_compare
);
186 /* Convert communities attribute to string.
188 For Well-known communities value, below keyword is used.
191 0xFFFF0000 "graceful-shutdown"
192 0xFFFF0001 "accept-own"
193 0xFFFF0002 "route-filter-translated-v4"
194 0xFFFF0003 "route-filter-v4"
195 0xFFFF0004 "route-filter-translated-v6"
196 0xFFFF0005 "route-filter-v6"
197 0xFFFF0006 "llgr-stale"
199 0xFFFF0008 "accept-own-nexthop"
200 0xFFFF029A "blackhole"
201 0xFFFFFF01 "no-export"
202 0xFFFFFF02 "no-advertise"
203 0xFFFFFF03 "local-AS"
206 For other values, "AS:VAL" format is used. */
207 static void set_community_string(struct community
*com
, bool make_json
)
216 json_object
*json_community_list
= NULL
;
217 json_object
*json_string
= NULL
;
223 com
->json
= json_object_new_object();
224 json_community_list
= json_object_new_array();
227 /* When communities attribute is empty. */
228 if (com
->size
== 0) {
229 str
= XMALLOC(MTYPE_COMMUNITY_STR
, 1);
233 json_object_string_add(com
->json
, "string", "");
234 json_object_object_add(com
->json
, "list",
235 json_community_list
);
241 /* Memory allocation is time consuming work. So we calculate
242 required string length first. */
245 for (i
= 0; i
< com
->size
; i
++) {
246 memcpy(&comval
, com_nthval(com
, i
), sizeof(uint32_t));
247 comval
= ntohl(comval
);
250 case COMMUNITY_INTERNET
:
251 len
+= strlen(" internet");
253 case COMMUNITY_GSHUT
:
254 len
+= strlen(" graceful-shutdown");
256 case COMMUNITY_ACCEPT_OWN
:
257 len
+= strlen(" accept-own");
259 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4
:
260 len
+= strlen(" route-filter-translated-v4");
262 case COMMUNITY_ROUTE_FILTER_v4
:
263 len
+= strlen(" route-filter-v4");
265 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6
:
266 len
+= strlen(" route-filter-translated-v6");
268 case COMMUNITY_ROUTE_FILTER_v6
:
269 len
+= strlen(" route-filter-v6");
271 case COMMUNITY_LLGR_STALE
:
272 len
+= strlen(" llgr-stale");
274 case COMMUNITY_NO_LLGR
:
275 len
+= strlen(" no-llgr");
277 case COMMUNITY_ACCEPT_OWN_NEXTHOP
:
278 len
+= strlen(" accept-own-nexthop");
280 case COMMUNITY_BLACKHOLE
:
281 len
+= strlen(" blackhole");
283 case COMMUNITY_NO_EXPORT
:
284 len
+= strlen(" no-export");
286 case COMMUNITY_NO_ADVERTISE
:
287 len
+= strlen(" no-advertise");
289 case COMMUNITY_LOCAL_AS
:
290 len
+= strlen(" local-AS");
292 case COMMUNITY_NO_PEER
:
293 len
+= strlen(" no-peer");
301 /* Allocate memory. */
302 str
= XCALLOC(MTYPE_COMMUNITY_STR
, len
);
305 /* Fill in string. */
306 for (i
= 0; i
< com
->size
; i
++) {
307 memcpy(&comval
, com_nthval(com
, i
), sizeof(uint32_t));
308 comval
= ntohl(comval
);
313 strlcat(str
, " ", len
);
316 case COMMUNITY_INTERNET
:
317 strlcat(str
, "internet", len
);
320 json_object_new_string("internet");
321 json_object_array_add(json_community_list
,
325 case COMMUNITY_GSHUT
:
326 strlcat(str
, "graceful-shutdown", len
);
328 json_string
= json_object_new_string(
330 json_object_array_add(json_community_list
,
334 case COMMUNITY_ACCEPT_OWN
:
335 strlcat(str
, "accept-own", len
);
337 json_string
= json_object_new_string(
339 json_object_array_add(json_community_list
,
343 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4
:
344 strlcat(str
, "route-filter-translated-v4", len
);
346 json_string
= json_object_new_string(
347 "routeFilterTranslatedV4");
348 json_object_array_add(json_community_list
,
352 case COMMUNITY_ROUTE_FILTER_v4
:
353 strlcat(str
, "route-filter-v4", len
);
355 json_string
= json_object_new_string(
357 json_object_array_add(json_community_list
,
361 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6
:
362 strlcat(str
, "route-filter-translated-v6", len
);
364 json_string
= json_object_new_string(
365 "routeFilterTranslatedV6");
366 json_object_array_add(json_community_list
,
370 case COMMUNITY_ROUTE_FILTER_v6
:
371 strlcat(str
, "route-filter-v6", len
);
373 json_string
= json_object_new_string(
375 json_object_array_add(json_community_list
,
379 case COMMUNITY_LLGR_STALE
:
380 strlcat(str
, "llgr-stale", len
);
382 json_string
= json_object_new_string(
384 json_object_array_add(json_community_list
,
388 case COMMUNITY_NO_LLGR
:
389 strlcat(str
, "no-llgr", len
);
391 json_string
= json_object_new_string(
393 json_object_array_add(json_community_list
,
397 case COMMUNITY_ACCEPT_OWN_NEXTHOP
:
398 strlcat(str
, "accept-own-nexthop", len
);
400 json_string
= json_object_new_string(
402 json_object_array_add(json_community_list
,
406 case COMMUNITY_BLACKHOLE
:
407 strlcat(str
, "blackhole", len
);
409 json_string
= json_object_new_string(
411 json_object_array_add(json_community_list
,
415 case COMMUNITY_NO_EXPORT
:
416 strlcat(str
, "no-export", len
);
419 json_object_new_string("noExport");
420 json_object_array_add(json_community_list
,
424 case COMMUNITY_NO_ADVERTISE
:
425 strlcat(str
, "no-advertise", len
);
428 json_object_new_string("noAdvertise");
429 json_object_array_add(json_community_list
,
433 case COMMUNITY_LOCAL_AS
:
434 strlcat(str
, "local-AS", len
);
436 json_string
= json_object_new_string("localAs");
437 json_object_array_add(json_community_list
,
441 case COMMUNITY_NO_PEER
:
442 strlcat(str
, "no-peer", len
);
444 json_string
= json_object_new_string("noPeer");
445 json_object_array_add(json_community_list
,
450 as
= (comval
>> 16) & 0xFFFF;
451 val
= comval
& 0xFFFF;
453 snprintf(buf
, sizeof(buf
), "%u:%d", as
, val
);
454 const char *com2alias
= bgp_community2alias(buf
);
456 strlcat(str
, com2alias
, len
);
458 json_string
= json_object_new_string(com2alias
);
459 json_object_array_add(json_community_list
,
467 json_object_string_add(com
->json
, "string", str
);
468 json_object_object_add(com
->json
, "list", json_community_list
);
473 /* Intern communities attribute. */
474 struct community
*community_intern(struct community
*com
)
476 struct community
*find
;
478 /* Assert this community structure is not interned. */
479 assert(com
->refcnt
== 0);
481 /* Lookup community hash. */
482 find
= (struct community
*)hash_get(comhash
, com
, hash_alloc_intern
);
484 /* Arguemnt com is allocated temporary. So when it is not used in
485 hash, it should be freed. */
487 community_free(&com
);
489 /* Increment refrence counter. */
494 set_community_string(find
, false);
499 /* Free community attribute. */
500 void community_unintern(struct community
**com
)
502 struct community
*ret
;
507 /* Pull off from hash. */
508 if ((*com
)->refcnt
== 0) {
509 /* Community value com must exist in hash. */
510 ret
= (struct community
*)hash_release(comhash
, *com
);
517 /* Create new community attribute. */
518 struct community
*community_parse(uint32_t *pnt
, unsigned short length
)
520 struct community tmp
;
521 struct community
*new;
523 /* If length is malformed return NULL. */
524 if (length
% COMMUNITY_SIZE
)
527 /* Make temporary community for hash look up. */
528 tmp
.size
= length
/ COMMUNITY_SIZE
;
531 new = community_uniq_sort(&tmp
);
533 return community_intern(new);
536 struct community
*community_dup(struct community
*com
)
538 struct community
*new;
540 new = XCALLOC(MTYPE_COMMUNITY
, sizeof(struct community
));
541 new->size
= com
->size
;
543 new->val
= XMALLOC(MTYPE_COMMUNITY_VAL
,
544 com
->size
* COMMUNITY_SIZE
);
545 memcpy(new->val
, com
->val
, com
->size
* COMMUNITY_SIZE
);
551 /* Retrun string representation of communities attribute. */
552 char *community_str(struct community
*com
, bool make_json
)
557 if (make_json
&& !com
->json
&& com
->str
)
558 XFREE(MTYPE_COMMUNITY_STR
, com
->str
);
561 set_community_string(com
, make_json
);
565 /* Make hash value of community attribute. This function is used by
567 unsigned int community_hash_make(const struct community
*com
)
569 uint32_t *pnt
= com
->val
;
571 return jhash2(pnt
, com
->size
, 0x43ea96c1);
574 bool community_match(const struct community
*com1
, const struct community
*com2
)
579 if (com1
== NULL
&& com2
== NULL
)
582 if (com1
== NULL
|| com2
== NULL
)
585 if (com1
->size
< com2
->size
)
588 /* Every community on com2 needs to be on com1 for this to match */
589 while (i
< com1
->size
&& j
< com2
->size
) {
590 if (memcmp(com1
->val
+ i
, com2
->val
+ j
, sizeof(uint32_t)) == 0)
601 /* If two aspath have same value then return 1 else return 0. This
602 function is used by hash package. */
603 bool community_cmp(const struct community
*com1
, const struct community
*com2
)
605 if (com1
== NULL
&& com2
== NULL
)
607 if (com1
== NULL
|| com2
== NULL
)
610 if (com1
->size
== com2
->size
)
611 if (memcmp(com1
->val
, com2
->val
, com1
->size
* COMMUNITY_SIZE
)
617 /* Add com2 to the end of com1. */
618 struct community
*community_merge(struct community
*com1
,
619 struct community
*com2
)
623 XREALLOC(MTYPE_COMMUNITY_VAL
, com1
->val
,
624 (com1
->size
+ com2
->size
) * COMMUNITY_SIZE
);
626 com1
->val
= XMALLOC(MTYPE_COMMUNITY_VAL
,
627 (com1
->size
+ com2
->size
) * COMMUNITY_SIZE
);
629 memcpy(com1
->val
+ com1
->size
, com2
->val
, com2
->size
* COMMUNITY_SIZE
);
630 com1
->size
+= com2
->size
;
635 /* Community token enum. */
636 enum community_token
{
638 community_token_gshut
,
639 community_token_accept_own
,
640 community_token_route_filter_translated_v4
,
641 community_token_route_filter_v4
,
642 community_token_route_filter_translated_v6
,
643 community_token_route_filter_v6
,
644 community_token_llgr_stale
,
645 community_token_no_llgr
,
646 community_token_accept_own_nexthop
,
647 community_token_blackhole
,
648 community_token_no_export
,
649 community_token_no_advertise
,
650 community_token_local_as
,
651 community_token_no_peer
,
652 community_token_unknown
655 /* Helper to check if a given community is valid */
656 static bool community_valid(const char *community
)
663 frrstr_split(community
, ":", &splits
, &num
);
665 for (int i
= 0; i
< num
; i
++) {
666 if (strtoul(splits
[i
], NULL
, 10) > UINT16_MAX
)
669 if (strlen(splits
[i
]) == 0)
673 XFREE(MTYPE_TMP
, splits
[i
]);
675 XFREE(MTYPE_TMP
, splits
);
677 return (octets
< 2 || invalid
) ? false : true;
680 /* Get next community token from string. */
682 community_gettoken(const char *buf
, enum community_token
*token
, uint32_t *val
)
686 /* Skip white space. */
687 while (isspace((unsigned char)*p
))
690 /* Check the end of the line. */
694 /* Well known community string check. */
695 if (isalpha((unsigned char)*p
)) {
696 if (strncmp(p
, "internet", strlen("internet")) == 0) {
697 *val
= COMMUNITY_INTERNET
;
698 *token
= community_token_no_export
;
699 p
+= strlen("internet");
702 if (strncmp(p
, "graceful-shutdown", strlen("graceful-shutdown"))
704 *val
= COMMUNITY_GSHUT
;
705 *token
= community_token_gshut
;
706 p
+= strlen("graceful-shutdown");
709 if (strncmp(p
, "accept-own-nexthop",
710 strlen("accept-own-nexthop"))
712 *val
= COMMUNITY_ACCEPT_OWN_NEXTHOP
;
713 *token
= community_token_accept_own_nexthop
;
714 p
+= strlen("accept-own-nexthop");
717 if (strncmp(p
, "accept-own", strlen("accept-own"))
719 *val
= COMMUNITY_ACCEPT_OWN
;
720 *token
= community_token_accept_own
;
721 p
+= strlen("accept-own");
724 if (strncmp(p
, "route-filter-translated-v4",
725 strlen("route-filter-translated-v4"))
727 *val
= COMMUNITY_ROUTE_FILTER_TRANSLATED_v4
;
728 *token
= community_token_route_filter_translated_v4
;
729 p
+= strlen("route-filter-translated-v4");
732 if (strncmp(p
, "route-filter-v4", strlen("route-filter-v4"))
734 *val
= COMMUNITY_ROUTE_FILTER_v4
;
735 *token
= community_token_route_filter_v4
;
736 p
+= strlen("route-filter-v4");
739 if (strncmp(p
, "route-filter-translated-v6",
740 strlen("route-filter-translated-v6"))
742 *val
= COMMUNITY_ROUTE_FILTER_TRANSLATED_v6
;
743 *token
= community_token_route_filter_translated_v6
;
744 p
+= strlen("route-filter-translated-v6");
747 if (strncmp(p
, "route-filter-v6", strlen("route-filter-v6"))
749 *val
= COMMUNITY_ROUTE_FILTER_v6
;
750 *token
= community_token_route_filter_v6
;
751 p
+= strlen("route-filter-v6");
754 if (strncmp(p
, "llgr-stale", strlen("llgr-stale"))
756 *val
= COMMUNITY_LLGR_STALE
;
757 *token
= community_token_llgr_stale
;
758 p
+= strlen("llgr-stale");
761 if (strncmp(p
, "no-llgr", strlen("no-llgr"))
763 *val
= COMMUNITY_NO_LLGR
;
764 *token
= community_token_no_llgr
;
765 p
+= strlen("no-llgr");
768 if (strncmp(p
, "blackhole", strlen("blackhole"))
770 *val
= COMMUNITY_BLACKHOLE
;
771 *token
= community_token_blackhole
;
772 p
+= strlen("blackhole");
775 if (strncmp(p
, "no-export", strlen("no-export")) == 0) {
776 *val
= COMMUNITY_NO_EXPORT
;
777 *token
= community_token_no_export
;
778 p
+= strlen("no-export");
781 if (strncmp(p
, "no-advertise", strlen("no-advertise")) == 0) {
782 *val
= COMMUNITY_NO_ADVERTISE
;
783 *token
= community_token_no_advertise
;
784 p
+= strlen("no-advertise");
787 if (strncmp(p
, "local-AS", strlen("local-AS")) == 0) {
788 *val
= COMMUNITY_LOCAL_AS
;
789 *token
= community_token_local_as
;
790 p
+= strlen("local-AS");
793 if (strncmp(p
, "no-peer", strlen("no-peer")) == 0) {
794 *val
= COMMUNITY_NO_PEER
;
795 *token
= community_token_no_peer
;
796 p
+= strlen("no-peer");
800 /* Unknown string. */
801 *token
= community_token_unknown
;
805 /* Community value. */
806 if (isdigit((unsigned char)*p
)) {
809 uint32_t community_low
= 0;
810 uint32_t community_high
= 0;
812 if (!community_valid(p
)) {
813 *token
= community_token_unknown
;
817 while (isdigit((unsigned char)*p
) || *p
== ':') {
820 *token
= community_token_unknown
;
826 if (community_low
> UINT16_MAX
) {
828 community_token_unknown
;
832 community_high
= community_low
<< 16;
838 community_low
+= (*p
- '0');
843 *token
= community_token_unknown
;
847 *val
= community_high
+ community_low
;
848 *token
= community_token_val
;
851 *token
= community_token_unknown
;
855 /* convert string to community structure */
856 struct community
*community_str2com(const char *str
)
858 struct community
*com
= NULL
;
859 struct community
*com_sort
= NULL
;
861 enum community_token token
= community_token_unknown
;
864 str
= community_gettoken(str
, &token
, &val
);
867 case community_token_val
:
868 case community_token_gshut
:
869 case community_token_accept_own
:
870 case community_token_route_filter_translated_v4
:
871 case community_token_route_filter_v4
:
872 case community_token_route_filter_translated_v6
:
873 case community_token_route_filter_v6
:
874 case community_token_llgr_stale
:
875 case community_token_no_llgr
:
876 case community_token_accept_own_nexthop
:
877 case community_token_blackhole
:
878 case community_token_no_export
:
879 case community_token_no_advertise
:
880 case community_token_local_as
:
881 case community_token_no_peer
:
883 com
= community_new();
886 community_add_val(com
, val
);
888 case community_token_unknown
:
890 community_free(&com
);
895 com_sort
= community_uniq_sort(com
);
896 community_free(&com
);
901 /* Return communities hash entry count. */
902 unsigned long community_count(void)
904 return comhash
->count
;
907 /* Return communities hash. */
908 struct hash
*community_hash(void)
913 /* Initialize comminity related hash. */
914 void community_init(void)
917 hash_create((unsigned int (*)(const void *))community_hash_make
,
918 (bool (*)(const void *, const void *))community_cmp
,
919 "BGP Community Hash");
922 void community_finish(void)
928 static struct community
*bgp_aggr_community_lookup(
929 struct bgp_aggregate
*aggregate
,
930 struct community
*community
)
932 return hash_lookup(aggregate
->community_hash
, community
);
935 static void *bgp_aggr_communty_hash_alloc(void *p
)
937 struct community
*ref
= (struct community
*)p
;
938 struct community
*community
= NULL
;
940 community
= community_dup(ref
);
944 static void bgp_aggr_community_prepare(struct hash_bucket
*hb
, void *arg
)
946 struct community
*hb_community
= hb
->data
;
947 struct community
**aggr_community
= arg
;
950 *aggr_community
= community_merge(*aggr_community
,
953 *aggr_community
= community_dup(hb_community
);
956 void bgp_aggr_community_remove(void *arg
)
958 struct community
*community
= arg
;
960 community_free(&community
);
963 void bgp_compute_aggregate_community(struct bgp_aggregate
*aggregate
,
964 struct community
*community
)
966 bgp_compute_aggregate_community_hash(aggregate
, community
);
967 bgp_compute_aggregate_community_val(aggregate
);
971 void bgp_compute_aggregate_community_hash(struct bgp_aggregate
*aggregate
,
972 struct community
*community
)
974 struct community
*aggr_community
= NULL
;
976 if ((aggregate
== NULL
) || (community
== NULL
))
979 /* Create hash if not already created.
981 if (aggregate
->community_hash
== NULL
)
982 aggregate
->community_hash
= hash_create(
983 (unsigned int (*)(const void *))community_hash_make
,
984 (bool (*)(const void *, const void *))community_cmp
,
985 "BGP Aggregator community hash");
987 aggr_community
= bgp_aggr_community_lookup(aggregate
, community
);
988 if (aggr_community
== NULL
) {
989 /* Insert community into hash.
991 aggr_community
= hash_get(aggregate
->community_hash
, community
,
992 bgp_aggr_communty_hash_alloc
);
995 /* Increment reference counter.
997 aggr_community
->refcnt
++;
1000 void bgp_compute_aggregate_community_val(struct bgp_aggregate
*aggregate
)
1002 struct community
*commerge
= NULL
;
1004 if (aggregate
== NULL
)
1007 /* Re-compute aggregate's community.
1009 if (aggregate
->community
)
1010 community_free(&aggregate
->community
);
1011 if (aggregate
->community_hash
&&
1012 aggregate
->community_hash
->count
) {
1013 hash_iterate(aggregate
->community_hash
,
1014 bgp_aggr_community_prepare
,
1015 &aggregate
->community
);
1016 commerge
= aggregate
->community
;
1017 aggregate
->community
= community_uniq_sort(commerge
);
1019 community_free(&commerge
);
1025 void bgp_remove_community_from_aggregate(struct bgp_aggregate
*aggregate
,
1026 struct community
*community
)
1028 struct community
*aggr_community
= NULL
;
1029 struct community
*ret_comm
= NULL
;
1032 || (!aggregate
->community_hash
)
1036 /* Look-up the community in the hash.
1038 aggr_community
= bgp_aggr_community_lookup(aggregate
, community
);
1039 if (aggr_community
) {
1040 aggr_community
->refcnt
--;
1042 if (aggr_community
->refcnt
== 0) {
1043 ret_comm
= hash_release(aggregate
->community_hash
,
1045 community_free(&ret_comm
);
1047 bgp_compute_aggregate_community_val(aggregate
);
1052 void bgp_remove_comm_from_aggregate_hash(struct bgp_aggregate
*aggregate
,
1053 struct community
*community
)
1056 struct community
*aggr_community
= NULL
;
1057 struct community
*ret_comm
= NULL
;
1060 || (!aggregate
->community_hash
)
1064 /* Look-up the community in the hash.
1066 aggr_community
= bgp_aggr_community_lookup(aggregate
, community
);
1067 if (aggr_community
) {
1068 aggr_community
->refcnt
--;
1070 if (aggr_community
->refcnt
== 0) {
1071 ret_comm
= hash_release(aggregate
->community_hash
,
1073 community_free(&ret_comm
);