1 /* Community attribute related functions.
2 * Copyright (C) 1998 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
30 #include "bgpd/bgp_community.h"
32 /* Hash of community attribute. */
38 struct community
*new;
40 new = XMALLOC (MTYPE_COMMUNITY
, sizeof (struct community
));
41 memset (new, 0, sizeof (struct community
));
46 community_free (struct community
*com
)
49 XFREE (MTYPE_COMMUNITY_VAL
, com
->val
);
50 XFREE (MTYPE_COMMUNITY
, com
);
53 /* Add one community value to the community. */
55 community_add_val (struct community
*com
, u_int32_t val
)
59 com
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com
->val
, com_length (com
));
61 com
->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, com_length (com
));
64 memcpy (com_lastval (com
), &val
, sizeof (u_int32_t
));
67 /* Delete one community. */
69 community_del_val (struct community
*com
, u_int32_t
*val
)
79 if (memcmp (com
->val
+ i
, val
, sizeof (u_int32_t
)) == 0)
84 memcpy (com
->val
+ i
, com
->val
+ (i
+ 1), c
* sizeof (val
));
89 com
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com
->val
,
93 XFREE (MTYPE_COMMUNITY_VAL
, com
->val
);
102 /* Delete all communities listed in com2 from com1 */
104 community_delete (struct community
*com1
, struct community
*com2
)
108 while(i
< com2
->size
)
110 community_del_val (com1
, com2
->val
+ i
);
117 /* Callback function from qsort(). */
119 community_compare (const void *a1
, const void *a2
)
124 memcpy (&v1
, a1
, sizeof (u_int32_t
));
125 memcpy (&v2
, a2
, sizeof (u_int32_t
));
137 community_include (struct community
*com
, u_int32_t val
)
143 for (i
= 0; i
< com
->size
; i
++)
145 if (memcmp (&val
, com_nthval (com
, i
), sizeof (u_int32_t
)) == 0)
152 community_val_get (struct community
*com
, int i
)
157 p
= (u_char
*) com
->val
;
160 memcpy (&val
, p
, sizeof (u_int32_t
));
165 /* Sort and uniq given community. */
167 community_uniq_sort (struct community
*com
)
170 struct community
*new;
173 new = community_new ();;
175 for (i
= 0; i
< com
->size
; i
++)
177 val
= community_val_get (com
, i
);
179 if (! community_include (new, val
))
180 community_add_val (new, val
);
183 qsort (new->val
, new->size
, sizeof (u_int32_t
), community_compare
);
188 /* Create new community attribute. */
190 community_parse (char *pnt
, u_short length
)
192 struct community tmp
;
193 struct community
*find
;
194 struct community
*new;
196 /* If length is malformed return NULL. */
200 /* Make temporary community for hash look up. */
201 tmp
.size
= length
/ 4;
202 tmp
.val
= (u_int32_t
*) pnt
;
204 new = community_uniq_sort (&tmp
);
206 /* Looking up hash of community attribute. */
207 find
= (struct community
*) hash_search (comhash
, new);
211 community_free (new);
216 /* new->size = length / 4; */
217 /* new->val = (u_int32_t *) XMALLOC (MTYPE_COMMUNITY_VAL, length); */
218 /* memcpy (new->val, pnt, length); */
220 hash_push (comhash
, new);
226 community_dup (struct community
*com
)
228 struct community
*new;
230 new = XMALLOC (MTYPE_COMMUNITY
, sizeof (struct community
));
231 memset (new, 0, sizeof (struct community
));
232 new->size
= com
->size
;
235 new->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, com
->size
* 4);
236 memcpy (new->val
, com
->val
, com
->size
* 4);
244 community_intern (struct community
*com
)
246 struct community
*find
;
248 /* Assert this community structure is not interned. */
249 assert (com
->refcnt
== 0);
251 /* Lookup community hash. */
252 find
= (struct community
*) hash_search (comhash
, com
);
255 community_free (com
);
260 /* Push new community to hash bucket. */
262 hash_push (comhash
, com
);
266 /* Free community attribute. */
268 community_unintern (struct community
*com
)
273 if (com
->refcnt
== 0)
275 struct community
*ret
;
277 /* Community value com must exist in hash. */
278 ret
= (struct community
*) hash_pull (comhash
, com
);
279 assert (ret
!= NULL
);
281 community_free (com
);
285 /* Pretty printing of community. For debug and logging purpose. */
287 community_print (struct community
*com
)
289 /* XXX non-re-entrant warning */
290 static char buf
[BUFSIZ
];
296 memset (buf
, 0, BUFSIZ
);
298 for (i
= 0; i
< com
->size
; i
++)
300 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
301 comval
= ntohl (comval
);
304 case COMMUNITY_NO_EXPORT
:
305 strlcat (buf
, " no-export", BUFSIZ
);
307 case COMMUNITY_NO_ADVERTISE
:
308 strlcat (buf
, " no-advertise", BUFSIZ
);
310 case COMMUNITY_LOCAL_AS
:
311 strlcat (buf
, " local-AS", BUFSIZ
);
314 as
= (comval
>> 16) & 0xFFFF;
315 val
= comval
& 0xFFFF;
316 snprintf (buf
+ strlen (buf
), BUFSIZ
- strlen (buf
),
324 /* Make hash value of community attribute. This function is used by
327 community_hash_make (struct community
*com
)
334 pnt
= (unsigned char *)com
->val
;
336 for(c
= 0; c
< com
->size
* 4; c
++)
339 return key
%= HASHTABSIZE
;
343 community_match (struct community
*com1
, struct community
*com2
)
348 if (com1
== NULL
&& com2
== NULL
)
351 if (com1
== NULL
|| com2
== NULL
)
354 if (com1
->size
< com2
->size
)
357 /* Every community on com2 needs to be on com1 for this to match */
358 while (i
< com1
->size
&& j
< com2
->size
)
360 if (memcmp (com1
->val
+ i
, com2
->val
+ j
, sizeof (u_int32_t
)) == 0)
371 /* If two aspath have same value then return 1 else return 0. This
372 function is used by hash package. */
374 community_cmp (struct community
*com1
, struct community
*com2
)
376 if (com1
== NULL
&& com2
== NULL
)
378 if (com1
== NULL
|| com2
== NULL
)
381 if (com1
->size
== com2
->size
)
382 if (memcmp (com1
->val
, com2
->val
, com1
->size
* 4) == 0)
387 /* Add com2 to the end of com1. */
389 community_merge (struct community
*com1
, struct community
*com2
)
392 com1
->val
= XREALLOC (MTYPE_COMMUNITY_VAL
, com1
->val
,
393 (com1
->size
+ com2
->size
) * 4);
395 com1
->val
= XMALLOC (MTYPE_COMMUNITY_VAL
, (com1
->size
+ com2
->size
) * 4);
397 memcpy (com1
->val
+ com1
->size
, com2
->val
, com2
->size
* 4);
398 com1
->size
+= com2
->size
;
403 /* Initialize comminity related hash. */
407 comhash
= hash_new (HASHTABSIZE
);
408 comhash
->hash_key
= community_hash_make
;
409 comhash
->hash_cmp
= community_cmp
;
412 /* Below is vty related function which needs some header include. */
414 /* Pretty printing of community attribute. */
416 community_print_vty (struct vty
*vty
, struct community
*com
)
423 for (i
= 0; i
< com
->size
; i
++)
425 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
426 comval
= ntohl (comval
);
429 case COMMUNITY_NO_EXPORT
:
430 vty_out (vty
, " no-export");
432 case COMMUNITY_NO_ADVERTISE
:
433 vty_out (vty
, " no-advertise");
435 case COMMUNITY_LOCAL_AS
:
436 vty_out (vty
, " local-AS");
439 as
= (comval
>> 16) & 0xFFFF ;
440 val
= comval
& 0xFFFF;
441 vty_out (vty
, " %d:%d", as
, val
);
447 /* For `show ip bgp community' command. */
449 community_print_all_vty (struct vty
*vty
)
454 for (i
= 0; i
< HASHTABSIZE
; i
++)
455 if ((mp
= (HashBacket
*) hash_head (comhash
, i
)) != NULL
)
458 struct community
*com
;
460 com
= (struct community
*) mp
->data
;
462 vty_out (vty
, "[%p:%d] (%ld)", mp
, i
, com
->refcnt
);
463 community_print_vty (vty
, com
);
464 vty_out (vty
, "%s", VTY_NEWLINE
);
469 /* Community token enum. */
473 community_token_no_export
,
474 community_token_no_advertise
,
475 community_token_local_as
,
476 community_token_unknown
479 /* Get next community token from string. */
481 community_gettoken (char *buf
, enum community_token
*token
, u_int32_t
*val
)
485 /* Skip white space. */
486 while (isspace ((int) *p
))
489 /* Check the end of the line. */
493 /* Well known community string check. */
494 if (isalpha ((int) *p
))
496 if (strncmp (p
, "no-export", strlen ("no-export")) == 0)
498 *val
= COMMUNITY_NO_EXPORT
;
499 *token
= community_token_no_export
;
500 p
+= strlen ("no-export");
503 if (strncmp (p
, "no-advertise", strlen ("no-advertise")) == 0)
505 *val
= COMMUNITY_NO_ADVERTISE
;
506 *token
= community_token_no_advertise
;
507 p
+= strlen ("no-advertise");
510 if (strncmp (p
, "local-AS", strlen ("local-AS")) == 0)
512 *val
= COMMUNITY_LOCAL_AS
;
513 *token
= community_token_local_as
;
514 p
+= strlen ("local-AS");
518 /* Unknown string. */
519 *token
= community_token_unknown
;
523 /* Community value. */
524 if (isdigit ((int) *p
))
527 u_int32_t community_low
= 0;
528 u_int32_t community_high
= 0;
530 while (isdigit ((int) *p
) || *p
== ':')
536 *token
= community_token_unknown
;
542 community_high
= community_low
<< 16;
549 community_low
+= (*p
- '0');
553 *val
= community_high
+ community_low
;
554 *token
= community_token_val
;
557 *token
= community_token_unknown
;
561 /* convert string to community structure */
563 community_str2com (char *str
)
565 struct community
*com
= NULL
;
566 struct community
*com_sort
= NULL
;
568 enum community_token token
;
570 while ((str
= community_gettoken (str
, &token
, &val
)))
574 case community_token_val
:
575 case community_token_no_export
:
576 case community_token_no_advertise
:
577 case community_token_local_as
:
579 com
= community_new();
580 community_add_val (com
, val
);
582 case community_token_unknown
:
585 community_free (com
);
591 com_sort
= community_uniq_sort (com
);
592 community_free (com
);
600 return comhash
->count
;