]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_lcommunity.c
Merge pull request #12603 from opensourcerouting/fix/deprecate_bgp_stuff_some
[mirror_frr.git] / bgpd / bgp_lcommunity.c
CommitLineData
57d187bc 1/* BGP Large Communities Attribute
2acb4ac2
DL
2 *
3 * Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
4 *
8678d638 5 * This file is part of FRRouting (FRR).
2acb4ac2
DL
6 *
7 * FRR is free software; you can redistribute it and/or modify it under the
8 * terms of the GNU General Public License as published by the Free Software
9 * Foundation; either version 2, or (at your option) any later version.
10 *
11 * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public License along
896014f4
DL
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
2acb4ac2 19 */
57d187bc
JS
20
21#include <zebra.h>
22
23#include "hash.h"
24#include "memory.h"
25#include "prefix.h"
26#include "command.h"
27#include "filter.h"
3f65c5b1 28#include "jhash.h"
937652c6 29#include "stream.h"
57d187bc
JS
30
31#include "bgpd/bgpd.h"
32#include "bgpd/bgp_lcommunity.h"
ed0e57e3 33#include "bgpd/bgp_community_alias.h"
57d187bc
JS
34#include "bgpd/bgp_aspath.h"
35
36/* Hash of community attribute. */
37static struct hash *lcomhash;
38
39/* Allocate a new lcommunities. */
d62a17ae 40static struct lcommunity *lcommunity_new(void)
57d187bc 41{
9f5dc319 42 return XCALLOC(MTYPE_LCOMMUNITY, sizeof(struct lcommunity));
57d187bc
JS
43}
44
45/* Allocate lcommunities. */
d62a17ae 46void lcommunity_free(struct lcommunity **lcom)
57d187bc 47{
2c15754e
JC
48 if (!(*lcom))
49 return;
50
0a22ddfb
QY
51 XFREE(MTYPE_LCOMMUNITY_VAL, (*lcom)->val);
52 XFREE(MTYPE_LCOMMUNITY_STR, (*lcom)->str);
74a630b6
NT
53 if ((*lcom)->json)
54 json_object_free((*lcom)->json);
d62a17ae 55 XFREE(MTYPE_LCOMMUNITY, *lcom);
57d187bc
JS
56}
57
d62a17ae 58static void lcommunity_hash_free(struct lcommunity *lcom)
47350fd9 59{
d62a17ae 60 lcommunity_free(&lcom);
47350fd9
DS
61}
62
57d187bc
JS
63/* Add a new Large Communities value to Large Communities
64 Attribute structure. When the value is already exists in the
65 structure, we don't add the value. Newly added value is sorted by
66 numerical order. When the value is added to the structure return 1
67 else return 0. */
3dc339cd
DA
68static bool lcommunity_add_val(struct lcommunity *lcom,
69 struct lcommunity_val *lval)
57d187bc 70{
d7c0a89a 71 uint8_t *p;
d62a17ae 72 int ret;
73 int c;
74
75 /* When this is fist value, just add it. */
76 if (lcom->val == NULL) {
77 lcom->size++;
78 lcom->val = XMALLOC(MTYPE_LCOMMUNITY_VAL, lcom_length(lcom));
79 memcpy(lcom->val, lval->val, LCOMMUNITY_SIZE);
3dc339cd 80 return true;
d62a17ae 81 }
82
83 /* If the value already exists in the structure return 0. */
84 c = 0;
85 for (p = lcom->val; c < lcom->size; p += LCOMMUNITY_SIZE, c++) {
86 ret = memcmp(p, lval->val, LCOMMUNITY_SIZE);
87 if (ret == 0)
3dc339cd 88 return false;
d62a17ae 89 if (ret > 0)
90 break;
91 }
92
93 /* Add the value to the structure with numerical sorting. */
94 lcom->size++;
95 lcom->val =
96 XREALLOC(MTYPE_LCOMMUNITY_VAL, lcom->val, lcom_length(lcom));
97
98 memmove(lcom->val + (c + 1) * LCOMMUNITY_SIZE,
99 lcom->val + c * LCOMMUNITY_SIZE,
100 (lcom->size - 1 - c) * LCOMMUNITY_SIZE);
101 memcpy(lcom->val + c * LCOMMUNITY_SIZE, lval->val, LCOMMUNITY_SIZE);
102
3dc339cd 103 return true;
57d187bc
JS
104}
105
544be979 106/* This function takes pointer to Large Communites structure then
57d187bc
JS
107 create a new Large Communities structure by uniq and sort each
108 Large Communities value. */
d62a17ae 109struct lcommunity *lcommunity_uniq_sort(struct lcommunity *lcom)
57d187bc 110{
d62a17ae 111 int i;
112 struct lcommunity *new;
113 struct lcommunity_val *lval;
57d187bc 114
d62a17ae 115 if (!lcom)
116 return NULL;
57d187bc 117
d62a17ae 118 new = lcommunity_new();
57d187bc 119
d62a17ae 120 for (i = 0; i < lcom->size; i++) {
121 lval = (struct lcommunity_val *)(lcom->val
122 + (i * LCOMMUNITY_SIZE));
123 lcommunity_add_val(new, lval);
124 }
125 return new;
57d187bc
JS
126}
127
128/* Parse Large Communites Attribute in BGP packet. */
d7c0a89a 129struct lcommunity *lcommunity_parse(uint8_t *pnt, unsigned short length)
57d187bc 130{
d62a17ae 131 struct lcommunity tmp;
132 struct lcommunity *new;
57d187bc 133
d62a17ae 134 /* Length check. */
135 if (length % LCOMMUNITY_SIZE)
136 return NULL;
57d187bc 137
d62a17ae 138 /* Prepare tmporary structure for making a new Large Communities
139 Attribute. */
140 tmp.size = length / LCOMMUNITY_SIZE;
141 tmp.val = pnt;
57d187bc 142
d62a17ae 143 /* Create a new Large Communities Attribute by uniq and sort each
144 Large Communities value */
145 new = lcommunity_uniq_sort(&tmp);
57d187bc 146
d62a17ae 147 return lcommunity_intern(new);
57d187bc
JS
148}
149
150/* Duplicate the Large Communities Attribute structure. */
d62a17ae 151struct lcommunity *lcommunity_dup(struct lcommunity *lcom)
57d187bc 152{
d62a17ae 153 struct lcommunity *new;
154
cb0c2da3 155 new = lcommunity_new();
d62a17ae 156 new->size = lcom->size;
157 if (new->size) {
79dab4b7
NK
158 new->val = XMALLOC(MTYPE_LCOMMUNITY_VAL, lcom_length(lcom));
159 memcpy(new->val, lcom->val, lcom_length(lcom));
d62a17ae 160 } else
161 new->val = NULL;
162 return new;
57d187bc
JS
163}
164
57d187bc 165/* Merge two Large Communities Attribute structure. */
d62a17ae 166struct lcommunity *lcommunity_merge(struct lcommunity *lcom1,
167 struct lcommunity *lcom2)
57d187bc 168{
0b04fa0e
DS
169 lcom1->val = XREALLOC(MTYPE_LCOMMUNITY_VAL, lcom1->val,
170 lcom_length(lcom1) + lcom_length(lcom2));
d62a17ae 171
79dab4b7 172 memcpy(lcom1->val + lcom_length(lcom1), lcom2->val, lcom_length(lcom2));
d62a17ae 173 lcom1->size += lcom2->size;
174
175 return lcom1;
57d187bc
JS
176}
177
c0945b78
DA
178static void set_lcommunity_string(struct lcommunity *lcom, bool make_json,
179 bool translate_alias)
8d9b8ed9
PM
180{
181 int i;
182 int len;
8d9b8ed9 183 char *str_buf;
1be1693e 184 const uint8_t *pnt;
8d9b8ed9
PM
185 uint32_t global, local1, local2;
186 json_object *json_lcommunity_list = NULL;
187 json_object *json_string = NULL;
188
73bfd76d
QY
189 /* 3 32-bit integers, 2 colons, and a space */
190#define LCOMMUNITY_STRLEN (10 * 3 + 2 + 1)
8d9b8ed9
PM
191
192 if (!lcom)
193 return;
194
195 if (make_json) {
196 lcom->json = json_object_new_object();
197 json_lcommunity_list = json_object_new_array();
198 }
199
200 if (lcom->size == 0) {
73bfd76d 201 str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, 1);
8d9b8ed9
PM
202
203 if (make_json) {
204 json_object_string_add(lcom->json, "string", "");
205 json_object_object_add(lcom->json, "list",
206 json_lcommunity_list);
207 }
208
209 lcom->str = str_buf;
210 return;
211 }
212
73bfd76d 213 /* 1 space + lcom->size lcom strings + null terminator */
ed0e57e3 214 size_t str_buf_sz = BUFSIZ;
73bfd76d 215 str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, str_buf_sz);
8d9b8ed9
PM
216
217 for (i = 0; i < lcom->size; i++) {
73bfd76d
QY
218 if (i > 0)
219 strlcat(str_buf, " ", str_buf_sz);
8d9b8ed9
PM
220
221 pnt = lcom->val + (i * LCOMMUNITY_SIZE);
222 pnt = ptr_get_be32(pnt, &global);
223 pnt = ptr_get_be32(pnt, &local1);
224 pnt = ptr_get_be32(pnt, &local2);
225 (void)pnt;
226
73bfd76d
QY
227 char lcsb[LCOMMUNITY_STRLEN + 1];
228
229 snprintf(lcsb, sizeof(lcsb), "%u:%u:%u", global, local1,
230 local2);
231
c0945b78
DA
232 const char *com2alias =
233 translate_alias ? bgp_community2alias(lcsb) : lcsb;
d95a84e0
DA
234
235 len = strlcat(str_buf, com2alias, str_buf_sz);
73bfd76d
QY
236 assert((unsigned int)len < str_buf_sz);
237
8d9b8ed9 238 if (make_json) {
d95a84e0 239 json_string = json_object_new_string(com2alias);
8d9b8ed9
PM
240 json_object_array_add(json_lcommunity_list,
241 json_string);
242 }
8d9b8ed9
PM
243 }
244
8d9b8ed9
PM
245 if (make_json) {
246 json_object_string_add(lcom->json, "string", str_buf);
247 json_object_object_add(lcom->json, "list",
248 json_lcommunity_list);
249 }
250
251 lcom->str = str_buf;
252}
253
57d187bc 254/* Intern Large Communities Attribute. */
d62a17ae 255struct lcommunity *lcommunity_intern(struct lcommunity *lcom)
57d187bc 256{
d62a17ae 257 struct lcommunity *find;
57d187bc 258
d62a17ae 259 assert(lcom->refcnt == 0);
57d187bc 260
d62a17ae 261 find = (struct lcommunity *)hash_get(lcomhash, lcom, hash_alloc_intern);
57d187bc 262
d62a17ae 263 if (find != lcom)
264 lcommunity_free(&lcom);
57d187bc 265
d62a17ae 266 find->refcnt++;
57d187bc 267
d62a17ae 268 if (!find->str)
c0945b78 269 set_lcommunity_string(find, false, true);
57d187bc 270
d62a17ae 271 return find;
57d187bc
JS
272}
273
274/* Unintern Large Communities Attribute. */
d62a17ae 275void lcommunity_unintern(struct lcommunity **lcom)
57d187bc 276{
d62a17ae 277 struct lcommunity *ret;
57d187bc 278
1bcf3a96
DA
279 if (!*lcom)
280 return;
281
d62a17ae 282 if ((*lcom)->refcnt)
283 (*lcom)->refcnt--;
57d187bc 284
d62a17ae 285 /* Pull off from hash. */
286 if ((*lcom)->refcnt == 0) {
287 /* Large community must be in the hash. */
288 ret = (struct lcommunity *)hash_release(lcomhash, *lcom);
289 assert(ret != NULL);
57d187bc 290
d62a17ae 291 lcommunity_free(lcom);
292 }
57d187bc
JS
293}
294
639caccf 295/* Return string representation of lcommunities attribute. */
c0945b78
DA
296char *lcommunity_str(struct lcommunity *lcom, bool make_json,
297 bool translate_alias)
8d9b8ed9
PM
298{
299 if (!lcom)
300 return NULL;
301
302 if (make_json && !lcom->json && lcom->str)
303 XFREE(MTYPE_LCOMMUNITY_STR, lcom->str);
304
305 if (!lcom->str)
c0945b78 306 set_lcommunity_string(lcom, make_json, translate_alias);
8d9b8ed9
PM
307
308 return lcom->str;
309}
310
57d187bc 311/* Utility function to make hash key. */
d8b87afe 312unsigned int lcommunity_hash_make(const void *arg)
57d187bc 313{
d62a17ae 314 const struct lcommunity *lcom = arg;
79dab4b7 315 int size = lcom_length(lcom);
d62a17ae 316
3f65c5b1 317 return jhash(lcom->val, size, 0xab125423);
57d187bc
JS
318}
319
320/* Compare two Large Communities Attribute structure. */
74df8d6d 321bool lcommunity_cmp(const void *arg1, const void *arg2)
57d187bc 322{
d62a17ae 323 const struct lcommunity *lcom1 = arg1;
324 const struct lcommunity *lcom2 = arg2;
57d187bc 325
fbcdff82 326 if (lcom1 == NULL && lcom2 == NULL)
b08047f8 327 return true;
fbcdff82
RW
328
329 if (lcom1 == NULL || lcom2 == NULL)
b08047f8 330 return false;
fbcdff82 331
d62a17ae 332 return (lcom1->size == lcom2->size
996c9314 333 && memcmp(lcom1->val, lcom2->val, lcom_length(lcom1)) == 0);
57d187bc
JS
334}
335
336/* Return communities hash. */
d62a17ae 337struct hash *lcommunity_hash(void)
57d187bc 338{
d62a17ae 339 return lcomhash;
57d187bc
JS
340}
341
342/* Initialize Large Comminities related hash. */
d62a17ae 343void lcommunity_init(void)
57d187bc 344{
996c9314 345 lcomhash = hash_create(lcommunity_hash_make, lcommunity_cmp,
3f65c5b1 346 "BGP lcommunity hash");
57d187bc
JS
347}
348
d62a17ae 349void lcommunity_finish(void)
57d187bc 350{
d62a17ae 351 hash_clean(lcomhash, (void (*)(void *))lcommunity_hash_free);
352 hash_free(lcomhash);
353 lcomhash = NULL;
57d187bc
JS
354}
355
c850908b
WC
356/* Get next Large Communities token from the string.
357 * Assumes str is space-delimeted and describes 0 or more
358 * valid large communities
359 */
d62a17ae 360static const char *lcommunity_gettoken(const char *str,
c850908b 361 struct lcommunity_val *lval)
57d187bc 362{
d62a17ae 363 const char *p = str;
364
365 /* Skip white space. */
fefa5e0f 366 while (isspace((unsigned char)*p)) {
d62a17ae 367 p++;
368 str++;
369 }
370
371 /* Check the end of the line. */
372 if (*p == '\0')
373 return NULL;
374
375 /* Community value. */
c850908b
WC
376 int separator = 0;
377 int digit = 0;
378 uint32_t globaladmin = 0;
379 uint32_t localdata1 = 0;
380 uint32_t localdata2 = 0;
381
382 while (*p && *p != ' ') {
383 /* large community valid chars */
384 assert(isdigit((unsigned char)*p) || *p == ':');
385
386 if (*p == ':') {
387 separator++;
388 digit = 0;
389 if (separator == 1) {
390 globaladmin = localdata2;
d62a17ae 391 } else {
c850908b 392 localdata1 = localdata2;
d62a17ae 393 }
c850908b
WC
394 localdata2 = 0;
395 } else {
396 digit = 1;
397 /* left shift the accumulated value and add current
398 * digit
399 */
400 localdata2 *= 10;
401 localdata2 += (*p - '0');
57d187bc 402 }
c850908b 403 p++;
d62a17ae 404 }
c850908b
WC
405
406 /* Assert str was a valid large community */
407 assert(separator == 2 && digit == 1);
408
409 /*
410 * Copy the large comm.
411 */
412 lval->val[0] = (globaladmin >> 24) & 0xff;
413 lval->val[1] = (globaladmin >> 16) & 0xff;
414 lval->val[2] = (globaladmin >> 8) & 0xff;
415 lval->val[3] = globaladmin & 0xff;
416 lval->val[4] = (localdata1 >> 24) & 0xff;
417 lval->val[5] = (localdata1 >> 16) & 0xff;
418 lval->val[6] = (localdata1 >> 8) & 0xff;
419 lval->val[7] = localdata1 & 0xff;
420 lval->val[8] = (localdata2 >> 24) & 0xff;
421 lval->val[9] = (localdata2 >> 16) & 0xff;
422 lval->val[10] = (localdata2 >> 8) & 0xff;
423 lval->val[11] = localdata2 & 0xff;
424
d62a17ae 425 return p;
57d187bc
JS
426}
427
428/*
429 Convert string to large community attribute.
430 When type is already known, please specify both str and type.
431
432 When string includes keyword for each large community value.
433 Please specify keyword_included as non-zero value.
434*/
d62a17ae 435struct lcommunity *lcommunity_str2com(const char *str)
57d187bc 436{
d62a17ae 437 struct lcommunity *lcom = NULL;
d62a17ae 438 struct lcommunity_val lval;
439
c850908b
WC
440 if (!lcommunity_list_valid(str, LARGE_COMMUNITY_LIST_STANDARD))
441 return NULL;
442
6aee3848 443 do {
c850908b
WC
444 str = lcommunity_gettoken(str, &lval);
445 if (lcom == NULL)
446 lcom = lcommunity_new();
447 lcommunity_add_val(lcom, &lval);
6aee3848
NT
448 } while (str);
449
d62a17ae 450 return lcom;
57d187bc
JS
451}
452
3dc339cd 453bool lcommunity_include(struct lcommunity *lcom, uint8_t *ptr)
57d187bc 454{
d62a17ae 455 int i;
d7c0a89a 456 uint8_t *lcom_ptr;
d62a17ae 457
d62a17ae 458 for (i = 0; i < lcom->size; i++) {
3ac053e6 459 lcom_ptr = lcom->val + (i * LCOMMUNITY_SIZE);
d62a17ae 460 if (memcmp(ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0)
3dc339cd 461 return true;
d62a17ae 462 }
3dc339cd 463 return false;
57d187bc
JS
464}
465
3dc339cd
DA
466bool lcommunity_match(const struct lcommunity *lcom1,
467 const struct lcommunity *lcom2)
57d187bc 468{
d62a17ae 469 int i = 0;
470 int j = 0;
471
472 if (lcom1 == NULL && lcom2 == NULL)
3dc339cd 473 return true;
d62a17ae 474
475 if (lcom1 == NULL || lcom2 == NULL)
3dc339cd 476 return false;
d62a17ae 477
478 if (lcom1->size < lcom2->size)
3dc339cd 479 return false;
d62a17ae 480
481 /* Every community on com2 needs to be on com1 for this to match */
482 while (i < lcom1->size && j < lcom2->size) {
996c9314
LB
483 if (memcmp(lcom1->val + (i * LCOMMUNITY_SIZE),
484 lcom2->val + (j * LCOMMUNITY_SIZE), LCOMMUNITY_SIZE)
d62a17ae 485 == 0)
486 j++;
487 i++;
488 }
489
490 if (j == lcom2->size)
3dc339cd 491 return true;
d62a17ae 492 else
3dc339cd 493 return false;
57d187bc
JS
494}
495
496/* Delete one lcommunity. */
d7c0a89a 497void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr)
57d187bc 498{
d62a17ae 499 int i = 0;
500 int c = 0;
501
502 if (!lcom->val)
503 return;
504
505 while (i < lcom->size) {
506 if (memcmp(lcom->val + i * LCOMMUNITY_SIZE, ptr,
507 LCOMMUNITY_SIZE)
508 == 0) {
509 c = lcom->size - i - 1;
510
511 if (c > 0)
512 memmove(lcom->val + i * LCOMMUNITY_SIZE,
513 lcom->val + (i + 1) * LCOMMUNITY_SIZE,
514 c * LCOMMUNITY_SIZE);
515
516 lcom->size--;
517
518 if (lcom->size > 0)
519 lcom->val =
996c9314
LB
520 XREALLOC(MTYPE_LCOMMUNITY_VAL,
521 lcom->val, lcom_length(lcom));
d62a17ae 522 else {
600d7ff8 523 XFREE(MTYPE_LCOMMUNITY_VAL, lcom->val);
d62a17ae 524 }
525 return;
526 }
527 i++;
57d187bc 528 }
57d187bc 529}
4c99b6c2
NT
530
531static struct lcommunity *bgp_aggr_lcommunity_lookup(
532 struct bgp_aggregate *aggregate,
533 struct lcommunity *lcommunity)
534{
535 return hash_lookup(aggregate->lcommunity_hash, lcommunity);
536}
537
538static void *bgp_aggr_lcommunty_hash_alloc(void *p)
539{
540 struct lcommunity *ref = (struct lcommunity *)p;
541 struct lcommunity *lcommunity = NULL;
542
543 lcommunity = lcommunity_dup(ref);
544 return lcommunity;
545}
546
7f5818fb 547static void bgp_aggr_lcommunity_prepare(struct hash_bucket *hb, void *arg)
4c99b6c2 548{
4c99b6c2
NT
549 struct lcommunity *hb_lcommunity = hb->data;
550 struct lcommunity **aggr_lcommunity = arg;
551
f1eb1f05 552 if (*aggr_lcommunity)
553 *aggr_lcommunity = lcommunity_merge(*aggr_lcommunity,
554 hb_lcommunity);
555 else
4c99b6c2
NT
556 *aggr_lcommunity = lcommunity_dup(hb_lcommunity);
557}
558
559void bgp_aggr_lcommunity_remove(void *arg)
560{
561 struct lcommunity *lcommunity = arg;
562
563 lcommunity_free(&lcommunity);
564}
565
566void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate,
567 struct lcommunity *lcommunity)
568{
f1eb1f05 569
570 bgp_compute_aggregate_lcommunity_hash(aggregate, lcommunity);
571 bgp_compute_aggregate_lcommunity_val(aggregate);
572}
573
574void bgp_compute_aggregate_lcommunity_hash(struct bgp_aggregate *aggregate,
575 struct lcommunity *lcommunity)
576{
577
4c99b6c2
NT
578 struct lcommunity *aggr_lcommunity = NULL;
579
580 if ((aggregate == NULL) || (lcommunity == NULL))
581 return;
582
583 /* Create hash if not already created.
584 */
585 if (aggregate->lcommunity_hash == NULL)
586 aggregate->lcommunity_hash = hash_create(
587 lcommunity_hash_make, lcommunity_cmp,
588 "BGP Aggregator lcommunity hash");
589
590 aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
591 if (aggr_lcommunity == NULL) {
592 /* Insert lcommunity into hash.
593 */
594 aggr_lcommunity = hash_get(aggregate->lcommunity_hash,
595 lcommunity,
596 bgp_aggr_lcommunty_hash_alloc);
f1eb1f05 597 }
4c99b6c2 598
f1eb1f05 599 /* Increment reference counter.
600 */
601 aggr_lcommunity->refcnt++;
602}
603
604void bgp_compute_aggregate_lcommunity_val(struct bgp_aggregate *aggregate)
605{
606 struct lcommunity *lcommerge = NULL;
607
608 if (aggregate == NULL)
609 return;
4c99b6c2 610
f1eb1f05 611 /* Re-compute aggregate's lcommunity.
612 */
613 if (aggregate->lcommunity)
614 lcommunity_free(&aggregate->lcommunity);
615 if (aggregate->lcommunity_hash &&
616 aggregate->lcommunity_hash->count) {
4c99b6c2
NT
617 hash_iterate(aggregate->lcommunity_hash,
618 bgp_aggr_lcommunity_prepare,
619 &aggregate->lcommunity);
f1eb1f05 620 lcommerge = aggregate->lcommunity;
621 aggregate->lcommunity = lcommunity_uniq_sort(lcommerge);
622 if (lcommerge)
623 lcommunity_free(&lcommerge);
4c99b6c2 624 }
4c99b6c2
NT
625}
626
627void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate,
628 struct lcommunity *lcommunity)
629{
630 struct lcommunity *aggr_lcommunity = NULL;
631 struct lcommunity *ret_lcomm = NULL;
632
f1eb1f05 633 if ((!aggregate)
634 || (!aggregate->lcommunity_hash)
635 || (!lcommunity))
4c99b6c2
NT
636 return;
637
638 /* Look-up the lcommunity in the hash.
639 */
640 aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
641 if (aggr_lcommunity) {
642 aggr_lcommunity->refcnt--;
643
644 if (aggr_lcommunity->refcnt == 0) {
645 ret_lcomm = hash_release(aggregate->lcommunity_hash,
646 aggr_lcommunity);
647 lcommunity_free(&ret_lcomm);
648
f1eb1f05 649 bgp_compute_aggregate_lcommunity_val(aggregate);
650
651 }
652 }
653}
654
655void bgp_remove_lcomm_from_aggregate_hash(struct bgp_aggregate *aggregate,
656 struct lcommunity *lcommunity)
657{
658 struct lcommunity *aggr_lcommunity = NULL;
659 struct lcommunity *ret_lcomm = NULL;
4c99b6c2 660
f1eb1f05 661 if ((!aggregate)
662 || (!aggregate->lcommunity_hash)
663 || (!lcommunity))
664 return;
665
666 /* Look-up the lcommunity in the hash.
667 */
668 aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
669 if (aggr_lcommunity) {
670 aggr_lcommunity->refcnt--;
671
672 if (aggr_lcommunity->refcnt == 0) {
673 ret_lcomm = hash_release(aggregate->lcommunity_hash,
674 aggr_lcommunity);
675 lcommunity_free(&ret_lcomm);
4c99b6c2
NT
676 }
677 }
678}