]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_community.c
Fixup of warnings in the code
[mirror_frr.git] / bgpd / bgp_community.c
CommitLineData
718e3744 1/* Community attribute related functions.
2 Copyright (C) 1998, 2001 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "hash.h"
24#include "memory.h"
25
26#include "bgpd/bgp_community.h"
27
28/* Hash of community attribute. */
730394d9 29static struct hash *comhash;
718e3744 30
31/* Allocate a new communities value. */
94f2b392 32static struct community *
33community_new (void)
718e3744 34{
35 return (struct community *) XCALLOC (MTYPE_COMMUNITY,
36 sizeof (struct community));
37}
38
39/* Free communities value. */
40void
41community_free (struct community *com)
42{
43 if (com->val)
44 XFREE (MTYPE_COMMUNITY_VAL, com->val);
45 if (com->str)
46 XFREE (MTYPE_COMMUNITY_STR, com->str);
f1aa5d8a
DS
47
48 if (com->json)
49 {
50 json_object_free(com->json);
51 com->json = NULL;
52 }
53
718e3744 54 XFREE (MTYPE_COMMUNITY, com);
55}
56
57/* Add one community value to the community. */
94f2b392 58static void
718e3744 59community_add_val (struct community *com, u_int32_t val)
60{
61 com->size++;
62 if (com->val)
63 com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com));
64 else
65 com->val = XMALLOC (MTYPE_COMMUNITY_VAL, com_length (com));
66
67 val = htonl (val);
68 memcpy (com_lastval (com), &val, sizeof (u_int32_t));
69}
70
71/* Delete one community. */
72void
73community_del_val (struct community *com, u_int32_t *val)
74{
75 int i = 0;
76 int c = 0;
77
78 if (! com->val)
79 return;
80
81 while (i < com->size)
82 {
83 if (memcmp (com->val + i, val, sizeof (u_int32_t)) == 0)
84 {
85 c = com->size -i -1;
86
87 if (c > 0)
4c005e3f 88 memmove (com->val + i, com->val + (i + 1), c * sizeof (*val));
718e3744 89
90 com->size--;
91
92 if (com->size > 0)
93 com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val,
94 com_length (com));
95 else
96 {
97 XFREE (MTYPE_COMMUNITY_VAL, com->val);
98 com->val = NULL;
99 }
100 return;
101 }
102 i++;
103 }
104}
105
106/* Delete all communities listed in com2 from com1 */
107struct community *
108community_delete (struct community *com1, struct community *com2)
109{
110 int i = 0;
111
112 while(i < com2->size)
113 {
114 community_del_val (com1, com2->val + i);
115 i++;
116 }
117
118 return com1;
119}
120
121/* Callback function from qsort(). */
94f2b392 122static int
718e3744 123community_compare (const void *a1, const void *a2)
124{
125 u_int32_t v1;
126 u_int32_t v2;
127
128 memcpy (&v1, a1, sizeof (u_int32_t));
129 memcpy (&v2, a2, sizeof (u_int32_t));
130 v1 = ntohl (v1);
131 v2 = ntohl (v2);
132
133 if (v1 < v2)
134 return -1;
135 if (v1 > v2)
136 return 1;
137 return 0;
138}
139
140int
141community_include (struct community *com, u_int32_t val)
142{
143 int i;
144
145 val = htonl (val);
146
147 for (i = 0; i < com->size; i++)
148 if (memcmp (&val, com_nthval (com, i), sizeof (u_int32_t)) == 0)
149 return 1;
150
151 return 0;
152}
153
5cbea288 154u_int32_t
718e3744 155community_val_get (struct community *com, int i)
156{
157 u_char *p;
158 u_int32_t val;
159
160 p = (u_char *) com->val;
161 p += (i * 4);
162
163 memcpy (&val, p, sizeof (u_int32_t));
164
165 return ntohl (val);
166}
167
168/* Sort and uniq given community. */
169struct community *
170community_uniq_sort (struct community *com)
171{
172 int i;
173 struct community *new;
174 u_int32_t val;
175
176 if (! com)
177 return NULL;
178
179 new = community_new ();;
f1aa5d8a 180 new->json = NULL;
718e3744 181
182 for (i = 0; i < com->size; i++)
183 {
184 val = community_val_get (com, i);
185
186 if (! community_include (new, val))
187 community_add_val (new, val);
188 }
189
190 qsort (new->val, new->size, sizeof (u_int32_t), community_compare);
191
192 return new;
193}
194
195/* Convert communities attribute to string.
196
197 For Well-known communities value, below keyword is used.
198
199 0x0 "internet"
200 0xFFFFFF01 "no-export"
201 0xFFFFFF02 "no-advertise"
202 0xFFFFFF03 "local-AS"
203
204 For other values, "AS:VAL" format is used. */
f1aa5d8a
DS
205static void
206set_community_string (struct community *com)
718e3744 207{
208 int i;
209 char *str;
210 char *pnt;
211 int len;
212 int first;
213 u_int32_t comval;
214 u_int16_t as;
215 u_int16_t val;
f1aa5d8a
DS
216 json_object *json_community_list = NULL;
217 json_object *json_string = NULL;
718e3744 218
b2ceea18 219 if (!com)
88177fe3 220 return;
b2ceea18 221
f1aa5d8a
DS
222 com->json = json_object_new_object();
223 json_community_list = json_object_new_array();
224
718e3744 225 /* When communities attribute is empty. */
226 if (com->size == 0)
227 {
228 str = XMALLOC (MTYPE_COMMUNITY_STR, 1);
229 str[0] = '\0';
f1aa5d8a
DS
230
231 json_object_string_add(com->json, "string", "");
232 json_object_object_add(com->json, "list", json_community_list);
233 com->str = str;
234 return;
718e3744 235 }
236
237 /* Memory allocation is time consuming work. So we calculate
238 required string length first. */
239 len = 0;
240
241 for (i = 0; i < com->size; i++)
242 {
243 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
244 comval = ntohl (comval);
245
246 switch (comval)
247 {
248 case COMMUNITY_INTERNET:
249 len += strlen (" internet");
250 break;
251 case COMMUNITY_NO_EXPORT:
252 len += strlen (" no-export");
253 break;
254 case COMMUNITY_NO_ADVERTISE:
255 len += strlen (" no-advertise");
256 break;
257 case COMMUNITY_LOCAL_AS:
258 len += strlen (" local-AS");
259 break;
260 default:
261 len += strlen (" 65536:65535");
262 break;
263 }
264 }
265
266 /* Allocate memory. */
267 str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len);
268 first = 1;
269
270 /* Fill in string. */
271 for (i = 0; i < com->size; i++)
272 {
273 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
274 comval = ntohl (comval);
275
276 if (first)
277 first = 0;
278 else
279 *pnt++ = ' ';
280
281 switch (comval)
282 {
283 case COMMUNITY_INTERNET:
284 strcpy (pnt, "internet");
285 pnt += strlen ("internet");
f1aa5d8a
DS
286 json_string = json_object_new_string("internet");
287 json_object_array_add(json_community_list, json_string);
718e3744 288 break;
289 case COMMUNITY_NO_EXPORT:
290 strcpy (pnt, "no-export");
291 pnt += strlen ("no-export");
62d6dca0 292 json_string = json_object_new_string("noExport");
f1aa5d8a 293 json_object_array_add(json_community_list, json_string);
718e3744 294 break;
295 case COMMUNITY_NO_ADVERTISE:
296 strcpy (pnt, "no-advertise");
297 pnt += strlen ("no-advertise");
62d6dca0 298 json_string = json_object_new_string("noAdvertise");
f1aa5d8a 299 json_object_array_add(json_community_list, json_string);
718e3744 300 break;
301 case COMMUNITY_LOCAL_AS:
302 strcpy (pnt, "local-AS");
303 pnt += strlen ("local-AS");
62d6dca0 304 json_string = json_object_new_string("localAs");
f1aa5d8a 305 json_object_array_add(json_community_list, json_string);
718e3744 306 break;
307 default:
308 as = (comval >> 16) & 0xFFFF;
309 val = comval & 0xFFFF;
aea339f7 310 sprintf (pnt, "%u:%d", as, val);
f1aa5d8a
DS
311 json_string = json_object_new_string(pnt);
312 json_object_array_add(json_community_list, json_string);
718e3744 313 pnt += strlen (pnt);
314 break;
315 }
316 }
317 *pnt = '\0';
318
f1aa5d8a
DS
319 json_object_string_add(com->json, "string", str);
320 json_object_object_add(com->json, "list", json_community_list);
321 com->str = str;
718e3744 322}
323
324/* Intern communities attribute. */
325struct community *
326community_intern (struct community *com)
327{
328 struct community *find;
329
330 /* Assert this community structure is not interned. */
331 assert (com->refcnt == 0);
332
333 /* Lookup community hash. */
334 find = (struct community *) hash_get (comhash, com, hash_alloc_intern);
335
336 /* Arguemnt com is allocated temporary. So when it is not used in
337 hash, it should be freed. */
338 if (find != com)
339 community_free (com);
340
341 /* Increment refrence counter. */
342 find->refcnt++;
343
344 /* Make string. */
345 if (! find->str)
f1aa5d8a 346 set_community_string (find);
718e3744 347
348 return find;
349}
350
351/* Free community attribute. */
352void
f6f434b2 353community_unintern (struct community **com)
718e3744 354{
355 struct community *ret;
356
f6f434b2
PJ
357 if ((*com)->refcnt)
358 (*com)->refcnt--;
718e3744 359
360 /* Pull off from hash. */
f6f434b2 361 if ((*com)->refcnt == 0)
718e3744 362 {
363 /* Community value com must exist in hash. */
f6f434b2 364 ret = (struct community *) hash_release (comhash, *com);
718e3744 365 assert (ret != NULL);
366
f6f434b2
PJ
367 community_free (*com);
368 *com = NULL;
718e3744 369 }
370}
371
372/* Create new community attribute. */
373struct community *
5228ad27 374community_parse (u_int32_t *pnt, u_short length)
718e3744 375{
376 struct community tmp;
377 struct community *new;
378
379 /* If length is malformed return NULL. */
380 if (length % 4)
381 return NULL;
382
383 /* Make temporary community for hash look up. */
384 tmp.size = length / 4;
5228ad27 385 tmp.val = pnt;
718e3744 386
387 new = community_uniq_sort (&tmp);
388
389 return community_intern (new);
390}
391
392struct community *
393community_dup (struct community *com)
394{
395 struct community *new;
396
397 new = XCALLOC (MTYPE_COMMUNITY, sizeof (struct community));
398 new->size = com->size;
399 if (new->size)
400 {
401 new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4);
402 memcpy (new->val, com->val, com->size * 4);
403 }
404 else
405 new->val = NULL;
406 return new;
407}
408
409/* Retrun string representation of communities attribute. */
410char *
411community_str (struct community *com)
412{
b2ceea18
PJ
413 if (!com)
414 return NULL;
f1aa5d8a 415
718e3744 416 if (! com->str)
f1aa5d8a 417 set_community_string (com);
718e3744 418 return com->str;
419}
420
421/* Make hash value of community attribute. This function is used by
422 hash package.*/
423unsigned int
424community_hash_make (struct community *com)
425{
c76275ee
JBD
426 unsigned char *pnt = (unsigned char *)com->val;
427 int size = com->size * 4;
428 unsigned int key = 0;
718e3744 429 int c;
718e3744 430
c76275ee
JBD
431 for (c = 0; c < size; c += 4)
432 {
433 key += pnt[c];
434 key += pnt[c + 1];
435 key += pnt[c + 2];
436 key += pnt[c + 3];
437 }
438
718e3744 439 return key;
440}
441
442int
fd79ac91 443community_match (const struct community *com1, const struct community *com2)
718e3744 444{
445 int i = 0;
446 int j = 0;
447
448 if (com1 == NULL && com2 == NULL)
449 return 1;
450
451 if (com1 == NULL || com2 == NULL)
452 return 0;
453
454 if (com1->size < com2->size)
455 return 0;
456
457 /* Every community on com2 needs to be on com1 for this to match */
458 while (i < com1->size && j < com2->size)
459 {
460 if (memcmp (com1->val + i, com2->val + j, sizeof (u_int32_t)) == 0)
461 j++;
462 i++;
463 }
464
465 if (j == com2->size)
466 return 1;
467 else
468 return 0;
469}
470
471/* If two aspath have same value then return 1 else return 0. This
472 function is used by hash package. */
473int
fd79ac91 474community_cmp (const struct community *com1, const struct community *com2)
718e3744 475{
476 if (com1 == NULL && com2 == NULL)
477 return 1;
478 if (com1 == NULL || com2 == NULL)
479 return 0;
480
481 if (com1->size == com2->size)
482 if (memcmp (com1->val, com2->val, com1->size * 4) == 0)
483 return 1;
484 return 0;
485}
486
487/* Add com2 to the end of com1. */
488struct community *
489community_merge (struct community *com1, struct community *com2)
490{
491 if (com1->val)
492 com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val,
493 (com1->size + com2->size) * 4);
494 else
495 com1->val = XMALLOC (MTYPE_COMMUNITY_VAL, (com1->size + com2->size) * 4);
496
497 memcpy (com1->val + com1->size, com2->val, com2->size * 4);
498 com1->size += com2->size;
499
500 return com1;
501}
502
503/* Community token enum. */
504enum community_token
505{
506 community_token_val,
507 community_token_no_export,
508 community_token_no_advertise,
509 community_token_local_as,
510 community_token_unknown
511};
512
513/* Get next community token from string. */
94f2b392 514static const char *
fd79ac91 515community_gettoken (const char *buf, enum community_token *token,
516 u_int32_t *val)
718e3744 517{
fd79ac91 518 const char *p = buf;
718e3744 519
520 /* Skip white space. */
521 while (isspace ((int) *p))
522 p++;
523
524 /* Check the end of the line. */
525 if (*p == '\0')
526 return NULL;
527
528 /* Well known community string check. */
529 if (isalpha ((int) *p))
530 {
531 if (strncmp (p, "internet", strlen ("internet")) == 0)
532 {
533 *val = COMMUNITY_INTERNET;
534 *token = community_token_no_export;
535 p += strlen ("internet");
536 return p;
537 }
538 if (strncmp (p, "no-export", strlen ("no-export")) == 0)
539 {
540 *val = COMMUNITY_NO_EXPORT;
541 *token = community_token_no_export;
542 p += strlen ("no-export");
543 return p;
544 }
545 if (strncmp (p, "no-advertise", strlen ("no-advertise")) == 0)
546 {
547 *val = COMMUNITY_NO_ADVERTISE;
548 *token = community_token_no_advertise;
549 p += strlen ("no-advertise");
550 return p;
551 }
552 if (strncmp (p, "local-AS", strlen ("local-AS")) == 0)
553 {
554 *val = COMMUNITY_LOCAL_AS;
555 *token = community_token_local_as;
556 p += strlen ("local-AS");
557 return p;
558 }
559
560 /* Unknown string. */
561 *token = community_token_unknown;
15aa6a1a 562 return NULL;
718e3744 563 }
564
565 /* Community value. */
566 if (isdigit ((int) *p))
567 {
568 int separator = 0;
569 int digit = 0;
570 u_int32_t community_low = 0;
571 u_int32_t community_high = 0;
572
573 while (isdigit ((int) *p) || *p == ':')
574 {
575 if (*p == ':')
576 {
577 if (separator)
578 {
579 *token = community_token_unknown;
15aa6a1a 580 return NULL;
718e3744 581 }
582 else
583 {
584 separator = 1;
585 digit = 0;
586 community_high = community_low << 16;
587 community_low = 0;
588 }
589 }
590 else
591 {
592 digit = 1;
593 community_low *= 10;
594 community_low += (*p - '0');
595 }
596 p++;
597 }
598 if (! digit)
599 {
600 *token = community_token_unknown;
15aa6a1a 601 return NULL;
718e3744 602 }
603 *val = community_high + community_low;
604 *token = community_token_val;
605 return p;
606 }
607 *token = community_token_unknown;
15aa6a1a 608 return NULL;
718e3744 609}
610
611/* convert string to community structure */
612struct community *
fd79ac91 613community_str2com (const char *str)
718e3744 614{
615 struct community *com = NULL;
616 struct community *com_sort = NULL;
851a1a5c
PJ
617 u_int32_t val = 0;
618 enum community_token token = community_token_unknown;
718e3744 619
15aa6a1a 620 do
718e3744 621 {
15aa6a1a
PJ
622 str = community_gettoken (str, &token, &val);
623
718e3744 624 switch (token)
625 {
626 case community_token_val:
627 case community_token_no_export:
628 case community_token_no_advertise:
629 case community_token_local_as:
630 if (com == NULL)
f1aa5d8a
DS
631 {
632 com = community_new();
633 com->json = NULL;
634 }
718e3744 635 community_add_val (com, val);
636 break;
637 case community_token_unknown:
638 default:
639 if (com)
640 community_free (com);
542bcb72 641 return NULL;
718e3744 642 }
15aa6a1a 643 } while (str);
718e3744 644
645 if (! com)
646 return NULL;
647
648 com_sort = community_uniq_sort (com);
649 community_free (com);
650
651 return com_sort;
652}
653
654/* Return communities hash entry count. */
655unsigned long
66e5cd87 656community_count (void)
718e3744 657{
658 return comhash->count;
659}
660
661/* Return communities hash. */
662struct hash *
94f2b392 663community_hash (void)
718e3744 664{
665 return comhash;
666}
667
668/* Initialize comminity related hash. */
669void
94f2b392 670community_init (void)
718e3744 671{
ffe11cfb
SH
672 comhash = hash_create ((unsigned int (*) (void *))community_hash_make,
673 (int (*) (const void *, const void *))community_cmp);
718e3744 674}
228da428
CC
675
676void
677community_finish (void)
678{
679 hash_free (comhash);
680 comhash = NULL;
681}