Tomato 1.28
[tomato.git] / release / src / router / zebra / bgpd / bgp_community.c
blob9376d2c393ab5352ae6128b8f78369df99381a9e
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
9 * later version.
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
19 * 02111-1307, USA.
22 #include <zebra.h>
24 #include "hash.h"
25 #include "memory.h"
26 #include "vector.h"
27 #include "vty.h"
28 #include "str.h"
30 #include "bgpd/bgp_community.h"
32 /* Hash of community attribute. */
33 struct Hash *comhash;
35 struct community *
36 community_new ()
38 struct community *new;
40 new = XMALLOC (MTYPE_COMMUNITY, sizeof (struct community));
41 memset (new, 0, sizeof (struct community));
42 return new;
45 void
46 community_free (struct community *com)
48 if (com->val)
49 XFREE (MTYPE_COMMUNITY_VAL, com->val);
50 XFREE (MTYPE_COMMUNITY, com);
53 /* Add one community value to the community. */
54 void
55 community_add_val (struct community *com, u_int32_t val)
57 com->size++;
58 if (com->val)
59 com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com));
60 else
61 com->val = XMALLOC (MTYPE_COMMUNITY_VAL, com_length (com));
63 val = htonl (val);
64 memcpy (com_lastval (com), &val, sizeof (u_int32_t));
67 /* Delete one community. */
68 void
69 community_del_val (struct community *com, u_int32_t *val)
71 int i = 0;
72 int c = 0;
74 if (! com->val)
75 return;
77 while (i < com->size)
79 if (memcmp (com->val + i, val, sizeof (u_int32_t)) == 0)
81 c = com->size -i -1;
83 if (c > 0)
84 memcpy (com->val + i, com->val + (i + 1), c * sizeof (val));
86 com->size--;
88 if (com->size > 0)
89 com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val,
90 com_length (com));
91 else
93 XFREE (MTYPE_COMMUNITY_VAL, com->val);
94 com->val = NULL;
96 return;
98 i++;
102 /* Delete all communities listed in com2 from com1 */
103 struct community *
104 community_delete (struct community *com1, struct community *com2)
106 int i = 0;
108 while(i < com2->size)
110 community_del_val (com1, com2->val + i);
111 i++;
114 return com1;
117 /* Callback function from qsort(). */
119 community_compare (const void *a1, const void *a2)
121 u_int32_t v1;
122 u_int32_t v2;
124 memcpy (&v1, a1, sizeof (u_int32_t));
125 memcpy (&v2, a2, sizeof (u_int32_t));
126 v1 = ntohl (v1);
127 v2 = ntohl (v2);
129 if (v1 < v2)
130 return -1;
131 if (v1 > v2)
132 return 1;
133 return 0;
137 community_include (struct community *com, u_int32_t val)
139 int i;
141 val = htonl (val);
143 for (i = 0; i < com->size; i++)
145 if (memcmp (&val, com_nthval (com, i), sizeof (u_int32_t)) == 0)
146 return 1;
148 return 0;
151 u_int32_t
152 community_val_get (struct community *com, int i)
154 u_char *p;
155 u_int32_t val;
157 p = (u_char *) com->val;
158 p += (i * 4);
160 memcpy (&val, p, sizeof (u_int32_t));
162 return ntohl (val);
165 /* Sort and uniq given community. */
166 struct community *
167 community_uniq_sort (struct community *com)
169 int i;
170 struct community *new;
171 u_int32_t val;
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);
185 return new;
188 /* Create new community attribute. */
189 struct community *
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. */
197 if (length % 4)
198 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);
208 if (find)
210 find->refcnt++;
211 community_free (new);
212 return find;
215 new->refcnt = 1;
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);
222 return new;
225 struct community *
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;
233 if (new->size)
235 new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4);
236 memcpy (new->val, com->val, com->size * 4);
238 else
239 new->val = NULL;
240 return new;
243 struct community *
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);
253 if (find)
255 community_free (com);
256 find->refcnt++;
257 return find;
260 /* Push new community to hash bucket. */
261 com->refcnt = 1;
262 hash_push (comhash, com);
263 return com;
266 /* Free community attribute. */
267 void
268 community_unintern (struct community *com)
270 if (com->refcnt)
271 com->refcnt--;
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. */
286 const char *
287 community_print (struct community *com)
289 /* XXX non-re-entrant warning */
290 static char buf[BUFSIZ];
291 int i;
292 u_int32_t comval;
293 u_int16_t as;
294 u_int16_t val;
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);
302 switch (comval)
304 case COMMUNITY_NO_EXPORT:
305 strlcat (buf, " no-export", BUFSIZ);
306 break;
307 case COMMUNITY_NO_ADVERTISE:
308 strlcat (buf, " no-advertise", BUFSIZ);
309 break;
310 case COMMUNITY_LOCAL_AS:
311 strlcat (buf, " local-AS", BUFSIZ);
312 break;
313 default:
314 as = (comval >> 16) & 0xFFFF;
315 val = comval & 0xFFFF;
316 snprintf (buf + strlen (buf), BUFSIZ - strlen (buf),
317 " %d:%d", as, val);
318 break;
321 return buf;
324 /* Make hash value of community attribute. This function is used by
325 hash package.*/
326 unsigned int
327 community_hash_make (struct community *com)
329 int c;
330 unsigned int key;
331 unsigned char *pnt;
333 key = 0;
334 pnt = (unsigned char *)com->val;
336 for(c = 0; c < com->size * 4; c++)
337 key += pnt[c];
339 return key %= HASHTABSIZE;
343 community_match (struct community *com1, struct community *com2)
345 int i = 0;
346 int j = 0;
348 if (com1 == NULL && com2 == NULL)
349 return 1;
351 if (com1 == NULL || com2 == NULL)
352 return 0;
354 if (com1->size < com2->size)
355 return 0;
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)
361 j++;
362 i++;
365 if (j == com2->size)
366 return 1;
367 else
368 return 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)
377 return 1;
378 if (com1 == NULL || com2 == NULL)
379 return 0;
381 if (com1->size == com2->size)
382 if (memcmp (com1->val, com2->val, com1->size * 4) == 0)
383 return 1;
384 return 0;
387 /* Add com2 to the end of com1. */
388 struct community *
389 community_merge (struct community *com1, struct community *com2)
391 if (com1->val)
392 com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val,
393 (com1->size + com2->size) * 4);
394 else
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;
400 return com1;
403 /* Initialize comminity related hash. */
404 void
405 community_init ()
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. */
415 void
416 community_print_vty (struct vty *vty, struct community *com)
418 int i;
419 u_int32_t comval;
420 u_int16_t as;
421 u_int16_t val;
423 for (i = 0; i < com->size; i++)
425 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
426 comval = ntohl (comval);
427 switch (comval)
429 case COMMUNITY_NO_EXPORT:
430 vty_out (vty, " no-export");
431 break;
432 case COMMUNITY_NO_ADVERTISE:
433 vty_out (vty, " no-advertise");
434 break;
435 case COMMUNITY_LOCAL_AS:
436 vty_out (vty, " local-AS");
437 break;
438 default:
439 as = (comval >> 16) & 0xFFFF ;
440 val = comval & 0xFFFF;
441 vty_out (vty, " %d:%d", as, val);
442 break;
447 /* For `show ip bgp community' command. */
448 void
449 community_print_all_vty (struct vty *vty)
451 int i;
452 HashBacket *mp;
454 for (i = 0; i < HASHTABSIZE; i++)
455 if ((mp = (HashBacket *) hash_head (comhash, i)) != NULL)
456 while (mp)
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);
465 mp = mp->next;
469 /* Community token enum. */
470 enum community_token
472 community_token_val,
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. */
480 u_char *
481 community_gettoken (char *buf, enum community_token *token, u_int32_t *val)
483 char *p = buf;
485 /* Skip white space. */
486 while (isspace ((int) *p))
487 p++;
489 /* Check the end of the line. */
490 if (*p == '\0')
491 return NULL;
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");
501 return p;
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");
508 return p;
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");
515 return p;
518 /* Unknown string. */
519 *token = community_token_unknown;
520 return p;
523 /* Community value. */
524 if (isdigit ((int) *p))
526 int separator = 0;
527 u_int32_t community_low = 0;
528 u_int32_t community_high = 0;
530 while (isdigit ((int) *p) || *p == ':')
532 if (*p == ':')
534 if (separator)
536 *token = community_token_unknown;
537 return p;
539 else
541 separator = 1;
542 community_high = community_low << 16;
543 community_low = 0;
546 else
548 community_low *= 10;
549 community_low += (*p - '0');
551 p++;
553 *val = community_high + community_low;
554 *token = community_token_val;
555 return p;
557 *token = community_token_unknown;
558 return p;
561 /* convert string to community structure */
562 struct community *
563 community_str2com (char *str)
565 struct community *com = NULL;
566 struct community *com_sort = NULL;
567 u_int32_t val;
568 enum community_token token;
570 while ((str = community_gettoken (str, &token, &val)))
572 switch (token)
574 case community_token_val:
575 case community_token_no_export:
576 case community_token_no_advertise:
577 case community_token_local_as:
578 if (com == NULL)
579 com = community_new();
580 community_add_val (com, val);
581 break;
582 case community_token_unknown:
583 default:
584 if (com)
585 community_free (com);
586 return NULL;
587 break;
591 com_sort = community_uniq_sort (com);
592 community_free (com);
594 return com_sort;
597 unsigned long
598 community_count ()
600 return comhash->count;