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
17 along with GNU Zebra; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 #include "bgpd/bgp_memory.h"
28 #include "bgpd/bgp_community.h"
30 /* Hash of community attribute. */
31 static struct hash
*comhash
;
33 /* Allocate a new communities value. */
34 static struct community
*community_new(void)
36 return (struct community
*)XCALLOC(MTYPE_COMMUNITY
,
37 sizeof(struct community
));
40 /* Free communities value. */
41 void community_free(struct community
*com
)
44 XFREE(MTYPE_COMMUNITY_VAL
, com
->val
);
46 XFREE(MTYPE_COMMUNITY_STR
, com
->str
);
49 json_object_free(com
->json
);
53 XFREE(MTYPE_COMMUNITY
, com
);
56 /* Add one community value to the community. */
57 static void community_add_val(struct community
*com
, u_int32_t val
)
61 com
->val
= XREALLOC(MTYPE_COMMUNITY_VAL
, com
->val
,
64 com
->val
= XMALLOC(MTYPE_COMMUNITY_VAL
, com_length(com
));
67 memcpy(com_lastval(com
), &val
, sizeof(u_int32_t
));
70 /* Delete one community. */
71 void community_del_val(struct community
*com
, u_int32_t
*val
)
79 while (i
< com
->size
) {
80 if (memcmp(com
->val
+ i
, val
, sizeof(u_int32_t
)) == 0) {
81 c
= com
->size
- i
- 1;
84 memmove(com
->val
+ i
, com
->val
+ (i
+ 1),
90 com
->val
= XREALLOC(MTYPE_COMMUNITY_VAL
,
91 com
->val
, com_length(com
));
93 XFREE(MTYPE_COMMUNITY_VAL
, com
->val
);
102 /* Delete all communities listed in com2 from com1 */
103 struct community
*community_delete(struct community
*com1
,
104 struct community
*com2
)
108 while (i
< com2
->size
) {
109 community_del_val(com1
, com2
->val
+ i
);
116 /* Callback function from qsort(). */
117 static int community_compare(const void *a1
, const void *a2
)
122 memcpy(&v1
, a1
, sizeof(u_int32_t
));
123 memcpy(&v2
, a2
, sizeof(u_int32_t
));
134 int community_include(struct community
*com
, u_int32_t val
)
140 for (i
= 0; i
< com
->size
; i
++)
141 if (memcmp(&val
, com_nthval(com
, i
), sizeof(u_int32_t
)) == 0)
147 u_int32_t
community_val_get(struct community
*com
, int i
)
152 p
= (u_char
*)com
->val
;
155 memcpy(&val
, p
, sizeof(u_int32_t
));
160 /* Sort and uniq given community. */
161 struct community
*community_uniq_sort(struct community
*com
)
164 struct community
*new;
170 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(u_int32_t
), community_compare
);
186 /* Convert communities attribute to string.
188 For Well-known communities value, below keyword is used.
191 0xFFFFFF01 "no-export"
192 0xFFFFFF02 "no-advertise"
193 0xFFFFFF03 "local-AS"
195 For other values, "AS:VAL" format is used. */
196 static void set_community_string(struct community
*com
)
206 json_object
*json_community_list
= NULL
;
207 json_object
*json_string
= NULL
;
212 com
->json
= json_object_new_object();
213 json_community_list
= json_object_new_array();
215 /* When communities attribute is empty. */
216 if (com
->size
== 0) {
217 str
= XMALLOC(MTYPE_COMMUNITY_STR
, 1);
220 json_object_string_add(com
->json
, "string", "");
221 json_object_object_add(com
->json
, "list", json_community_list
);
226 /* Memory allocation is time consuming work. So we calculate
227 required string length first. */
230 for (i
= 0; i
< com
->size
; i
++) {
231 memcpy(&comval
, com_nthval(com
, i
), sizeof(u_int32_t
));
232 comval
= ntohl(comval
);
235 case COMMUNITY_INTERNET
:
236 len
+= strlen(" internet");
238 case COMMUNITY_NO_EXPORT
:
239 len
+= strlen(" no-export");
241 case COMMUNITY_NO_ADVERTISE
:
242 len
+= strlen(" no-advertise");
244 case COMMUNITY_LOCAL_AS
:
245 len
+= strlen(" local-AS");
248 len
+= strlen(" 65536:65535");
253 /* Allocate memory. */
254 str
= pnt
= XMALLOC(MTYPE_COMMUNITY_STR
, len
);
257 /* Fill in string. */
258 for (i
= 0; i
< com
->size
; i
++) {
259 memcpy(&comval
, com_nthval(com
, i
), sizeof(u_int32_t
));
260 comval
= ntohl(comval
);
268 case COMMUNITY_INTERNET
:
269 strcpy(pnt
, "internet");
270 pnt
+= strlen("internet");
271 json_string
= json_object_new_string("internet");
272 json_object_array_add(json_community_list
, json_string
);
274 case COMMUNITY_NO_EXPORT
:
275 strcpy(pnt
, "no-export");
276 pnt
+= strlen("no-export");
277 json_string
= json_object_new_string("noExport");
278 json_object_array_add(json_community_list
, json_string
);
280 case COMMUNITY_NO_ADVERTISE
:
281 strcpy(pnt
, "no-advertise");
282 pnt
+= strlen("no-advertise");
283 json_string
= json_object_new_string("noAdvertise");
284 json_object_array_add(json_community_list
, json_string
);
286 case COMMUNITY_LOCAL_AS
:
287 strcpy(pnt
, "local-AS");
288 pnt
+= strlen("local-AS");
289 json_string
= json_object_new_string("localAs");
290 json_object_array_add(json_community_list
, json_string
);
293 as
= (comval
>> 16) & 0xFFFF;
294 val
= comval
& 0xFFFF;
295 sprintf(pnt
, "%u:%d", as
, val
);
296 json_string
= json_object_new_string(pnt
);
297 json_object_array_add(json_community_list
, json_string
);
304 json_object_string_add(com
->json
, "string", str
);
305 json_object_object_add(com
->json
, "list", json_community_list
);
309 /* Intern communities attribute. */
310 struct community
*community_intern(struct community
*com
)
312 struct community
*find
;
314 /* Assert this community structure is not interned. */
315 assert(com
->refcnt
== 0);
317 /* Lookup community hash. */
318 find
= (struct community
*)hash_get(comhash
, com
, hash_alloc_intern
);
320 /* Arguemnt com is allocated temporary. So when it is not used in
321 hash, it should be freed. */
325 /* Increment refrence counter. */
330 set_community_string(find
);
335 /* Free community attribute. */
336 void community_unintern(struct community
**com
)
338 struct community
*ret
;
343 /* Pull off from hash. */
344 if ((*com
)->refcnt
== 0) {
345 /* Community value com must exist in hash. */
346 ret
= (struct community
*)hash_release(comhash
, *com
);
349 community_free(*com
);
354 /* Create new community attribute. */
355 struct community
*community_parse(u_int32_t
*pnt
, u_short length
)
357 struct community tmp
;
358 struct community
*new;
360 /* If length is malformed return NULL. */
364 /* Make temporary community for hash look up. */
365 tmp
.size
= length
/ 4;
368 new = community_uniq_sort(&tmp
);
370 return community_intern(new);
373 struct community
*community_dup(struct community
*com
)
375 struct community
*new;
377 new = XCALLOC(MTYPE_COMMUNITY
, sizeof(struct community
));
378 new->size
= com
->size
;
380 new->val
= XMALLOC(MTYPE_COMMUNITY_VAL
, com
->size
* 4);
381 memcpy(new->val
, com
->val
, com
->size
* 4);
387 /* Retrun string representation of communities attribute. */
388 char *community_str(struct community
*com
)
394 set_community_string(com
);
398 /* Make hash value of community attribute. This function is used by
400 unsigned int community_hash_make(struct community
*com
)
402 unsigned char *pnt
= (unsigned char *)com
->val
;
403 int size
= com
->size
* 4;
404 unsigned int key
= 0;
407 for (c
= 0; c
< size
; c
+= 4) {
417 int community_match(const struct community
*com1
, const struct community
*com2
)
422 if (com1
== NULL
&& com2
== NULL
)
425 if (com1
== NULL
|| com2
== NULL
)
428 if (com1
->size
< com2
->size
)
431 /* Every community on com2 needs to be on com1 for this to match */
432 while (i
< com1
->size
&& j
< com2
->size
) {
433 if (memcmp(com1
->val
+ i
, com2
->val
+ j
, sizeof(u_int32_t
))
445 /* If two aspath have same value then return 1 else return 0. This
446 function is used by hash package. */
447 int community_cmp(const struct community
*com1
, const struct community
*com2
)
449 if (com1
== NULL
&& com2
== NULL
)
451 if (com1
== NULL
|| com2
== NULL
)
454 if (com1
->size
== com2
->size
)
455 if (memcmp(com1
->val
, com2
->val
, com1
->size
* 4) == 0)
460 /* Add com2 to the end of com1. */
461 struct community
*community_merge(struct community
*com1
,
462 struct community
*com2
)
465 com1
->val
= XREALLOC(MTYPE_COMMUNITY_VAL
, com1
->val
,
466 (com1
->size
+ com2
->size
) * 4);
468 com1
->val
= XMALLOC(MTYPE_COMMUNITY_VAL
,
469 (com1
->size
+ com2
->size
) * 4);
471 memcpy(com1
->val
+ com1
->size
, com2
->val
, com2
->size
* 4);
472 com1
->size
+= com2
->size
;
477 /* Community token enum. */
478 enum community_token
{
480 community_token_no_export
,
481 community_token_no_advertise
,
482 community_token_local_as
,
483 community_token_unknown
486 /* Get next community token from string. */
488 community_gettoken(const char *buf
, enum community_token
*token
, u_int32_t
*val
)
492 /* Skip white space. */
493 while (isspace((int)*p
))
496 /* Check the end of the line. */
500 /* Well known community string check. */
501 if (isalpha((int)*p
)) {
502 if (strncmp(p
, "internet", strlen("internet")) == 0) {
503 *val
= COMMUNITY_INTERNET
;
504 *token
= community_token_no_export
;
505 p
+= strlen("internet");
508 if (strncmp(p
, "no-export", strlen("no-export")) == 0) {
509 *val
= COMMUNITY_NO_EXPORT
;
510 *token
= community_token_no_export
;
511 p
+= strlen("no-export");
514 if (strncmp(p
, "no-advertise", strlen("no-advertise")) == 0) {
515 *val
= COMMUNITY_NO_ADVERTISE
;
516 *token
= community_token_no_advertise
;
517 p
+= strlen("no-advertise");
520 if (strncmp(p
, "local-AS", strlen("local-AS")) == 0) {
521 *val
= COMMUNITY_LOCAL_AS
;
522 *token
= community_token_local_as
;
523 p
+= strlen("local-AS");
527 /* Unknown string. */
528 *token
= community_token_unknown
;
532 /* Community value. */
533 if (isdigit((int)*p
)) {
536 u_int32_t community_low
= 0;
537 u_int32_t community_high
= 0;
539 while (isdigit((int)*p
) || *p
== ':') {
542 *token
= community_token_unknown
;
548 if (community_low
> UINT16_MAX
) {
550 community_token_unknown
;
554 community_high
= community_low
<< 16;
560 community_low
+= (*p
- '0');
565 *token
= community_token_unknown
;
569 if (community_low
> UINT16_MAX
) {
570 *token
= community_token_unknown
;
574 *val
= community_high
+ community_low
;
575 *token
= community_token_val
;
578 *token
= community_token_unknown
;
582 /* convert string to community structure */
583 struct community
*community_str2com(const char *str
)
585 struct community
*com
= NULL
;
586 struct community
*com_sort
= NULL
;
588 enum community_token token
= community_token_unknown
;
591 str
= community_gettoken(str
, &token
, &val
);
594 case community_token_val
:
595 case community_token_no_export
:
596 case community_token_no_advertise
:
597 case community_token_local_as
:
599 com
= community_new();
602 community_add_val(com
, val
);
604 case community_token_unknown
:
615 com_sort
= community_uniq_sort(com
);
621 /* Return communities hash entry count. */
622 unsigned long community_count(void)
624 return comhash
->count
;
627 /* Return communities hash. */
628 struct hash
*community_hash(void)
633 /* Initialize comminity related hash. */
634 void community_init(void)
637 hash_create((unsigned int (*)(void *))community_hash_make
,
638 (int (*)(const void *, const void *))community_cmp
);
641 void community_finish(void)