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
26 #include "bgpd/bgp_memory.h"
27 #include "bgpd/bgp_community.h"
29 /* Hash of community attribute. */
30 static struct hash
*comhash
;
32 /* Allocate a new communities value. */
33 static struct community
*
36 return (struct community
*) XCALLOC (MTYPE_COMMUNITY
,
37 sizeof (struct community
));
40 /* Free communities value. */
42 community_free (struct community
*com
)
45 XFREE (MTYPE_COMMUNITY_VAL
, com
->val
);
47 XFREE (MTYPE_COMMUNITY_STR
, com
->str
);
51 json_object_free(com
->json
);
55 XFREE (MTYPE_COMMUNITY
, com
);
58 /* Add one community value to the community. */
60 community_add_val (struct community
*com
, u_int32_t val
)
64 com
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com
->val
, com_length (com
));
66 com
->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, com_length (com
));
69 memcpy (com_lastval (com
), &val
, sizeof (u_int32_t
));
72 /* Delete one community. */
74 community_del_val (struct community
*com
, u_int32_t
*val
)
84 if (memcmp (com
->val
+ i
, val
, sizeof (u_int32_t
)) == 0)
89 memmove (com
->val
+ i
, com
->val
+ (i
+ 1), c
* sizeof (*val
));
94 com
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com
->val
,
98 XFREE (MTYPE_COMMUNITY_VAL
, com
->val
);
107 /* Delete all communities listed in com2 from com1 */
109 community_delete (struct community
*com1
, struct community
*com2
)
113 while(i
< com2
->size
)
115 community_del_val (com1
, com2
->val
+ i
);
122 /* Callback function from qsort(). */
124 community_compare (const void *a1
, const void *a2
)
129 memcpy (&v1
, a1
, sizeof (u_int32_t
));
130 memcpy (&v2
, a2
, sizeof (u_int32_t
));
142 community_include (struct community
*com
, u_int32_t val
)
148 for (i
= 0; i
< com
->size
; i
++)
149 if (memcmp (&val
, com_nthval (com
, i
), sizeof (u_int32_t
)) == 0)
156 community_val_get (struct community
*com
, int i
)
161 p
= (u_char
*) com
->val
;
164 memcpy (&val
, p
, sizeof (u_int32_t
));
169 /* Sort and uniq given community. */
171 community_uniq_sort (struct community
*com
)
174 struct community
*new;
180 new = community_new ();;
183 for (i
= 0; i
< com
->size
; i
++)
185 val
= community_val_get (com
, i
);
187 if (! community_include (new, val
))
188 community_add_val (new, val
);
191 qsort (new->val
, new->size
, sizeof (u_int32_t
), community_compare
);
196 /* Convert communities attribute to string.
198 For Well-known communities value, below keyword is used.
201 0xFFFFFF01 "no-export"
202 0xFFFFFF02 "no-advertise"
203 0xFFFFFF03 "local-AS"
205 For other values, "AS:VAL" format is used. */
207 set_community_string (struct community
*com
)
217 json_object
*json_community_list
= NULL
;
218 json_object
*json_string
= NULL
;
223 com
->json
= json_object_new_object();
224 json_community_list
= json_object_new_array();
226 /* When communities attribute is empty. */
229 str
= XMALLOC (MTYPE_COMMUNITY_STR
, 1);
232 json_object_string_add(com
->json
, "string", "");
233 json_object_object_add(com
->json
, "list", 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
++)
244 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
245 comval
= ntohl (comval
);
249 case COMMUNITY_INTERNET
:
250 len
+= strlen (" internet");
252 case COMMUNITY_NO_EXPORT
:
253 len
+= strlen (" no-export");
255 case COMMUNITY_NO_ADVERTISE
:
256 len
+= strlen (" no-advertise");
258 case COMMUNITY_LOCAL_AS
:
259 len
+= strlen (" local-AS");
262 len
+= strlen (" 65536:65535");
267 /* Allocate memory. */
268 str
= pnt
= XMALLOC (MTYPE_COMMUNITY_STR
, len
);
271 /* Fill in string. */
272 for (i
= 0; i
< com
->size
; i
++)
274 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
275 comval
= ntohl (comval
);
284 case COMMUNITY_INTERNET
:
285 strcpy (pnt
, "internet");
286 pnt
+= strlen ("internet");
287 json_string
= json_object_new_string("internet");
288 json_object_array_add(json_community_list
, json_string
);
290 case COMMUNITY_NO_EXPORT
:
291 strcpy (pnt
, "no-export");
292 pnt
+= strlen ("no-export");
293 json_string
= json_object_new_string("noExport");
294 json_object_array_add(json_community_list
, json_string
);
296 case COMMUNITY_NO_ADVERTISE
:
297 strcpy (pnt
, "no-advertise");
298 pnt
+= strlen ("no-advertise");
299 json_string
= json_object_new_string("noAdvertise");
300 json_object_array_add(json_community_list
, json_string
);
302 case COMMUNITY_LOCAL_AS
:
303 strcpy (pnt
, "local-AS");
304 pnt
+= strlen ("local-AS");
305 json_string
= json_object_new_string("localAs");
306 json_object_array_add(json_community_list
, json_string
);
309 as
= (comval
>> 16) & 0xFFFF;
310 val
= comval
& 0xFFFF;
311 sprintf (pnt
, "%u:%d", as
, val
);
312 json_string
= json_object_new_string(pnt
);
313 json_object_array_add(json_community_list
, json_string
);
320 json_object_string_add(com
->json
, "string", str
);
321 json_object_object_add(com
->json
, "list", json_community_list
);
325 /* Intern communities attribute. */
327 community_intern (struct community
*com
)
329 struct community
*find
;
331 /* Assert this community structure is not interned. */
332 assert (com
->refcnt
== 0);
334 /* Lookup community hash. */
335 find
= (struct community
*) hash_get (comhash
, com
, hash_alloc_intern
);
337 /* Arguemnt com is allocated temporary. So when it is not used in
338 hash, it should be freed. */
340 community_free (com
);
342 /* Increment refrence counter. */
347 set_community_string (find
);
352 /* Free community attribute. */
354 community_unintern (struct community
**com
)
356 struct community
*ret
;
361 /* Pull off from hash. */
362 if ((*com
)->refcnt
== 0)
364 /* Community value com must exist in hash. */
365 ret
= (struct community
*) hash_release (comhash
, *com
);
366 assert (ret
!= NULL
);
368 community_free (*com
);
373 /* Create new community attribute. */
375 community_parse (u_int32_t
*pnt
, u_short length
)
377 struct community tmp
;
378 struct community
*new;
380 /* If length is malformed return NULL. */
384 /* Make temporary community for hash look up. */
385 tmp
.size
= length
/ 4;
388 new = community_uniq_sort (&tmp
);
390 return community_intern (new);
394 community_dup (struct community
*com
)
396 struct community
*new;
398 new = XCALLOC (MTYPE_COMMUNITY
, sizeof (struct community
));
399 new->size
= com
->size
;
402 new->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, com
->size
* 4);
403 memcpy (new->val
, com
->val
, com
->size
* 4);
410 /* Retrun string representation of communities attribute. */
412 community_str (struct community
*com
)
418 set_community_string (com
);
422 /* Make hash value of community attribute. This function is used by
425 community_hash_make (struct community
*com
)
427 unsigned char *pnt
= (unsigned char *)com
->val
;
428 int size
= com
->size
* 4;
429 unsigned int key
= 0;
432 for (c
= 0; c
< size
; c
+= 4)
444 community_match (const struct community
*com1
, const struct community
*com2
)
449 if (com1
== NULL
&& com2
== NULL
)
452 if (com1
== NULL
|| com2
== NULL
)
455 if (com1
->size
< com2
->size
)
458 /* Every community on com2 needs to be on com1 for this to match */
459 while (i
< com1
->size
&& j
< com2
->size
)
461 if (memcmp (com1
->val
+ i
, com2
->val
+ j
, sizeof (u_int32_t
)) == 0)
472 /* If two aspath have same value then return 1 else return 0. This
473 function is used by hash package. */
475 community_cmp (const struct community
*com1
, const struct community
*com2
)
477 if (com1
== NULL
&& com2
== NULL
)
479 if (com1
== NULL
|| com2
== NULL
)
482 if (com1
->size
== com2
->size
)
483 if (memcmp (com1
->val
, com2
->val
, com1
->size
* 4) == 0)
488 /* Add com2 to the end of com1. */
490 community_merge (struct community
*com1
, struct community
*com2
)
493 com1
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com1
->val
,
494 (com1
->size
+ com2
->size
) * 4);
496 com1
->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, (com1
->size
+ com2
->size
) * 4);
498 memcpy (com1
->val
+ com1
->size
, com2
->val
, com2
->size
* 4);
499 com1
->size
+= com2
->size
;
504 /* Community token enum. */
508 community_token_no_export
,
509 community_token_no_advertise
,
510 community_token_local_as
,
511 community_token_unknown
514 /* Get next community token from string. */
516 community_gettoken (const char *buf
, enum community_token
*token
,
521 /* Skip white space. */
522 while (isspace ((int) *p
))
525 /* Check the end of the line. */
529 /* Well known community string check. */
530 if (isalpha ((int) *p
))
532 if (strncmp (p
, "internet", strlen ("internet")) == 0)
534 *val
= COMMUNITY_INTERNET
;
535 *token
= community_token_no_export
;
536 p
+= strlen ("internet");
539 if (strncmp (p
, "no-export", strlen ("no-export")) == 0)
541 *val
= COMMUNITY_NO_EXPORT
;
542 *token
= community_token_no_export
;
543 p
+= strlen ("no-export");
546 if (strncmp (p
, "no-advertise", strlen ("no-advertise")) == 0)
548 *val
= COMMUNITY_NO_ADVERTISE
;
549 *token
= community_token_no_advertise
;
550 p
+= strlen ("no-advertise");
553 if (strncmp (p
, "local-AS", strlen ("local-AS")) == 0)
555 *val
= COMMUNITY_LOCAL_AS
;
556 *token
= community_token_local_as
;
557 p
+= strlen ("local-AS");
561 /* Unknown string. */
562 *token
= community_token_unknown
;
566 /* Community value. */
567 if (isdigit ((int) *p
))
571 u_int32_t community_low
= 0;
572 u_int32_t community_high
= 0;
574 while (isdigit ((int) *p
) || *p
== ':')
580 *token
= community_token_unknown
;
588 if (community_low
> UINT16_MAX
)
590 *token
= community_token_unknown
;
594 community_high
= community_low
<< 16;
602 community_low
+= (*p
- '0');
608 *token
= community_token_unknown
;
612 if (community_low
> UINT16_MAX
)
614 *token
= community_token_unknown
;
618 *val
= community_high
+ community_low
;
619 *token
= community_token_val
;
622 *token
= community_token_unknown
;
626 /* convert string to community structure */
628 community_str2com (const char *str
)
630 struct community
*com
= NULL
;
631 struct community
*com_sort
= NULL
;
633 enum community_token token
= community_token_unknown
;
637 str
= community_gettoken (str
, &token
, &val
);
641 case community_token_val
:
642 case community_token_no_export
:
643 case community_token_no_advertise
:
644 case community_token_local_as
:
647 com
= community_new();
650 community_add_val (com
, val
);
652 case community_token_unknown
:
655 community_free (com
);
663 com_sort
= community_uniq_sort (com
);
664 community_free (com
);
669 /* Return communities hash entry count. */
671 community_count (void)
673 return comhash
->count
;
676 /* Return communities hash. */
678 community_hash (void)
683 /* Initialize comminity related hash. */
685 community_init (void)
687 comhash
= hash_create ((unsigned int (*) (void *))community_hash_make
,
688 (int (*) (const void *, const void *))community_cmp
);
692 community_finish (void)