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