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