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 memmove (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);
343 /* Create new community attribute. */
345 community_parse (u_int32_t *pnt, u_short length)
347 struct community tmp;
348 struct community *new;
350 /* If length is malformed return NULL. */
354 /* Make temporary community for hash look up. */
355 tmp.size = length / 4;
358 new = community_uniq_sort (&tmp);
360 return community_intern (new);
364 community_dup (struct community *com)
366 struct community *new;
368 new = XCALLOC (MTYPE_COMMUNITY, sizeof (struct community));
369 new->size = com->size;
372 new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4);
373 memcpy (new->val, com->val, com->size * 4);
380 /* Retrun string representation of communities attribute. */
382 community_str (struct community *com)
388 com->str = community_com2str (com);
392 /* Make hash value of community attribute. This function is used by
395 community_hash_make (struct community *com)
397 unsigned char *pnt = (unsigned char *)com->val;
398 int size = com->size * 4;
399 unsigned int key = 0;
402 for (c = 0; c < size; c += 4)
414 community_match (const struct community *com1, const struct community *com2)
419 if (com1 == NULL && com2 == NULL)
422 if (com1 == NULL || com2 == NULL)
425 if (com1->size < com2->size)
428 /* Every community on com2 needs to be on com1 for this to match */
429 while (i < com1->size && j < com2->size)
431 if (memcmp (com1->val + i, com2->val + j, sizeof (u_int32_t)) == 0)
442 /* If two aspath have same value then return 1 else return 0. This
443 function is used by hash package. */
445 community_cmp (const struct community *com1, const struct community *com2)
447 if (com1 == NULL && com2 == NULL)
449 if (com1 == NULL || com2 == NULL)
452 if (com1->size == com2->size)
453 if (memcmp (com1->val, com2->val, com1->size * 4) == 0)
458 /* Add com2 to the end of com1. */
460 community_merge (struct community *com1, struct community *com2)
463 com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val,
464 (com1->size + com2->size) * 4);
466 com1->val = XMALLOC (MTYPE_COMMUNITY_VAL, (com1->size + com2->size) * 4);
468 memcpy (com1->val + com1->size, com2->val, com2->size * 4);
469 com1->size += com2->size;
474 /* Community token enum. */
478 community_token_no_export,
479 community_token_no_advertise,
480 community_token_local_as,
481 community_token_unknown
484 /* Get next community token from string. */
486 community_gettoken (const char *buf, enum community_token *token,
491 /* Skip white space. */
492 while (isspace ((int) *p))
495 /* Check the end of the line. */
499 /* Well known community string check. */
500 if (isalpha ((int) *p))
502 if (strncmp (p, "internet", strlen ("internet")) == 0)
504 *val = COMMUNITY_INTERNET;
505 *token = community_token_no_export;
506 p += strlen ("internet");
509 if (strncmp (p, "no-export", strlen ("no-export")) == 0)
511 *val = COMMUNITY_NO_EXPORT;
512 *token = community_token_no_export;
513 p += strlen ("no-export");
516 if (strncmp (p, "no-advertise", strlen ("no-advertise")) == 0)
518 *val = COMMUNITY_NO_ADVERTISE;
519 *token = community_token_no_advertise;
520 p += strlen ("no-advertise");
523 if (strncmp (p, "local-AS", strlen ("local-AS")) == 0)
525 *val = COMMUNITY_LOCAL_AS;
526 *token = community_token_local_as;
527 p += strlen ("local-AS");
531 /* Unknown string. */
532 *token = community_token_unknown;
536 /* Community value. */
537 if (isdigit ((int) *p))
541 u_int32_t community_low = 0;
542 u_int32_t community_high = 0;
544 while (isdigit ((int) *p) || *p == ':')
550 *token = community_token_unknown;
557 community_high = community_low << 16;
565 community_low += (*p - '0');
571 *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 */
584 community_str2com (const char *str)
586 struct community *com = NULL;
587 struct community *com_sort = NULL;
589 enum community_token token = community_token_unknown;
593 str = community_gettoken (str, &token, &val);
597 case community_token_val:
598 case community_token_no_export:
599 case community_token_no_advertise:
600 case community_token_local_as:
602 com = community_new();
603 community_add_val (com, val);
605 case community_token_unknown:
608 community_free (com);
616 com_sort = community_uniq_sort (com);
617 community_free (com);
622 /* Return communities hash entry count. */
624 community_count (void)
626 return comhash->count;
629 /* Return communities hash. */
631 community_hash (void)
636 /* Initialize comminity related hash. */
638 community_init (void)
640 comhash = hash_create ((unsigned int (*) (void *))community_hash_make,
641 (int (*) (const void *, const void *))community_cmp);
645 community_finish (void)