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
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
*
37 return (struct community
*) XCALLOC (MTYPE_COMMUNITY
,
38 sizeof (struct community
));
41 /* Free communities value. */
43 community_free (struct community
*com
)
46 XFREE (MTYPE_COMMUNITY_VAL
, com
->val
);
48 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. */
61 community_add_val (struct community
*com
, u_int32_t val
)
65 com
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com
->val
, com_length (com
));
67 com
->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, com_length (com
));
70 memcpy (com_lastval (com
), &val
, sizeof (u_int32_t
));
73 /* Delete one community. */
75 community_del_val (struct community
*com
, u_int32_t
*val
)
85 if (memcmp (com
->val
+ i
, val
, sizeof (u_int32_t
)) == 0)
90 memmove (com
->val
+ i
, com
->val
+ (i
+ 1), c
* sizeof (*val
));
95 com
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com
->val
,
99 XFREE (MTYPE_COMMUNITY_VAL
, com
->val
);
108 /* Delete all communities listed in com2 from com1 */
110 community_delete (struct community
*com1
, struct community
*com2
)
114 while(i
< com2
->size
)
116 community_del_val (com1
, com2
->val
+ i
);
123 /* Callback function from qsort(). */
125 community_compare (const void *a1
, const void *a2
)
130 memcpy (&v1
, a1
, sizeof (u_int32_t
));
131 memcpy (&v2
, a2
, sizeof (u_int32_t
));
143 community_include (struct community
*com
, u_int32_t val
)
149 for (i
= 0; i
< com
->size
; i
++)
150 if (memcmp (&val
, com_nthval (com
, i
), sizeof (u_int32_t
)) == 0)
157 community_val_get (struct community
*com
, int i
)
162 p
= (u_char
*) com
->val
;
165 memcpy (&val
, p
, sizeof (u_int32_t
));
170 /* Sort and uniq given community. */
172 community_uniq_sort (struct community
*com
)
175 struct community
*new;
181 new = community_new ();;
184 for (i
= 0; i
< com
->size
; i
++)
186 val
= community_val_get (com
, i
);
188 if (! community_include (new, val
))
189 community_add_val (new, val
);
192 qsort (new->val
, new->size
, sizeof (u_int32_t
), community_compare
);
197 /* Convert communities attribute to string.
199 For Well-known communities value, below keyword is used.
202 0xFFFFFF01 "no-export"
203 0xFFFFFF02 "no-advertise"
204 0xFFFFFF03 "local-AS"
206 For other values, "AS:VAL" format is used. */
208 set_community_string (struct community
*com
)
218 json_object
*json_community_list
= NULL
;
219 json_object
*json_string
= NULL
;
224 com
->json
= json_object_new_object();
225 json_community_list
= json_object_new_array();
227 /* When communities attribute is empty. */
230 str
= XMALLOC (MTYPE_COMMUNITY_STR
, 1);
233 json_object_string_add(com
->json
, "string", "");
234 json_object_object_add(com
->json
, "list", json_community_list
);
239 /* Memory allocation is time consuming work. So we calculate
240 required string length first. */
243 for (i
= 0; i
< com
->size
; i
++)
245 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
246 comval
= ntohl (comval
);
250 case COMMUNITY_INTERNET
:
251 len
+= strlen (" internet");
253 case COMMUNITY_NO_EXPORT
:
254 len
+= strlen (" no-export");
256 case COMMUNITY_NO_ADVERTISE
:
257 len
+= strlen (" no-advertise");
259 case COMMUNITY_LOCAL_AS
:
260 len
+= strlen (" local-AS");
263 len
+= strlen (" 65536:65535");
268 /* Allocate memory. */
269 str
= pnt
= XMALLOC (MTYPE_COMMUNITY_STR
, len
);
272 /* Fill in string. */
273 for (i
= 0; i
< com
->size
; i
++)
275 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
276 comval
= ntohl (comval
);
285 case COMMUNITY_INTERNET
:
286 strcpy (pnt
, "internet");
287 pnt
+= strlen ("internet");
288 json_string
= json_object_new_string("internet");
289 json_object_array_add(json_community_list
, json_string
);
291 case COMMUNITY_NO_EXPORT
:
292 strcpy (pnt
, "no-export");
293 pnt
+= strlen ("no-export");
294 json_string
= json_object_new_string("noExport");
295 json_object_array_add(json_community_list
, json_string
);
297 case COMMUNITY_NO_ADVERTISE
:
298 strcpy (pnt
, "no-advertise");
299 pnt
+= strlen ("no-advertise");
300 json_string
= json_object_new_string("noAdvertise");
301 json_object_array_add(json_community_list
, json_string
);
303 case COMMUNITY_LOCAL_AS
:
304 strcpy (pnt
, "local-AS");
305 pnt
+= strlen ("local-AS");
306 json_string
= json_object_new_string("localAs");
307 json_object_array_add(json_community_list
, json_string
);
310 as
= (comval
>> 16) & 0xFFFF;
311 val
= comval
& 0xFFFF;
312 sprintf (pnt
, "%u:%d", as
, val
);
313 json_string
= json_object_new_string(pnt
);
314 json_object_array_add(json_community_list
, json_string
);
321 json_object_string_add(com
->json
, "string", str
);
322 json_object_object_add(com
->json
, "list", json_community_list
);
326 /* Intern communities attribute. */
328 community_intern (struct community
*com
)
330 struct community
*find
;
332 /* Assert this community structure is not interned. */
333 assert (com
->refcnt
== 0);
335 /* Lookup community hash. */
336 find
= (struct community
*) hash_get (comhash
, com
, hash_alloc_intern
);
338 /* Arguemnt com is allocated temporary. So when it is not used in
339 hash, it should be freed. */
341 community_free (com
);
343 /* Increment refrence counter. */
348 set_community_string (find
);
353 /* Free community attribute. */
355 community_unintern (struct community
**com
)
357 struct community
*ret
;
362 /* Pull off from hash. */
363 if ((*com
)->refcnt
== 0)
365 /* Community value com must exist in hash. */
366 ret
= (struct community
*) hash_release (comhash
, *com
);
367 assert (ret
!= NULL
);
369 community_free (*com
);
374 /* Create new community attribute. */
376 community_parse (u_int32_t
*pnt
, u_short length
)
378 struct community tmp
;
379 struct community
*new;
381 /* If length is malformed return NULL. */
385 /* Make temporary community for hash look up. */
386 tmp
.size
= length
/ 4;
389 new = community_uniq_sort (&tmp
);
391 return community_intern (new);
395 community_dup (struct community
*com
)
397 struct community
*new;
399 new = XCALLOC (MTYPE_COMMUNITY
, sizeof (struct community
));
400 new->size
= com
->size
;
403 new->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, com
->size
* 4);
404 memcpy (new->val
, com
->val
, com
->size
* 4);
411 /* Retrun string representation of communities attribute. */
413 community_str (struct community
*com
)
419 set_community_string (com
);
423 /* Make hash value of community attribute. This function is used by
426 community_hash_make (struct community
*com
)
428 unsigned char *pnt
= (unsigned char *)com
->val
;
429 int size
= com
->size
* 4;
430 unsigned int key
= 0;
433 for (c
= 0; c
< size
; c
+= 4)
445 community_match (const struct community
*com1
, const struct community
*com2
)
450 if (com1
== NULL
&& com2
== NULL
)
453 if (com1
== NULL
|| com2
== NULL
)
456 if (com1
->size
< com2
->size
)
459 /* Every community on com2 needs to be on com1 for this to match */
460 while (i
< com1
->size
&& j
< com2
->size
)
462 if (memcmp (com1
->val
+ i
, com2
->val
+ j
, sizeof (u_int32_t
)) == 0)
473 /* If two aspath have same value then return 1 else return 0. This
474 function is used by hash package. */
476 community_cmp (const struct community
*com1
, const struct community
*com2
)
478 if (com1
== NULL
&& com2
== NULL
)
480 if (com1
== NULL
|| com2
== NULL
)
483 if (com1
->size
== com2
->size
)
484 if (memcmp (com1
->val
, com2
->val
, com1
->size
* 4) == 0)
489 /* Add com2 to the end of com1. */
491 community_merge (struct community
*com1
, struct community
*com2
)
494 com1
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com1
->val
,
495 (com1
->size
+ com2
->size
) * 4);
497 com1
->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, (com1
->size
+ com2
->size
) * 4);
499 memcpy (com1
->val
+ com1
->size
, com2
->val
, com2
->size
* 4);
500 com1
->size
+= com2
->size
;
505 /* Community token enum. */
509 community_token_no_export
,
510 community_token_no_advertise
,
511 community_token_local_as
,
512 community_token_unknown
515 /* Get next community token from string. */
517 community_gettoken (const char *buf
, enum community_token
*token
,
522 /* Skip white space. */
523 while (isspace ((int) *p
))
526 /* Check the end of the line. */
530 /* Well known community string check. */
531 if (isalpha ((int) *p
))
533 if (strncmp (p
, "internet", strlen ("internet")) == 0)
535 *val
= COMMUNITY_INTERNET
;
536 *token
= community_token_no_export
;
537 p
+= strlen ("internet");
540 if (strncmp (p
, "no-export", strlen ("no-export")) == 0)
542 *val
= COMMUNITY_NO_EXPORT
;
543 *token
= community_token_no_export
;
544 p
+= strlen ("no-export");
547 if (strncmp (p
, "no-advertise", strlen ("no-advertise")) == 0)
549 *val
= COMMUNITY_NO_ADVERTISE
;
550 *token
= community_token_no_advertise
;
551 p
+= strlen ("no-advertise");
554 if (strncmp (p
, "local-AS", strlen ("local-AS")) == 0)
556 *val
= COMMUNITY_LOCAL_AS
;
557 *token
= community_token_local_as
;
558 p
+= strlen ("local-AS");
562 /* Unknown string. */
563 *token
= community_token_unknown
;
567 /* Community value. */
568 if (isdigit ((int) *p
))
572 u_int32_t community_low
= 0;
573 u_int32_t community_high
= 0;
575 while (isdigit ((int) *p
) || *p
== ':')
581 *token
= community_token_unknown
;
589 if (community_low
> UINT16_MAX
)
591 *token
= community_token_unknown
;
595 community_high
= community_low
<< 16;
603 community_low
+= (*p
- '0');
609 *token
= community_token_unknown
;
613 if (community_low
> UINT16_MAX
)
615 *token
= community_token_unknown
;
619 *val
= community_high
+ community_low
;
620 *token
= community_token_val
;
623 *token
= community_token_unknown
;
627 /* convert string to community structure */
629 community_str2com (const char *str
)
631 struct community
*com
= NULL
;
632 struct community
*com_sort
= NULL
;
634 enum community_token token
= community_token_unknown
;
638 str
= community_gettoken (str
, &token
, &val
);
642 case community_token_val
:
643 case community_token_no_export
:
644 case community_token_no_advertise
:
645 case community_token_local_as
:
648 com
= community_new();
651 community_add_val (com
, val
);
653 case community_token_unknown
:
656 community_free (com
);
664 com_sort
= community_uniq_sort (com
);
665 community_free (com
);
670 /* Return communities hash entry count. */
672 community_count (void)
674 return comhash
->count
;
677 /* Return communities hash. */
679 community_hash (void)
684 /* Initialize comminity related hash. */
686 community_init (void)
688 comhash
= hash_create ((unsigned int (*) (void *))community_hash_make
,
689 (int (*) (const void *, const void *))community_cmp
);
693 community_finish (void)