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
28 #include "bgpd/bgp_memory.h"
29 #include "bgpd/bgp_community.h"
31 /* Hash of community attribute. */
32 static struct hash
*comhash
;
34 /* Allocate a new communities value. */
35 static struct community
*community_new(void)
37 return XCALLOC(MTYPE_COMMUNITY
, sizeof(struct community
));
40 /* Free communities value. */
41 void community_free(struct community
**com
)
43 XFREE(MTYPE_COMMUNITY_VAL
, (*com
)->val
);
44 XFREE(MTYPE_COMMUNITY_STR
, (*com
)->str
);
47 json_object_free((*com
)->json
);
51 XFREE(MTYPE_COMMUNITY
, (*com
));
54 /* Add one community value to the community. */
55 static void community_add_val(struct community
*com
, uint32_t val
)
59 com
->val
= XREALLOC(MTYPE_COMMUNITY_VAL
, com
->val
,
62 com
->val
= XMALLOC(MTYPE_COMMUNITY_VAL
, com_length(com
));
65 memcpy(com_lastval(com
), &val
, sizeof(uint32_t));
68 /* Delete one community. */
69 void community_del_val(struct community
*com
, uint32_t *val
)
77 while (i
< com
->size
) {
78 if (memcmp(com
->val
+ i
, val
, sizeof(uint32_t)) == 0) {
79 c
= com
->size
- i
- 1;
82 memmove(com
->val
+ i
, com
->val
+ (i
+ 1),
88 com
->val
= XREALLOC(MTYPE_COMMUNITY_VAL
,
89 com
->val
, com_length(com
));
91 XFREE(MTYPE_COMMUNITY_VAL
, com
->val
);
100 /* Delete all communities listed in com2 from com1 */
101 struct community
*community_delete(struct community
*com1
,
102 struct community
*com2
)
106 while (i
< com2
->size
) {
107 community_del_val(com1
, com2
->val
+ i
);
114 /* Callback function from qsort(). */
115 static int community_compare(const void *a1
, const void *a2
)
120 memcpy(&v1
, a1
, sizeof(uint32_t));
121 memcpy(&v2
, a2
, sizeof(uint32_t));
132 int community_include(struct community
*com
, uint32_t val
)
138 for (i
= 0; i
< com
->size
; i
++)
139 if (memcmp(&val
, com_nthval(com
, i
), sizeof(uint32_t)) == 0)
145 uint32_t community_val_get(struct community
*com
, int i
)
150 p
= (uint8_t *)com
->val
;
153 memcpy(&val
, p
, sizeof(uint32_t));
158 /* Sort and uniq given community. */
159 struct community
*community_uniq_sort(struct community
*com
)
162 struct community
*new;
168 new = community_new();
171 for (i
= 0; i
< com
->size
; i
++) {
172 val
= community_val_get(com
, i
);
174 if (!community_include(new, val
))
175 community_add_val(new, val
);
178 qsort(new->val
, new->size
, sizeof(uint32_t), community_compare
);
183 /* Convert communities attribute to string.
185 For Well-known communities value, below keyword is used.
188 0xFFFF0000 "graceful-shutdown"
189 0xFFFF0001 "accept-own"
190 0xFFFF0002 "route-filter-translated-v4"
191 0xFFFF0003 "route-filter-v4"
192 0xFFFF0004 "route-filter-translated-v6"
193 0xFFFF0005 "route-filter-v6"
194 0xFFFF0006 "llgr-stale"
196 0xFFFF0008 "accept-own-nexthop"
197 0xFFFF029A "blackhole"
198 0xFFFFFF01 "no-export"
199 0xFFFFFF02 "no-advertise"
200 0xFFFFFF03 "local-AS"
203 For other values, "AS:VAL" format is used. */
204 static void set_community_string(struct community
*com
, bool make_json
)
213 json_object
*json_community_list
= NULL
;
214 json_object
*json_string
= NULL
;
220 com
->json
= json_object_new_object();
221 json_community_list
= json_object_new_array();
224 /* When communities attribute is empty. */
225 if (com
->size
== 0) {
226 str
= XMALLOC(MTYPE_COMMUNITY_STR
, 1);
230 json_object_string_add(com
->json
, "string", "");
231 json_object_object_add(com
->json
, "list",
232 json_community_list
);
238 /* Memory allocation is time consuming work. So we calculate
239 required string length first. */
242 for (i
= 0; i
< com
->size
; i
++) {
243 memcpy(&comval
, com_nthval(com
, i
), sizeof(uint32_t));
244 comval
= ntohl(comval
);
247 case COMMUNITY_INTERNET
:
248 len
+= strlen(" internet");
250 case COMMUNITY_GSHUT
:
251 len
+= strlen(" graceful-shutdown");
253 case COMMUNITY_ACCEPT_OWN
:
254 len
+= strlen(" accept-own");
256 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4
:
257 len
+= strlen(" route-filter-translated-v4");
259 case COMMUNITY_ROUTE_FILTER_v4
:
260 len
+= strlen(" route-filter-v4");
262 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6
:
263 len
+= strlen(" route-filter-translated-v6");
265 case COMMUNITY_ROUTE_FILTER_v6
:
266 len
+= strlen(" route-filter-v6");
268 case COMMUNITY_LLGR_STALE
:
269 len
+= strlen(" llgr-stale");
271 case COMMUNITY_NO_LLGR
:
272 len
+= strlen(" no-llgr");
274 case COMMUNITY_ACCEPT_OWN_NEXTHOP
:
275 len
+= strlen(" accept-own-nexthop");
277 case COMMUNITY_BLACKHOLE
:
278 len
+= strlen(" blackhole");
280 case COMMUNITY_NO_EXPORT
:
281 len
+= strlen(" no-export");
283 case COMMUNITY_NO_ADVERTISE
:
284 len
+= strlen(" no-advertise");
286 case COMMUNITY_LOCAL_AS
:
287 len
+= strlen(" local-AS");
289 case COMMUNITY_NO_PEER
:
290 len
+= strlen(" no-peer");
293 len
+= strlen(" 65536:65535");
298 /* Allocate memory. */
299 str
= XCALLOC(MTYPE_COMMUNITY_STR
, len
);
302 /* Fill in string. */
303 for (i
= 0; i
< com
->size
; i
++) {
304 memcpy(&comval
, com_nthval(com
, i
), sizeof(uint32_t));
305 comval
= ntohl(comval
);
310 strlcat(str
, " ", len
);
313 case COMMUNITY_INTERNET
:
314 strlcat(str
, "internet", len
);
317 json_object_new_string("internet");
318 json_object_array_add(json_community_list
,
322 case COMMUNITY_GSHUT
:
323 strlcat(str
, "graceful-shutdown", len
);
325 json_string
= json_object_new_string(
327 json_object_array_add(json_community_list
,
331 case COMMUNITY_ACCEPT_OWN
:
332 strlcat(str
, "accept-own", len
);
334 json_string
= json_object_new_string(
336 json_object_array_add(json_community_list
,
340 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4
:
341 strlcat(str
, "route-filter-translated-v4", len
);
343 json_string
= json_object_new_string(
344 "routeFilterTranslatedV4");
345 json_object_array_add(json_community_list
,
349 case COMMUNITY_ROUTE_FILTER_v4
:
350 strlcat(str
, "route-filter-v4", len
);
352 json_string
= json_object_new_string(
354 json_object_array_add(json_community_list
,
358 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6
:
359 strlcat(str
, "route-filter-translated-v6", len
);
361 json_string
= json_object_new_string(
362 "routeFilterTranslatedV6");
363 json_object_array_add(json_community_list
,
367 case COMMUNITY_ROUTE_FILTER_v6
:
368 strlcat(str
, "route-filter-v6", len
);
370 json_string
= json_object_new_string(
372 json_object_array_add(json_community_list
,
376 case COMMUNITY_LLGR_STALE
:
377 strlcat(str
, "llgr-stale", len
);
379 json_string
= json_object_new_string(
381 json_object_array_add(json_community_list
,
385 case COMMUNITY_NO_LLGR
:
386 strlcat(str
, "no-llgr", len
);
388 json_string
= json_object_new_string(
390 json_object_array_add(json_community_list
,
394 case COMMUNITY_ACCEPT_OWN_NEXTHOP
:
395 strlcat(str
, "accept-own-nexthop", len
);
397 json_string
= json_object_new_string(
399 json_object_array_add(json_community_list
,
403 case COMMUNITY_BLACKHOLE
:
404 strlcat(str
, "blackhole", len
);
406 json_string
= json_object_new_string(
408 json_object_array_add(json_community_list
,
412 case COMMUNITY_NO_EXPORT
:
413 strlcat(str
, "no-export", len
);
416 json_object_new_string("noExport");
417 json_object_array_add(json_community_list
,
421 case COMMUNITY_NO_ADVERTISE
:
422 strlcat(str
, "no-advertise", len
);
425 json_object_new_string("noAdvertise");
426 json_object_array_add(json_community_list
,
430 case COMMUNITY_LOCAL_AS
:
431 strlcat(str
, "local-AS", len
);
433 json_string
= json_object_new_string("localAs");
434 json_object_array_add(json_community_list
,
438 case COMMUNITY_NO_PEER
:
439 strlcat(str
, "no-peer", len
);
441 json_string
= json_object_new_string("noPeer");
442 json_object_array_add(json_community_list
,
447 as
= (comval
>> 16) & 0xFFFF;
448 val
= comval
& 0xFFFF;
450 snprintf(buf
, sizeof(buf
), "%u:%d", as
, val
);
451 strlcat(str
, buf
, len
);
453 json_string
= json_object_new_string(buf
);
454 json_object_array_add(json_community_list
,
462 json_object_string_add(com
->json
, "string", str
);
463 json_object_object_add(com
->json
, "list", json_community_list
);
468 /* Intern communities attribute. */
469 struct community
*community_intern(struct community
*com
)
471 struct community
*find
;
473 /* Assert this community structure is not interned. */
474 assert(com
->refcnt
== 0);
476 /* Lookup community hash. */
477 find
= (struct community
*)hash_get(comhash
, com
, hash_alloc_intern
);
479 /* Arguemnt com is allocated temporary. So when it is not used in
480 hash, it should be freed. */
482 community_free(&com
);
484 /* Increment refrence counter. */
489 set_community_string(find
, false);
494 /* Free community attribute. */
495 void community_unintern(struct community
**com
)
497 struct community
*ret
;
502 /* Pull off from hash. */
503 if ((*com
)->refcnt
== 0) {
504 /* Community value com must exist in hash. */
505 ret
= (struct community
*)hash_release(comhash
, *com
);
512 /* Create new community attribute. */
513 struct community
*community_parse(uint32_t *pnt
, unsigned short length
)
515 struct community tmp
;
516 struct community
*new;
518 /* If length is malformed return NULL. */
522 /* Make temporary community for hash look up. */
523 tmp
.size
= length
/ 4;
526 new = community_uniq_sort(&tmp
);
528 return community_intern(new);
531 struct community
*community_dup(struct community
*com
)
533 struct community
*new;
535 new = XCALLOC(MTYPE_COMMUNITY
, sizeof(struct community
));
536 new->size
= com
->size
;
538 new->val
= XMALLOC(MTYPE_COMMUNITY_VAL
, com
->size
* 4);
539 memcpy(new->val
, com
->val
, com
->size
* 4);
545 /* Retrun string representation of communities attribute. */
546 char *community_str(struct community
*com
, bool make_json
)
551 if (make_json
&& !com
->json
&& com
->str
)
552 XFREE(MTYPE_COMMUNITY_STR
, com
->str
);
555 set_community_string(com
, make_json
);
559 /* Make hash value of community attribute. This function is used by
561 unsigned int community_hash_make(const struct community
*com
)
563 uint32_t *pnt
= (uint32_t *)com
->val
;
565 return jhash2(pnt
, com
->size
, 0x43ea96c1);
568 int community_match(const struct community
*com1
, const struct community
*com2
)
573 if (com1
== NULL
&& com2
== NULL
)
576 if (com1
== NULL
|| com2
== NULL
)
579 if (com1
->size
< com2
->size
)
582 /* Every community on com2 needs to be on com1 for this to match */
583 while (i
< com1
->size
&& j
< com2
->size
) {
584 if (memcmp(com1
->val
+ i
, com2
->val
+ j
, sizeof(uint32_t)) == 0)
595 /* If two aspath have same value then return 1 else return 0. This
596 function is used by hash package. */
597 bool community_cmp(const struct community
*com1
, const struct community
*com2
)
599 if (com1
== NULL
&& com2
== NULL
)
601 if (com1
== NULL
|| com2
== NULL
)
604 if (com1
->size
== com2
->size
)
605 if (memcmp(com1
->val
, com2
->val
, com1
->size
* 4) == 0)
610 /* Add com2 to the end of com1. */
611 struct community
*community_merge(struct community
*com1
,
612 struct community
*com2
)
615 com1
->val
= XREALLOC(MTYPE_COMMUNITY_VAL
, com1
->val
,
616 (com1
->size
+ com2
->size
) * 4);
618 com1
->val
= XMALLOC(MTYPE_COMMUNITY_VAL
,
619 (com1
->size
+ com2
->size
) * 4);
621 memcpy(com1
->val
+ com1
->size
, com2
->val
, com2
->size
* 4);
622 com1
->size
+= com2
->size
;
627 /* Community token enum. */
628 enum community_token
{
630 community_token_gshut
,
631 community_token_accept_own
,
632 community_token_route_filter_translated_v4
,
633 community_token_route_filter_v4
,
634 community_token_route_filter_translated_v6
,
635 community_token_route_filter_v6
,
636 community_token_llgr_stale
,
637 community_token_no_llgr
,
638 community_token_accept_own_nexthop
,
639 community_token_blackhole
,
640 community_token_no_export
,
641 community_token_no_advertise
,
642 community_token_local_as
,
643 community_token_no_peer
,
644 community_token_unknown
647 /* Get next community token from string. */
649 community_gettoken(const char *buf
, enum community_token
*token
, uint32_t *val
)
653 /* Skip white space. */
654 while (isspace((unsigned char)*p
))
657 /* Check the end of the line. */
661 /* Well known community string check. */
662 if (isalpha((unsigned char)*p
)) {
663 if (strncmp(p
, "internet", strlen("internet")) == 0) {
664 *val
= COMMUNITY_INTERNET
;
665 *token
= community_token_no_export
;
666 p
+= strlen("internet");
669 if (strncmp(p
, "graceful-shutdown", strlen("graceful-shutdown"))
671 *val
= COMMUNITY_GSHUT
;
672 *token
= community_token_gshut
;
673 p
+= strlen("graceful-shutdown");
676 if (strncmp(p
, "accept-own", strlen("accept-own"))
678 *val
= COMMUNITY_ACCEPT_OWN
;
679 *token
= community_token_accept_own
;
680 p
+= strlen("accept-own");
683 if (strncmp(p
, "route-filter-translated-v4",
684 strlen("route-filter-translated-v4"))
686 *val
= COMMUNITY_ROUTE_FILTER_TRANSLATED_v4
;
687 *token
= community_token_route_filter_translated_v4
;
688 p
+= strlen("route-filter-translated-v4");
691 if (strncmp(p
, "route-filter-v4", strlen("route-filter-v4"))
693 *val
= COMMUNITY_ROUTE_FILTER_v4
;
694 *token
= community_token_route_filter_v4
;
695 p
+= strlen("route-filter-v4");
698 if (strncmp(p
, "route-filter-translated-v6",
699 strlen("route-filter-translated-v6"))
701 *val
= COMMUNITY_ROUTE_FILTER_TRANSLATED_v6
;
702 *token
= community_token_route_filter_translated_v6
;
703 p
+= strlen("route-filter-translated-v6");
706 if (strncmp(p
, "route-filter-v6", strlen("route-filter-v6"))
708 *val
= COMMUNITY_ROUTE_FILTER_v6
;
709 *token
= community_token_route_filter_v6
;
710 p
+= strlen("route-filter-v6");
713 if (strncmp(p
, "llgr-stale", strlen("llgr-stale"))
715 *val
= COMMUNITY_LLGR_STALE
;
716 *token
= community_token_llgr_stale
;
717 p
+= strlen("llgr-stale");
720 if (strncmp(p
, "no-llgr", strlen("no-llgr"))
722 *val
= COMMUNITY_NO_LLGR
;
723 *token
= community_token_no_llgr
;
724 p
+= strlen("no-llgr");
727 if (strncmp(p
, "accept-own-nexthop",
728 strlen("accept-own-nexthop"))
730 *val
= COMMUNITY_ACCEPT_OWN_NEXTHOP
;
731 *token
= community_token_accept_own_nexthop
;
732 p
+= strlen("accept-own-nexthop");
735 if (strncmp(p
, "blackhole", strlen("blackhole"))
737 *val
= COMMUNITY_BLACKHOLE
;
738 *token
= community_token_blackhole
;
739 p
+= strlen("blackhole");
742 if (strncmp(p
, "no-export", strlen("no-export")) == 0) {
743 *val
= COMMUNITY_NO_EXPORT
;
744 *token
= community_token_no_export
;
745 p
+= strlen("no-export");
748 if (strncmp(p
, "no-advertise", strlen("no-advertise")) == 0) {
749 *val
= COMMUNITY_NO_ADVERTISE
;
750 *token
= community_token_no_advertise
;
751 p
+= strlen("no-advertise");
754 if (strncmp(p
, "local-AS", strlen("local-AS")) == 0) {
755 *val
= COMMUNITY_LOCAL_AS
;
756 *token
= community_token_local_as
;
757 p
+= strlen("local-AS");
760 if (strncmp(p
, "no-peer", strlen("no-peer")) == 0) {
761 *val
= COMMUNITY_NO_PEER
;
762 *token
= community_token_no_peer
;
763 p
+= strlen("no-peer");
767 /* Unknown string. */
768 *token
= community_token_unknown
;
772 /* Community value. */
773 if (isdigit((unsigned char)*p
)) {
776 uint32_t community_low
= 0;
777 uint32_t community_high
= 0;
779 while (isdigit((unsigned char)*p
) || *p
== ':') {
782 *token
= community_token_unknown
;
788 if (community_low
> UINT16_MAX
) {
790 community_token_unknown
;
794 community_high
= community_low
<< 16;
800 community_low
+= (*p
- '0');
805 *token
= community_token_unknown
;
809 if (community_low
> UINT16_MAX
) {
810 *token
= community_token_unknown
;
814 *val
= community_high
+ community_low
;
815 *token
= community_token_val
;
818 *token
= community_token_unknown
;
822 /* convert string to community structure */
823 struct community
*community_str2com(const char *str
)
825 struct community
*com
= NULL
;
826 struct community
*com_sort
= NULL
;
828 enum community_token token
= community_token_unknown
;
831 str
= community_gettoken(str
, &token
, &val
);
834 case community_token_val
:
835 case community_token_gshut
:
836 case community_token_accept_own
:
837 case community_token_route_filter_translated_v4
:
838 case community_token_route_filter_v4
:
839 case community_token_route_filter_translated_v6
:
840 case community_token_route_filter_v6
:
841 case community_token_llgr_stale
:
842 case community_token_no_llgr
:
843 case community_token_accept_own_nexthop
:
844 case community_token_blackhole
:
845 case community_token_no_export
:
846 case community_token_no_advertise
:
847 case community_token_local_as
:
848 case community_token_no_peer
:
850 com
= community_new();
853 community_add_val(com
, val
);
855 case community_token_unknown
:
857 community_free(&com
);
862 com_sort
= community_uniq_sort(com
);
863 community_free(&com
);
868 /* Return communities hash entry count. */
869 unsigned long community_count(void)
871 return comhash
->count
;
874 /* Return communities hash. */
875 struct hash
*community_hash(void)
880 /* Initialize comminity related hash. */
881 void community_init(void)
884 hash_create((unsigned int (*)(const void *))community_hash_make
,
885 (bool (*)(const void *, const void *))community_cmp
,
886 "BGP Community Hash");
889 void community_finish(void)
895 static struct community
*bgp_aggr_community_lookup(
896 struct bgp_aggregate
*aggregate
,
897 struct community
*community
)
899 return hash_lookup(aggregate
->community_hash
, community
);
902 static void *bgp_aggr_communty_hash_alloc(void *p
)
904 struct community
*ref
= (struct community
*)p
;
905 struct community
*community
= NULL
;
907 community
= community_dup(ref
);
911 static void bgp_aggr_community_prepare(struct hash_backet
*hb
, void *arg
)
913 struct community
*hb_community
= hb
->data
;
914 struct community
**aggr_community
= arg
;
917 *aggr_community
= community_merge(*aggr_community
,
920 *aggr_community
= community_dup(hb_community
);
923 void bgp_aggr_community_remove(void *arg
)
925 struct community
*community
= arg
;
927 community_free(&community
);
930 void bgp_compute_aggregate_community(struct bgp_aggregate
*aggregate
,
931 struct community
*community
)
933 bgp_compute_aggregate_community_hash(aggregate
, community
);
934 bgp_compute_aggregate_community_val(aggregate
);
938 void bgp_compute_aggregate_community_hash(struct bgp_aggregate
*aggregate
,
939 struct community
*community
)
941 struct community
*aggr_community
= NULL
;
943 if ((aggregate
== NULL
) || (community
== NULL
))
946 /* Create hash if not already created.
948 if (aggregate
->community_hash
== NULL
)
949 aggregate
->community_hash
= hash_create(
950 (unsigned int (*)(const void *))community_hash_make
,
951 (bool (*)(const void *, const void *))community_cmp
,
952 "BGP Aggregator community hash");
954 aggr_community
= bgp_aggr_community_lookup(aggregate
, community
);
955 if (aggr_community
== NULL
) {
956 /* Insert community into hash.
958 aggr_community
= hash_get(aggregate
->community_hash
, community
,
959 bgp_aggr_communty_hash_alloc
);
962 /* Increment reference counter.
964 aggr_community
->refcnt
++;
967 void bgp_compute_aggregate_community_val(struct bgp_aggregate
*aggregate
)
969 struct community
*commerge
= NULL
;
971 if (aggregate
== NULL
)
974 /* Re-compute aggregate's community.
976 if (aggregate
->community
)
977 community_free(&aggregate
->community
);
978 if (aggregate
->community_hash
&&
979 aggregate
->community_hash
->count
) {
980 hash_iterate(aggregate
->community_hash
,
981 bgp_aggr_community_prepare
,
982 &aggregate
->community
);
983 commerge
= aggregate
->community
;
984 aggregate
->community
= community_uniq_sort(commerge
);
986 community_free(&commerge
);
992 void bgp_remove_community_from_aggregate(struct bgp_aggregate
*aggregate
,
993 struct community
*community
)
995 struct community
*aggr_community
= NULL
;
996 struct community
*ret_comm
= NULL
;
999 || (!aggregate
->community_hash
)
1003 /* Look-up the community in the hash.
1005 aggr_community
= bgp_aggr_community_lookup(aggregate
, community
);
1006 if (aggr_community
) {
1007 aggr_community
->refcnt
--;
1009 if (aggr_community
->refcnt
== 0) {
1010 ret_comm
= hash_release(aggregate
->community_hash
,
1012 community_free(&ret_comm
);
1014 bgp_compute_aggregate_community_val(aggregate
);
1019 void bgp_remove_comm_from_aggregate_hash(struct bgp_aggregate
*aggregate
,
1020 struct community
*community
)
1023 struct community
*aggr_community
= NULL
;
1024 struct community
*ret_comm
= NULL
;
1027 || (!aggregate
->community_hash
)
1031 /* Look-up the community in the hash.
1033 aggr_community
= bgp_aggr_community_lookup(aggregate
, community
);
1034 if (aggr_community
) {
1035 aggr_community
->refcnt
--;
1037 if (aggr_community
->refcnt
== 0) {
1038 ret_comm
= hash_release(aggregate
->community_hash
,
1040 community_free(&ret_comm
);