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. */
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
)
209 /* When communities attribute is empty. */
212 str
= XMALLOC (MTYPE_COMMUNITY_STR
, 1);
217 /* Memory allocation is time consuming work. So we calculate
218 required string length first. */
221 for (i
= 0; i
< com
->size
; i
++)
223 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
224 comval
= ntohl (comval
);
228 case COMMUNITY_INTERNET
:
229 len
+= strlen (" internet");
231 case COMMUNITY_NO_EXPORT
:
232 len
+= strlen (" no-export");
234 case COMMUNITY_NO_ADVERTISE
:
235 len
+= strlen (" no-advertise");
237 case COMMUNITY_LOCAL_AS
:
238 len
+= strlen (" local-AS");
241 len
+= strlen (" 65536:65535");
246 /* Allocate memory. */
247 str
= pnt
= XMALLOC (MTYPE_COMMUNITY_STR
, len
);
250 /* Fill in string. */
251 for (i
= 0; i
< com
->size
; i
++)
253 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
254 comval
= ntohl (comval
);
263 case COMMUNITY_INTERNET
:
264 strcpy (pnt
, "internet");
265 pnt
+= strlen ("internet");
267 case COMMUNITY_NO_EXPORT
:
268 strcpy (pnt
, "no-export");
269 pnt
+= strlen ("no-export");
271 case COMMUNITY_NO_ADVERTISE
:
272 strcpy (pnt
, "no-advertise");
273 pnt
+= strlen ("no-advertise");
275 case COMMUNITY_LOCAL_AS
:
276 strcpy (pnt
, "local-AS");
277 pnt
+= strlen ("local-AS");
280 as
= (comval
>> 16) & 0xFFFF;
281 val
= comval
& 0xFFFF;
282 sprintf (pnt
, "%d:%d", as
, val
);
292 /* Intern communities attribute. */
294 community_intern (struct community
*com
)
296 struct community
*find
;
298 /* Assert this community structure is not interned. */
299 assert (com
->refcnt
== 0);
301 /* Lookup community hash. */
302 find
= (struct community
*) hash_get (comhash
, com
, hash_alloc_intern
);
304 /* Arguemnt com is allocated temporary. So when it is not used in
305 hash, it should be freed. */
307 community_free (com
);
309 /* Increment refrence counter. */
314 find
->str
= community_com2str (find
);
319 /* Free community attribute. */
321 community_unintern (struct community
*com
)
323 struct community
*ret
;
328 /* Pull off from hash. */
329 if (com
->refcnt
== 0)
331 /* Community value com must exist in hash. */
332 ret
= (struct community
*) hash_release (comhash
, com
);
333 assert (ret
!= NULL
);
335 community_free (com
);
339 /* Create new community attribute. */
341 community_parse (u_int32_t
*pnt
, u_short length
)
343 struct community tmp
;
344 struct community
*new;
346 /* If length is malformed return NULL. */
350 /* Make temporary community for hash look up. */
351 tmp
.size
= length
/ 4;
354 new = community_uniq_sort (&tmp
);
356 return community_intern (new);
360 community_dup (struct community
*com
)
362 struct community
*new;
364 new = XCALLOC (MTYPE_COMMUNITY
, sizeof (struct community
));
365 new->size
= com
->size
;
368 new->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, com
->size
* 4);
369 memcpy (new->val
, com
->val
, com
->size
* 4);
376 /* Retrun string representation of communities attribute. */
378 community_str (struct community
*com
)
381 com
->str
= community_com2str (com
);
385 /* Make hash value of community attribute. This function is used by
388 community_hash_make (struct community
*com
)
395 pnt
= (unsigned char *)com
->val
;
397 for(c
= 0; c
< com
->size
* 4; c
++)
404 community_match (const struct community
*com1
, const struct community
*com2
)
409 if (com1
== NULL
&& com2
== NULL
)
412 if (com1
== NULL
|| com2
== NULL
)
415 if (com1
->size
< com2
->size
)
418 /* Every community on com2 needs to be on com1 for this to match */
419 while (i
< com1
->size
&& j
< com2
->size
)
421 if (memcmp (com1
->val
+ i
, com2
->val
+ j
, sizeof (u_int32_t
)) == 0)
432 /* If two aspath have same value then return 1 else return 0. This
433 function is used by hash package. */
435 community_cmp (const struct community
*com1
, const struct community
*com2
)
437 if (com1
== NULL
&& com2
== NULL
)
439 if (com1
== NULL
|| com2
== NULL
)
442 if (com1
->size
== com2
->size
)
443 if (memcmp (com1
->val
, com2
->val
, com1
->size
* 4) == 0)
448 /* Add com2 to the end of com1. */
450 community_merge (struct community
*com1
, struct community
*com2
)
453 com1
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com1
->val
,
454 (com1
->size
+ com2
->size
) * 4);
456 com1
->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, (com1
->size
+ com2
->size
) * 4);
458 memcpy (com1
->val
+ com1
->size
, com2
->val
, com2
->size
* 4);
459 com1
->size
+= com2
->size
;
464 /* Community token enum. */
468 community_token_no_export
,
469 community_token_no_advertise
,
470 community_token_local_as
,
471 community_token_unknown
474 /* Get next community token from string. */
476 community_gettoken (const char *buf
, enum community_token
*token
,
481 /* Skip white space. */
482 while (isspace ((int) *p
))
485 /* Check the end of the line. */
489 /* Well known community string check. */
490 if (isalpha ((int) *p
))
492 if (strncmp (p
, "internet", strlen ("internet")) == 0)
494 *val
= COMMUNITY_INTERNET
;
495 *token
= community_token_no_export
;
496 p
+= strlen ("internet");
499 if (strncmp (p
, "no-export", strlen ("no-export")) == 0)
501 *val
= COMMUNITY_NO_EXPORT
;
502 *token
= community_token_no_export
;
503 p
+= strlen ("no-export");
506 if (strncmp (p
, "no-advertise", strlen ("no-advertise")) == 0)
508 *val
= COMMUNITY_NO_ADVERTISE
;
509 *token
= community_token_no_advertise
;
510 p
+= strlen ("no-advertise");
513 if (strncmp (p
, "local-AS", strlen ("local-AS")) == 0)
515 *val
= COMMUNITY_LOCAL_AS
;
516 *token
= community_token_local_as
;
517 p
+= strlen ("local-AS");
521 /* Unknown string. */
522 *token
= community_token_unknown
;
526 /* Community value. */
527 if (isdigit ((int) *p
))
531 u_int32_t community_low
= 0;
532 u_int32_t community_high
= 0;
534 while (isdigit ((int) *p
) || *p
== ':')
540 *token
= community_token_unknown
;
547 community_high
= community_low
<< 16;
555 community_low
+= (*p
- '0');
561 *token
= community_token_unknown
;
564 *val
= community_high
+ community_low
;
565 *token
= community_token_val
;
568 *token
= community_token_unknown
;
572 /* convert string to community structure */
574 community_str2com (const char *str
)
576 struct community
*com
= NULL
;
577 struct community
*com_sort
= NULL
;
579 enum community_token token
;
581 while ((str
= community_gettoken (str
, &token
, &val
)))
585 case community_token_val
:
586 case community_token_no_export
:
587 case community_token_no_advertise
:
588 case community_token_local_as
:
590 com
= community_new();
591 community_add_val (com
, val
);
593 case community_token_unknown
:
596 community_free (com
);
605 com_sort
= community_uniq_sort (com
);
606 community_free (com
);
611 /* Return communities hash entry count. */
615 return comhash
->count
;
618 /* Return communities hash. */
620 community_hash (void)
625 /* Initialize comminity related hash. */
627 community_init (void)
629 comhash
= hash_create (community_hash_make
, community_cmp
);