]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_community.c
zebra: Convert socket interface to use `union sockunion`
[mirror_frr.git] / bgpd / bgp_community.c
CommitLineData
718e3744 1/* Community attribute related functions.
896014f4
DL
2 * Copyright (C) 1998, 2001 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
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.
10 *
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.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
718e3744 20
21#include <zebra.h>
22
4dcadbef 23#include "command.h"
718e3744 24#include "hash.h"
25#include "memory.h"
3f65c5b1 26#include "jhash.h"
718e3744 27
4a1ab8e4 28#include "bgpd/bgp_memory.h"
718e3744 29#include "bgpd/bgp_community.h"
30
31/* Hash of community attribute. */
730394d9 32static struct hash *comhash;
718e3744 33
34/* Allocate a new communities value. */
d62a17ae 35static struct community *community_new(void)
718e3744 36{
d62a17ae 37 return (struct community *)XCALLOC(MTYPE_COMMUNITY,
38 sizeof(struct community));
718e3744 39}
40
41/* Free communities value. */
3c1f53de 42void community_free(struct community **com)
718e3744 43{
3c1f53de
SMS
44 if ((*com)->val)
45 XFREE(MTYPE_COMMUNITY_VAL, (*com)->val);
46 if ((*com)->str)
47 XFREE(MTYPE_COMMUNITY_STR, (*com)->str);
48
49 if ((*com)->json) {
50 json_object_free((*com)->json);
51 (*com)->json = NULL;
d62a17ae 52 }
53
3c1f53de 54 XFREE(MTYPE_COMMUNITY, (*com));
718e3744 55}
56
57/* Add one community value to the community. */
d7c0a89a 58static void community_add_val(struct community *com, uint32_t val)
718e3744 59{
d62a17ae 60 com->size++;
61 if (com->val)
62 com->val = XREALLOC(MTYPE_COMMUNITY_VAL, com->val,
63 com_length(com));
64 else
65 com->val = XMALLOC(MTYPE_COMMUNITY_VAL, com_length(com));
66
67 val = htonl(val);
d7c0a89a 68 memcpy(com_lastval(com), &val, sizeof(uint32_t));
718e3744 69}
70
71/* Delete one community. */
d7c0a89a 72void community_del_val(struct community *com, uint32_t *val)
718e3744 73{
d62a17ae 74 int i = 0;
75 int c = 0;
76
77 if (!com->val)
78 return;
79
80 while (i < com->size) {
d7c0a89a 81 if (memcmp(com->val + i, val, sizeof(uint32_t)) == 0) {
d62a17ae 82 c = com->size - i - 1;
83
84 if (c > 0)
85 memmove(com->val + i, com->val + (i + 1),
86 c * sizeof(*val));
87
88 com->size--;
89
90 if (com->size > 0)
91 com->val = XREALLOC(MTYPE_COMMUNITY_VAL,
92 com->val, com_length(com));
93 else {
94 XFREE(MTYPE_COMMUNITY_VAL, com->val);
95 com->val = NULL;
96 }
97 return;
98 }
99 i++;
718e3744 100 }
718e3744 101}
102
103/* Delete all communities listed in com2 from com1 */
d62a17ae 104struct community *community_delete(struct community *com1,
105 struct community *com2)
718e3744 106{
d62a17ae 107 int i = 0;
718e3744 108
d62a17ae 109 while (i < com2->size) {
110 community_del_val(com1, com2->val + i);
111 i++;
112 }
718e3744 113
d62a17ae 114 return com1;
718e3744 115}
116
117/* Callback function from qsort(). */
d62a17ae 118static int community_compare(const void *a1, const void *a2)
718e3744 119{
d7c0a89a
QY
120 uint32_t v1;
121 uint32_t v2;
d62a17ae 122
d7c0a89a
QY
123 memcpy(&v1, a1, sizeof(uint32_t));
124 memcpy(&v2, a2, sizeof(uint32_t));
d62a17ae 125 v1 = ntohl(v1);
126 v2 = ntohl(v2);
127
128 if (v1 < v2)
129 return -1;
130 if (v1 > v2)
131 return 1;
132 return 0;
718e3744 133}
134
d7c0a89a 135int community_include(struct community *com, uint32_t val)
718e3744 136{
d62a17ae 137 int i;
718e3744 138
d62a17ae 139 val = htonl(val);
718e3744 140
d62a17ae 141 for (i = 0; i < com->size; i++)
d7c0a89a 142 if (memcmp(&val, com_nthval(com, i), sizeof(uint32_t)) == 0)
d62a17ae 143 return 1;
718e3744 144
d62a17ae 145 return 0;
718e3744 146}
147
d7c0a89a 148uint32_t community_val_get(struct community *com, int i)
718e3744 149{
d7c0a89a
QY
150 uint8_t *p;
151 uint32_t val;
718e3744 152
d7c0a89a 153 p = (uint8_t *)com->val;
d62a17ae 154 p += (i * 4);
718e3744 155
d7c0a89a 156 memcpy(&val, p, sizeof(uint32_t));
718e3744 157
d62a17ae 158 return ntohl(val);
718e3744 159}
160
161/* Sort and uniq given community. */
d62a17ae 162struct community *community_uniq_sort(struct community *com)
718e3744 163{
d62a17ae 164 int i;
165 struct community *new;
d7c0a89a 166 uint32_t val;
d62a17ae 167
168 if (!com)
169 return NULL;
170
171 new = community_new();
d62a17ae 172 new->json = NULL;
173
174 for (i = 0; i < com->size; i++) {
175 val = community_val_get(com, i);
176
177 if (!community_include(new, val))
178 community_add_val(new, val);
179 }
180
d7c0a89a 181 qsort(new->val, new->size, sizeof(uint32_t), community_compare);
d62a17ae 182
183 return new;
718e3744 184}
185
186/* Convert communities attribute to string.
187
188 For Well-known communities value, below keyword is used.
189
d62a17ae 190 0x0 "internet"
aa861c10
C
191 0xFFFF0000 "graceful-shutdown"
192 0xFFFF0001 "accept-own"
193 0xFFFF0002 "route-filter-translated-v4"
194 0xFFFF0003 "route-filter-v4"
195 0xFFFF0004 "route-filter-translated-v6"
196 0xFFFF0005 "route-filter-v6"
197 0xFFFF0006 "llgr-stale"
198 0xFFFF0007 "no-llgr"
199 0xFFFF0008 "accept-own-nexthop"
200 0xFFFF029A "blackhole"
718e3744 201 0xFFFFFF01 "no-export"
202 0xFFFFFF02 "no-advertise"
203 0xFFFFFF03 "local-AS"
aa861c10 204 0xFFFFFF04 "no-peer"
718e3744 205
206 For other values, "AS:VAL" format is used. */
a69ea8ae 207static void set_community_string(struct community *com, bool make_json)
718e3744 208{
d62a17ae 209 int i;
210 char *str;
211 char *pnt;
212 int len;
213 int first;
d7c0a89a
QY
214 uint32_t comval;
215 uint16_t as;
216 uint16_t val;
d62a17ae 217 json_object *json_community_list = NULL;
218 json_object *json_string = NULL;
219
220 if (!com)
221 return;
222
a69ea8ae
DS
223 if (make_json) {
224 com->json = json_object_new_object();
225 json_community_list = json_object_new_array();
226 }
d62a17ae 227
228 /* When communities attribute is empty. */
229 if (com->size == 0) {
230 str = XMALLOC(MTYPE_COMMUNITY_STR, 1);
231 str[0] = '\0';
232
a69ea8ae
DS
233 if (make_json) {
234 json_object_string_add(com->json, "string", "");
996c9314
LB
235 json_object_object_add(com->json, "list",
236 json_community_list);
a69ea8ae 237 }
d62a17ae 238 com->str = str;
239 return;
718e3744 240 }
d62a17ae 241
242 /* Memory allocation is time consuming work. So we calculate
243 required string length first. */
244 len = 0;
245
246 for (i = 0; i < com->size; i++) {
d7c0a89a 247 memcpy(&comval, com_nthval(com, i), sizeof(uint32_t));
d62a17ae 248 comval = ntohl(comval);
249
250 switch (comval) {
251 case COMMUNITY_INTERNET:
252 len += strlen(" internet");
253 break;
aa861c10
C
254 case COMMUNITY_GSHUT:
255 len += strlen(" graceful-shutdown");
256 break;
257 case COMMUNITY_ACCEPT_OWN:
258 len += strlen(" accept-own");
259 break;
260 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4:
261 len += strlen(" route-filter-translated-v4");
262 break;
263 case COMMUNITY_ROUTE_FILTER_v4:
264 len += strlen(" route-filter-v4");
265 break;
266 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6:
267 len += strlen(" route-filter-translated-v6");
268 break;
269 case COMMUNITY_ROUTE_FILTER_v6:
270 len += strlen(" route-filter-v6");
271 break;
272 case COMMUNITY_LLGR_STALE:
273 len += strlen(" llgr-stale");
274 break;
275 case COMMUNITY_NO_LLGR:
276 len += strlen(" no-llgr");
277 break;
278 case COMMUNITY_ACCEPT_OWN_NEXTHOP:
279 len += strlen(" accept-own-nexthop");
280 break;
281 case COMMUNITY_BLACKHOLE:
282 len += strlen(" blackhole");
283 break;
d62a17ae 284 case COMMUNITY_NO_EXPORT:
285 len += strlen(" no-export");
286 break;
287 case COMMUNITY_NO_ADVERTISE:
288 len += strlen(" no-advertise");
289 break;
290 case COMMUNITY_LOCAL_AS:
291 len += strlen(" local-AS");
292 break;
aa861c10
C
293 case COMMUNITY_NO_PEER:
294 len += strlen(" no-peer");
7f323236 295 break;
d62a17ae 296 default:
297 len += strlen(" 65536:65535");
298 break;
299 }
300 }
301
302 /* Allocate memory. */
303 str = pnt = XMALLOC(MTYPE_COMMUNITY_STR, len);
304 first = 1;
305
306 /* Fill in string. */
307 for (i = 0; i < com->size; i++) {
d7c0a89a 308 memcpy(&comval, com_nthval(com, i), sizeof(uint32_t));
d62a17ae 309 comval = ntohl(comval);
310
311 if (first)
312 first = 0;
313 else
314 *pnt++ = ' ';
315
316 switch (comval) {
317 case COMMUNITY_INTERNET:
318 strcpy(pnt, "internet");
319 pnt += strlen("internet");
a69ea8ae 320 if (make_json) {
996c9314
LB
321 json_string =
322 json_object_new_string("internet");
323 json_object_array_add(json_community_list,
324 json_string);
a69ea8ae 325 }
d62a17ae 326 break;
aa861c10
C
327 case COMMUNITY_GSHUT:
328 strcpy(pnt, "graceful-shutdown");
329 pnt += strlen("graceful-shutdown");
330 if (make_json) {
331 json_string = json_object_new_string(
332 "gracefulShutdown");
333 json_object_array_add(json_community_list,
334 json_string);
335 }
336 break;
337 case COMMUNITY_ACCEPT_OWN:
338 strcpy(pnt, "accept-own");
339 pnt += strlen("accept-own");
340 if (make_json) {
341 json_string = json_object_new_string(
342 "acceptown");
343 json_object_array_add(json_community_list,
344 json_string);
345 }
346 break;
347 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4:
348 strcpy(pnt, "route-filter-translated-v4");
349 pnt += strlen("route-filter-translated-v4");
350 if (make_json) {
351 json_string = json_object_new_string(
352 "routeFilterTranslatedV4");
353 json_object_array_add(json_community_list,
354 json_string);
355 }
356 break;
357 case COMMUNITY_ROUTE_FILTER_v4:
358 strcpy(pnt, "route-filter-v4");
359 pnt += strlen("route-filter-v4");
360 if (make_json) {
361 json_string = json_object_new_string(
362 "routeFilterV4");
363 json_object_array_add(json_community_list,
364 json_string);
365 }
366 break;
367 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6:
368 strcpy(pnt, "route-filter-translated-v6");
369 pnt += strlen("route-filter-translated-v6");
370 if (make_json) {
371 json_string = json_object_new_string(
372 "routeFilterTranslatedV6");
373 json_object_array_add(json_community_list,
374 json_string);
375 }
376 break;
377 case COMMUNITY_ROUTE_FILTER_v6:
378 strcpy(pnt, "route-filter-v6");
379 pnt += strlen("route-filter-v6");
380 if (make_json) {
381 json_string = json_object_new_string(
382 "routeFilterV6");
383 json_object_array_add(json_community_list,
384 json_string);
385 }
386 break;
387 case COMMUNITY_LLGR_STALE:
388 strcpy(pnt, "llgr-stale");
389 pnt += strlen("llgr-stale");
390 if (make_json) {
391 json_string = json_object_new_string(
392 "llgrStale");
393 json_object_array_add(json_community_list,
394 json_string);
395 }
396 break;
397 case COMMUNITY_NO_LLGR:
398 strcpy(pnt, "no-llgr");
399 pnt += strlen("no-llgr");
400 if (make_json) {
401 json_string = json_object_new_string(
402 "noLlgr");
403 json_object_array_add(json_community_list,
404 json_string);
405 }
406 break;
407 case COMMUNITY_ACCEPT_OWN_NEXTHOP:
408 strcpy(pnt, "accept-own-nexthop");
409 pnt += strlen("accept-own-nexthop");
410 if (make_json) {
411 json_string = json_object_new_string(
412 "acceptownnexthop");
413 json_object_array_add(json_community_list,
414 json_string);
415 }
416 break;
417 case COMMUNITY_BLACKHOLE:
418 strcpy(pnt, "blackhole");
419 pnt += strlen("blackhole");
420 if (make_json) {
421 json_string = json_object_new_string(
422 "blackhole");
423 json_object_array_add(json_community_list,
424 json_string);
425 }
426 break;
d62a17ae 427 case COMMUNITY_NO_EXPORT:
428 strcpy(pnt, "no-export");
429 pnt += strlen("no-export");
a69ea8ae 430 if (make_json) {
996c9314
LB
431 json_string =
432 json_object_new_string("noExport");
433 json_object_array_add(json_community_list,
434 json_string);
a69ea8ae 435 }
d62a17ae 436 break;
437 case COMMUNITY_NO_ADVERTISE:
438 strcpy(pnt, "no-advertise");
439 pnt += strlen("no-advertise");
a69ea8ae 440 if (make_json) {
996c9314
LB
441 json_string =
442 json_object_new_string("noAdvertise");
443 json_object_array_add(json_community_list,
444 json_string);
a69ea8ae 445 }
d62a17ae 446 break;
447 case COMMUNITY_LOCAL_AS:
448 strcpy(pnt, "local-AS");
449 pnt += strlen("local-AS");
a69ea8ae
DS
450 if (make_json) {
451 json_string = json_object_new_string("localAs");
996c9314
LB
452 json_object_array_add(json_community_list,
453 json_string);
a69ea8ae 454 }
d62a17ae 455 break;
aa861c10
C
456 case COMMUNITY_NO_PEER:
457 strcpy(pnt, "no-peer");
458 pnt += strlen("no-peer");
a69ea8ae 459 if (make_json) {
aa861c10 460 json_string = json_object_new_string("noPeer");
996c9314
LB
461 json_object_array_add(json_community_list,
462 json_string);
a69ea8ae 463 }
7f323236 464 break;
d62a17ae 465 default:
466 as = (comval >> 16) & 0xFFFF;
467 val = comval & 0xFFFF;
468 sprintf(pnt, "%u:%d", as, val);
a69ea8ae
DS
469 if (make_json) {
470 json_string = json_object_new_string(pnt);
996c9314
LB
471 json_object_array_add(json_community_list,
472 json_string);
a69ea8ae 473 }
d62a17ae 474 pnt += strlen(pnt);
475 break;
476 }
718e3744 477 }
d62a17ae 478 *pnt = '\0';
718e3744 479
a69ea8ae
DS
480 if (make_json) {
481 json_object_string_add(com->json, "string", str);
482 json_object_object_add(com->json, "list", json_community_list);
483 }
d62a17ae 484 com->str = str;
718e3744 485}
486
487/* Intern communities attribute. */
d62a17ae 488struct community *community_intern(struct community *com)
718e3744 489{
d62a17ae 490 struct community *find;
718e3744 491
d62a17ae 492 /* Assert this community structure is not interned. */
493 assert(com->refcnt == 0);
718e3744 494
d62a17ae 495 /* Lookup community hash. */
496 find = (struct community *)hash_get(comhash, com, hash_alloc_intern);
718e3744 497
d62a17ae 498 /* Arguemnt com is allocated temporary. So when it is not used in
499 hash, it should be freed. */
500 if (find != com)
3c1f53de 501 community_free(&com);
718e3744 502
d62a17ae 503 /* Increment refrence counter. */
504 find->refcnt++;
718e3744 505
d62a17ae 506 /* Make string. */
507 if (!find->str)
a69ea8ae 508 set_community_string(find, false);
718e3744 509
d62a17ae 510 return find;
718e3744 511}
512
513/* Free community attribute. */
d62a17ae 514void community_unintern(struct community **com)
718e3744 515{
d62a17ae 516 struct community *ret;
718e3744 517
d62a17ae 518 if ((*com)->refcnt)
519 (*com)->refcnt--;
718e3744 520
d62a17ae 521 /* Pull off from hash. */
522 if ((*com)->refcnt == 0) {
523 /* Community value com must exist in hash. */
524 ret = (struct community *)hash_release(comhash, *com);
525 assert(ret != NULL);
718e3744 526
3c1f53de 527 community_free(com);
d62a17ae 528 }
718e3744 529}
530
531/* Create new community attribute. */
d7c0a89a 532struct community *community_parse(uint32_t *pnt, unsigned short length)
718e3744 533{
d62a17ae 534 struct community tmp;
535 struct community *new;
718e3744 536
d62a17ae 537 /* If length is malformed return NULL. */
538 if (length % 4)
539 return NULL;
718e3744 540
d62a17ae 541 /* Make temporary community for hash look up. */
542 tmp.size = length / 4;
543 tmp.val = pnt;
718e3744 544
d62a17ae 545 new = community_uniq_sort(&tmp);
718e3744 546
d62a17ae 547 return community_intern(new);
718e3744 548}
549
d62a17ae 550struct community *community_dup(struct community *com)
718e3744 551{
d62a17ae 552 struct community *new;
553
554 new = XCALLOC(MTYPE_COMMUNITY, sizeof(struct community));
555 new->size = com->size;
556 if (new->size) {
557 new->val = XMALLOC(MTYPE_COMMUNITY_VAL, com->size * 4);
558 memcpy(new->val, com->val, com->size * 4);
559 } else
560 new->val = NULL;
561 return new;
718e3744 562}
563
564/* Retrun string representation of communities attribute. */
a69ea8ae 565char *community_str(struct community *com, bool make_json)
718e3744 566{
d62a17ae 567 if (!com)
568 return NULL;
f1aa5d8a 569
a69ea8ae
DS
570 if (make_json && !com->json && com->str)
571 XFREE(MTYPE_COMMUNITY_STR, com->str);
572
d62a17ae 573 if (!com->str)
a69ea8ae 574 set_community_string(com, make_json);
d62a17ae 575 return com->str;
718e3744 576}
577
578/* Make hash value of community attribute. This function is used by
579 hash package.*/
d62a17ae 580unsigned int community_hash_make(struct community *com)
718e3744 581{
d7c0a89a 582 uint32_t *pnt = (uint32_t *)com->val;
d62a17ae 583
3f65c5b1 584 return jhash2(pnt, com->size, 0x43ea96c1);
718e3744 585}
586
d62a17ae 587int community_match(const struct community *com1, const struct community *com2)
718e3744 588{
d62a17ae 589 int i = 0;
590 int j = 0;
591
592 if (com1 == NULL && com2 == NULL)
593 return 1;
594
595 if (com1 == NULL || com2 == NULL)
596 return 0;
597
598 if (com1->size < com2->size)
599 return 0;
600
601 /* Every community on com2 needs to be on com1 for this to match */
602 while (i < com1->size && j < com2->size) {
d7c0a89a 603 if (memcmp(com1->val + i, com2->val + j, sizeof(uint32_t)) == 0)
d62a17ae 604 j++;
605 i++;
606 }
607
608 if (j == com2->size)
609 return 1;
610 else
611 return 0;
718e3744 612}
613
614/* If two aspath have same value then return 1 else return 0. This
615 function is used by hash package. */
74df8d6d 616bool community_cmp(const struct community *com1, const struct community *com2)
718e3744 617{
d62a17ae 618 if (com1 == NULL && com2 == NULL)
74df8d6d 619 return true;
d62a17ae 620 if (com1 == NULL || com2 == NULL)
74df8d6d 621 return false;
d62a17ae 622
623 if (com1->size == com2->size)
624 if (memcmp(com1->val, com2->val, com1->size * 4) == 0)
74df8d6d
DS
625 return true;
626 return false;
718e3744 627}
628
629/* Add com2 to the end of com1. */
d62a17ae 630struct community *community_merge(struct community *com1,
631 struct community *com2)
718e3744 632{
d62a17ae 633 if (com1->val)
634 com1->val = XREALLOC(MTYPE_COMMUNITY_VAL, com1->val,
635 (com1->size + com2->size) * 4);
636 else
637 com1->val = XMALLOC(MTYPE_COMMUNITY_VAL,
638 (com1->size + com2->size) * 4);
718e3744 639
d62a17ae 640 memcpy(com1->val + com1->size, com2->val, com2->size * 4);
641 com1->size += com2->size;
718e3744 642
d62a17ae 643 return com1;
718e3744 644}
645
646/* Community token enum. */
d62a17ae 647enum community_token {
648 community_token_val,
aa861c10
C
649 community_token_gshut,
650 community_token_accept_own,
651 community_token_route_filter_translated_v4,
652 community_token_route_filter_v4,
653 community_token_route_filter_translated_v6,
654 community_token_route_filter_v6,
655 community_token_llgr_stale,
656 community_token_no_llgr,
657 community_token_accept_own_nexthop,
658 community_token_blackhole,
d62a17ae 659 community_token_no_export,
660 community_token_no_advertise,
661 community_token_local_as,
aa861c10 662 community_token_no_peer,
d62a17ae 663 community_token_unknown
718e3744 664};
665
666/* Get next community token from string. */
94f2b392 667static const char *
d7c0a89a 668community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
718e3744 669{
d62a17ae 670 const char *p = buf;
671
672 /* Skip white space. */
673 while (isspace((int)*p))
674 p++;
675
676 /* Check the end of the line. */
677 if (*p == '\0')
678 return NULL;
679
680 /* Well known community string check. */
681 if (isalpha((int)*p)) {
682 if (strncmp(p, "internet", strlen("internet")) == 0) {
683 *val = COMMUNITY_INTERNET;
684 *token = community_token_no_export;
685 p += strlen("internet");
686 return p;
687 }
aa861c10
C
688 if (strncmp(p, "graceful-shutdown", strlen("graceful-shutdown"))
689 == 0) {
690 *val = COMMUNITY_GSHUT;
691 *token = community_token_gshut;
692 p += strlen("graceful-shutdown");
693 return p;
694 }
695 if (strncmp(p, "accept-own", strlen("accept-own"))
696 == 0) {
697 *val = COMMUNITY_ACCEPT_OWN;
698 *token = community_token_accept_own;
699 p += strlen("accept-own");
700 return p;
701 }
702 if (strncmp(p, "route-filter-translated-v4",
703 strlen("route-filter-translated-v4"))
704 == 0) {
705 *val = COMMUNITY_ROUTE_FILTER_TRANSLATED_v4;
706 *token = community_token_route_filter_translated_v4;
707 p += strlen("route-filter-translated-v4");
708 return p;
709 }
710 if (strncmp(p, "route-filter-v4", strlen("route-filter-v4"))
711 == 0) {
712 *val = COMMUNITY_ROUTE_FILTER_v4;
713 *token = community_token_route_filter_v4;
714 p += strlen("route-filter-v4");
715 return p;
716 }
717 if (strncmp(p, "route-filter-translated-v6",
718 strlen("route-filter-translated-v6"))
719 == 0) {
720 *val = COMMUNITY_ROUTE_FILTER_TRANSLATED_v6;
721 *token = community_token_route_filter_translated_v6;
722 p += strlen("route-filter-translated-v6");
723 return p;
724 }
725 if (strncmp(p, "route-filter-v6", strlen("route-filter-v6"))
726 == 0) {
727 *val = COMMUNITY_ROUTE_FILTER_v6;
728 *token = community_token_route_filter_v6;
729 p += strlen("route-filter-v6");
730 return p;
731 }
732 if (strncmp(p, "llgr-stale", strlen("llgr-stale"))
733 == 0) {
734 *val = COMMUNITY_LLGR_STALE;
735 *token = community_token_llgr_stale;
736 p += strlen("llgr-stale");
737 return p;
738 }
739 if (strncmp(p, "no-llgr", strlen("no-llgr"))
740 == 0) {
741 *val = COMMUNITY_NO_LLGR;
742 *token = community_token_no_llgr;
743 p += strlen("no-llgr");
744 return p;
745 }
746 if (strncmp(p, "accept-own-nexthop",
747 strlen("accept-own-nexthop"))
748 == 0) {
749 *val = COMMUNITY_ACCEPT_OWN_NEXTHOP;
750 *token = community_token_accept_own_nexthop;
751 p += strlen("accept-own-nexthop");
752 return p;
753 }
754 if (strncmp(p, "blackhole", strlen("blackhole"))
755 == 0) {
756 *val = COMMUNITY_BLACKHOLE;
757 *token = community_token_blackhole;
758 p += strlen("blackhole");
759 return p;
760 }
d62a17ae 761 if (strncmp(p, "no-export", strlen("no-export")) == 0) {
762 *val = COMMUNITY_NO_EXPORT;
763 *token = community_token_no_export;
764 p += strlen("no-export");
765 return p;
766 }
767 if (strncmp(p, "no-advertise", strlen("no-advertise")) == 0) {
768 *val = COMMUNITY_NO_ADVERTISE;
769 *token = community_token_no_advertise;
770 p += strlen("no-advertise");
771 return p;
772 }
773 if (strncmp(p, "local-AS", strlen("local-AS")) == 0) {
774 *val = COMMUNITY_LOCAL_AS;
775 *token = community_token_local_as;
776 p += strlen("local-AS");
777 return p;
778 }
aa861c10
C
779 if (strncmp(p, "no-peer", strlen("no-peer")) == 0) {
780 *val = COMMUNITY_NO_PEER;
781 *token = community_token_no_peer;
782 p += strlen("no-peer");
7f323236
DW
783 return p;
784 }
d62a17ae 785
786 /* Unknown string. */
787 *token = community_token_unknown;
788 return NULL;
718e3744 789 }
790
d62a17ae 791 /* Community value. */
792 if (isdigit((int)*p)) {
793 int separator = 0;
794 int digit = 0;
d7c0a89a
QY
795 uint32_t community_low = 0;
796 uint32_t community_high = 0;
d62a17ae 797
798 while (isdigit((int)*p) || *p == ':') {
799 if (*p == ':') {
800 if (separator) {
801 *token = community_token_unknown;
802 return NULL;
803 } else {
804 separator = 1;
805 digit = 0;
806
807 if (community_low > UINT16_MAX) {
808 *token =
809 community_token_unknown;
810 return NULL;
811 }
812
813 community_high = community_low << 16;
814 community_low = 0;
815 }
816 } else {
817 digit = 1;
818 community_low *= 10;
819 community_low += (*p - '0');
820 }
821 p++;
718e3744 822 }
d62a17ae 823 if (!digit) {
824 *token = community_token_unknown;
825 return NULL;
826 }
827
828 if (community_low > UINT16_MAX) {
829 *token = community_token_unknown;
830 return NULL;
718e3744 831 }
859d388e 832
d62a17ae 833 *val = community_high + community_low;
834 *token = community_token_val;
835 return p;
836 }
837 *token = community_token_unknown;
838 return NULL;
718e3744 839}
840
841/* convert string to community structure */
d62a17ae 842struct community *community_str2com(const char *str)
718e3744 843{
d62a17ae 844 struct community *com = NULL;
845 struct community *com_sort = NULL;
d7c0a89a 846 uint32_t val = 0;
d62a17ae 847 enum community_token token = community_token_unknown;
848
849 do {
850 str = community_gettoken(str, &token, &val);
851
852 switch (token) {
853 case community_token_val:
aa861c10
C
854 case community_token_gshut:
855 case community_token_accept_own:
856 case community_token_route_filter_translated_v4:
857 case community_token_route_filter_v4:
858 case community_token_route_filter_translated_v6:
859 case community_token_route_filter_v6:
860 case community_token_llgr_stale:
861 case community_token_no_llgr:
862 case community_token_accept_own_nexthop:
863 case community_token_blackhole:
d62a17ae 864 case community_token_no_export:
865 case community_token_no_advertise:
866 case community_token_local_as:
aa861c10 867 case community_token_no_peer:
d62a17ae 868 if (com == NULL) {
869 com = community_new();
870 com->json = NULL;
871 }
872 community_add_val(com, val);
873 break;
874 case community_token_unknown:
d62a17ae 875 if (com)
3c1f53de 876 community_free(&com);
d62a17ae 877 return NULL;
878 }
879 } while (str);
880
d62a17ae 881 com_sort = community_uniq_sort(com);
3c1f53de 882 community_free(&com);
718e3744 883
d62a17ae 884 return com_sort;
718e3744 885}
886
887/* Return communities hash entry count. */
d62a17ae 888unsigned long community_count(void)
718e3744 889{
d62a17ae 890 return comhash->count;
718e3744 891}
892
893/* Return communities hash. */
d62a17ae 894struct hash *community_hash(void)
718e3744 895{
d62a17ae 896 return comhash;
718e3744 897}
898
899/* Initialize comminity related hash. */
d62a17ae 900void community_init(void)
718e3744 901{
996c9314
LB
902 comhash =
903 hash_create((unsigned int (*)(void *))community_hash_make,
74df8d6d 904 (bool (*)(const void *, const void *))community_cmp,
996c9314 905 "BGP Community Hash");
718e3744 906}
228da428 907
d62a17ae 908void community_finish(void)
228da428 909{
d62a17ae 910 hash_free(comhash);
911 comhash = NULL;
228da428 912}