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