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_community.h"
28 /* Hash of community attribute. */
29 static struct hash
*comhash
;
31 /* Allocate a new communities value. */
32 static struct community
*
35 return (struct community
*) XCALLOC (MTYPE_COMMUNITY
,
36 sizeof (struct community
));
39 /* Free communities value. */
41 community_free (struct community
*com
)
44 XFREE (MTYPE_COMMUNITY_VAL
, com
->val
);
46 XFREE (MTYPE_COMMUNITY_STR
, com
->str
);
47 XFREE (MTYPE_COMMUNITY
, com
);
50 /* Add one community value to the community. */
52 community_add_val (struct community
*com
, u_int32_t val
)
56 com
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com
->val
, com_length (com
));
58 com
->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, com_length (com
));
61 memcpy (com_lastval (com
), &val
, sizeof (u_int32_t
));
64 /* Delete one community. */
66 community_del_val (struct community
*com
, u_int32_t
*val
)
76 if (memcmp (com
->val
+ i
, val
, sizeof (u_int32_t
)) == 0)
81 memcpy (com
->val
+ i
, com
->val
+ (i
+ 1), c
* sizeof (*val
));
86 com
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com
->val
,
90 XFREE (MTYPE_COMMUNITY_VAL
, com
->val
);
99 /* Delete all communities listed in com2 from com1 */
101 community_delete (struct community
*com1
, struct community
*com2
)
105 while(i
< com2
->size
)
107 community_del_val (com1
, com2
->val
+ i
);
114 /* Callback function from qsort(). */
116 community_compare (const void *a1
, const void *a2
)
121 memcpy (&v1
, a1
, sizeof (u_int32_t
));
122 memcpy (&v2
, a2
, sizeof (u_int32_t
));
134 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)
148 community_val_get (struct community
*com
, int i
)
153 p
= (u_char
*) com
->val
;
156 memcpy (&val
, p
, sizeof (u_int32_t
));
161 /* Sort and uniq given community. */
163 community_uniq_sort (struct community
*com
)
166 struct community
*new;
172 new = community_new ();;
174 for (i
= 0; i
< com
->size
; i
++)
176 val
= community_val_get (com
, i
);
178 if (! community_include (new, val
))
179 community_add_val (new, val
);
182 qsort (new->val
, new->size
, sizeof (u_int32_t
), community_compare
);
187 /* Convert communities attribute to string.
189 For Well-known communities value, below keyword is used.
192 0xFFFFFF01 "no-export"
193 0xFFFFFF02 "no-advertise"
194 0xFFFFFF03 "local-AS"
196 For other values, "AS:VAL" format is used. */
198 community_com2str (struct community
*com
)
212 /* When communities attribute is empty. */
215 str
= XMALLOC (MTYPE_COMMUNITY_STR
, 1);
220 /* Memory allocation is time consuming work. So we calculate
221 required string length first. */
224 for (i
= 0; i
< com
->size
; i
++)
226 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
227 comval
= ntohl (comval
);
231 case COMMUNITY_INTERNET
:
232 len
+= strlen (" internet");
234 case COMMUNITY_NO_EXPORT
:
235 len
+= strlen (" no-export");
237 case COMMUNITY_NO_ADVERTISE
:
238 len
+= strlen (" no-advertise");
240 case COMMUNITY_LOCAL_AS
:
241 len
+= strlen (" local-AS");
244 len
+= strlen (" 65536:65535");
249 /* Allocate memory. */
250 str
= pnt
= XMALLOC (MTYPE_COMMUNITY_STR
, len
);
253 /* Fill in string. */
254 for (i
= 0; i
< com
->size
; i
++)
256 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
257 comval
= ntohl (comval
);
266 case COMMUNITY_INTERNET
:
267 strcpy (pnt
, "internet");
268 pnt
+= strlen ("internet");
270 case COMMUNITY_NO_EXPORT
:
271 strcpy (pnt
, "no-export");
272 pnt
+= strlen ("no-export");
274 case COMMUNITY_NO_ADVERTISE
:
275 strcpy (pnt
, "no-advertise");
276 pnt
+= strlen ("no-advertise");
278 case COMMUNITY_LOCAL_AS
:
279 strcpy (pnt
, "local-AS");
280 pnt
+= strlen ("local-AS");
283 as
= (comval
>> 16) & 0xFFFF;
284 val
= comval
& 0xFFFF;
285 sprintf (pnt
, "%u:%d", as
, val
);
295 /* Intern communities attribute. */
297 community_intern (struct community
*com
)
299 struct community
*find
;
301 /* Assert this community structure is not interned. */
302 assert (com
->refcnt
== 0);
304 /* Lookup community hash. */
305 find
= (struct community
*) hash_get (comhash
, com
, hash_alloc_intern
);
307 /* Arguemnt com is allocated temporary. So when it is not used in
308 hash, it should be freed. */
310 community_free (com
);
312 /* Increment refrence counter. */
317 find
->str
= community_com2str (find
);
322 /* Free community attribute. */
324 community_unintern (struct community
*com
)
326 struct community
*ret
;
331 /* Pull off from hash. */
332 if (com
->refcnt
== 0)
334 /* Community value com must exist in hash. */
335 ret
= (struct community
*) hash_release (comhash
, com
);
336 assert (ret
!= NULL
);
338 community_free (com
);
342 /* Create new community attribute. */
344 community_parse (u_int32_t
*pnt
, u_short length
)
346 struct community tmp
;
347 struct community
*new;
349 /* If length is malformed return NULL. */
353 /* Make temporary community for hash look up. */
354 tmp
.size
= length
/ 4;
357 new = community_uniq_sort (&tmp
);
359 return community_intern (new);
363 community_dup (struct community
*com
)
365 struct community
*new;
367 new = XCALLOC (MTYPE_COMMUNITY
, sizeof (struct community
));
368 new->size
= com
->size
;
371 new->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, com
->size
* 4);
372 memcpy (new->val
, com
->val
, com
->size
* 4);
379 /* Retrun string representation of communities attribute. */
381 community_str (struct community
*com
)
387 com
->str
= community_com2str (com
);
391 /* Make hash value of community attribute. This function is used by
394 community_hash_make (struct community
*com
)
401 pnt
= (unsigned char *)com
->val
;
403 for(c
= 0; c
< com
->size
* 4; c
++)
410 community_match (const struct community
*com1
, const struct community
*com2
)
415 if (com1
== NULL
&& com2
== NULL
)
418 if (com1
== NULL
|| com2
== NULL
)
421 if (com1
->size
< com2
->size
)
424 /* Every community on com2 needs to be on com1 for this to match */
425 while (i
< com1
->size
&& j
< com2
->size
)
427 if (memcmp (com1
->val
+ i
, com2
->val
+ j
, sizeof (u_int32_t
)) == 0)
438 /* If two aspath have same value then return 1 else return 0. This
439 function is used by hash package. */
441 community_cmp (const struct community
*com1
, const struct community
*com2
)
443 if (com1
== NULL
&& com2
== NULL
)
445 if (com1
== NULL
|| com2
== NULL
)
448 if (com1
->size
== com2
->size
)
449 if (memcmp (com1
->val
, com2
->val
, com1
->size
* 4) == 0)
454 /* Add com2 to the end of com1. */
456 community_merge (struct community
*com1
, struct community
*com2
)
459 com1
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com1
->val
,
460 (com1
->size
+ com2
->size
) * 4);
462 com1
->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, (com1
->size
+ com2
->size
) * 4);
464 memcpy (com1
->val
+ com1
->size
, com2
->val
, com2
->size
* 4);
465 com1
->size
+= com2
->size
;
470 /* Community token enum. */
474 community_token_no_export
,
475 community_token_no_advertise
,
476 community_token_local_as
,
477 community_token_unknown
480 /* Get next community token from string. */
482 community_gettoken (const char *buf
, enum community_token
*token
,
487 /* Skip white space. */
488 while (isspace ((int) *p
))
491 /* Check the end of the line. */
495 /* Well known community string check. */
496 if (isalpha ((int) *p
))
498 if (strncmp (p
, "internet", strlen ("internet")) == 0)
500 *val
= COMMUNITY_INTERNET
;
501 *token
= community_token_no_export
;
502 p
+= strlen ("internet");
505 if (strncmp (p
, "no-export", strlen ("no-export")) == 0)
507 *val
= COMMUNITY_NO_EXPORT
;
508 *token
= community_token_no_export
;
509 p
+= strlen ("no-export");
512 if (strncmp (p
, "no-advertise", strlen ("no-advertise")) == 0)
514 *val
= COMMUNITY_NO_ADVERTISE
;
515 *token
= community_token_no_advertise
;
516 p
+= strlen ("no-advertise");
519 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
))
537 u_int32_t community_low
= 0;
538 u_int32_t community_high
= 0;
540 while (isdigit ((int) *p
) || *p
== ':')
546 *token
= community_token_unknown
;
553 community_high
= community_low
<< 16;
561 community_low
+= (*p
- '0');
567 *token
= community_token_unknown
;
570 *val
= community_high
+ community_low
;
571 *token
= community_token_val
;
574 *token
= community_token_unknown
;
578 /* convert string to community structure */
580 community_str2com (const char *str
)
582 struct community
*com
= NULL
;
583 struct community
*com_sort
= NULL
;
585 enum community_token token
= community_token_unknown
;
589 str
= community_gettoken (str
, &token
, &val
);
593 case community_token_val
:
594 case community_token_no_export
:
595 case community_token_no_advertise
:
596 case community_token_local_as
:
598 com
= community_new();
599 community_add_val (com
, val
);
601 case community_token_unknown
:
604 community_free (com
);
612 com_sort
= community_uniq_sort (com
);
613 community_free (com
);
618 /* Return communities hash entry count. */
620 community_count (void)
622 return comhash
->count
;
625 /* Return communities hash. */
627 community_hash (void)
632 /* Initialize comminity related hash. */
634 community_init (void)
636 comhash
= hash_create ((unsigned int (*) (void *))community_hash_make
,
637 (int (*) (const void *, const void *))community_cmp
);
641 community_finish (void)