]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_lcommunity.c
tests: Check if Node Target Extended Communities work
[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 */
ed0e57e3 200 size_t str_buf_sz = BUFSIZ;
73bfd76d 201 str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, str_buf_sz);
8d9b8ed9
PM
202
203 for (i = 0; i < lcom->size; i++) {
73bfd76d
QY
204 if (i > 0)
205 strlcat(str_buf, " ", str_buf_sz);
8d9b8ed9
PM
206
207 pnt = lcom->val + (i * LCOMMUNITY_SIZE);
208 pnt = ptr_get_be32(pnt, &global);
209 pnt = ptr_get_be32(pnt, &local1);
210 pnt = ptr_get_be32(pnt, &local2);
211 (void)pnt;
212
73bfd76d
QY
213 char lcsb[LCOMMUNITY_STRLEN + 1];
214
215 snprintf(lcsb, sizeof(lcsb), "%u:%u:%u", global, local1,
216 local2);
217
c0945b78
DA
218 const char *com2alias =
219 translate_alias ? bgp_community2alias(lcsb) : lcsb;
d95a84e0
DA
220
221 len = strlcat(str_buf, com2alias, str_buf_sz);
73bfd76d
QY
222 assert((unsigned int)len < str_buf_sz);
223
8d9b8ed9 224 if (make_json) {
d95a84e0 225 json_string = json_object_new_string(com2alias);
8d9b8ed9
PM
226 json_object_array_add(json_lcommunity_list,
227 json_string);
228 }
8d9b8ed9
PM
229 }
230
8d9b8ed9
PM
231 if (make_json) {
232 json_object_string_add(lcom->json, "string", str_buf);
233 json_object_object_add(lcom->json, "list",
234 json_lcommunity_list);
235 }
236
237 lcom->str = str_buf;
238}
239
57d187bc 240/* Intern Large Communities Attribute. */
d62a17ae 241struct lcommunity *lcommunity_intern(struct lcommunity *lcom)
57d187bc 242{
d62a17ae 243 struct lcommunity *find;
57d187bc 244
d62a17ae 245 assert(lcom->refcnt == 0);
57d187bc 246
d62a17ae 247 find = (struct lcommunity *)hash_get(lcomhash, lcom, hash_alloc_intern);
57d187bc 248
d62a17ae 249 if (find != lcom)
250 lcommunity_free(&lcom);
57d187bc 251
d62a17ae 252 find->refcnt++;
57d187bc 253
d62a17ae 254 if (!find->str)
c0945b78 255 set_lcommunity_string(find, false, true);
57d187bc 256
d62a17ae 257 return find;
57d187bc
JS
258}
259
260/* Unintern Large Communities Attribute. */
d62a17ae 261void lcommunity_unintern(struct lcommunity **lcom)
57d187bc 262{
d62a17ae 263 struct lcommunity *ret;
57d187bc 264
1bcf3a96
DA
265 if (!*lcom)
266 return;
267
d62a17ae 268 if ((*lcom)->refcnt)
269 (*lcom)->refcnt--;
57d187bc 270
d62a17ae 271 /* Pull off from hash. */
272 if ((*lcom)->refcnt == 0) {
273 /* Large community must be in the hash. */
274 ret = (struct lcommunity *)hash_release(lcomhash, *lcom);
275 assert(ret != NULL);
57d187bc 276
d62a17ae 277 lcommunity_free(lcom);
278 }
57d187bc
JS
279}
280
639caccf 281/* Return string representation of lcommunities attribute. */
c0945b78
DA
282char *lcommunity_str(struct lcommunity *lcom, bool make_json,
283 bool translate_alias)
8d9b8ed9
PM
284{
285 if (!lcom)
286 return NULL;
287
288 if (make_json && !lcom->json && lcom->str)
289 XFREE(MTYPE_LCOMMUNITY_STR, lcom->str);
290
291 if (!lcom->str)
c0945b78 292 set_lcommunity_string(lcom, make_json, translate_alias);
8d9b8ed9
PM
293
294 return lcom->str;
295}
296
57d187bc 297/* Utility function to make hash key. */
d8b87afe 298unsigned int lcommunity_hash_make(const void *arg)
57d187bc 299{
d62a17ae 300 const struct lcommunity *lcom = arg;
79dab4b7 301 int size = lcom_length(lcom);
d62a17ae 302
3f65c5b1 303 return jhash(lcom->val, size, 0xab125423);
57d187bc
JS
304}
305
306/* Compare two Large Communities Attribute structure. */
74df8d6d 307bool lcommunity_cmp(const void *arg1, const void *arg2)
57d187bc 308{
d62a17ae 309 const struct lcommunity *lcom1 = arg1;
310 const struct lcommunity *lcom2 = arg2;
57d187bc 311
fbcdff82 312 if (lcom1 == NULL && lcom2 == NULL)
b08047f8 313 return true;
fbcdff82
RW
314
315 if (lcom1 == NULL || lcom2 == NULL)
b08047f8 316 return false;
fbcdff82 317
d62a17ae 318 return (lcom1->size == lcom2->size
996c9314 319 && memcmp(lcom1->val, lcom2->val, lcom_length(lcom1)) == 0);
57d187bc
JS
320}
321
322/* Return communities hash. */
d62a17ae 323struct hash *lcommunity_hash(void)
57d187bc 324{
d62a17ae 325 return lcomhash;
57d187bc
JS
326}
327
328/* Initialize Large Comminities related hash. */
d62a17ae 329void lcommunity_init(void)
57d187bc 330{
996c9314 331 lcomhash = hash_create(lcommunity_hash_make, lcommunity_cmp,
3f65c5b1 332 "BGP lcommunity hash");
57d187bc
JS
333}
334
d62a17ae 335void lcommunity_finish(void)
57d187bc 336{
d8bc11a5 337 hash_clean_and_free(&lcomhash, (void (*)(void *))lcommunity_hash_free);
57d187bc
JS
338}
339
c850908b
WC
340/* Get next Large Communities token from the string.
341 * Assumes str is space-delimeted and describes 0 or more
342 * valid large communities
343 */
d62a17ae 344static const char *lcommunity_gettoken(const char *str,
c850908b 345 struct lcommunity_val *lval)
57d187bc 346{
d62a17ae 347 const char *p = str;
348
349 /* Skip white space. */
fefa5e0f 350 while (isspace((unsigned char)*p)) {
d62a17ae 351 p++;
352 str++;
353 }
354
355 /* Check the end of the line. */
356 if (*p == '\0')
357 return NULL;
358
359 /* Community value. */
c850908b
WC
360 int separator = 0;
361 int digit = 0;
362 uint32_t globaladmin = 0;
363 uint32_t localdata1 = 0;
364 uint32_t localdata2 = 0;
365
366 while (*p && *p != ' ') {
367 /* large community valid chars */
368 assert(isdigit((unsigned char)*p) || *p == ':');
369
370 if (*p == ':') {
371 separator++;
372 digit = 0;
373 if (separator == 1) {
374 globaladmin = localdata2;
d62a17ae 375 } else {
c850908b 376 localdata1 = localdata2;
d62a17ae 377 }
c850908b
WC
378 localdata2 = 0;
379 } else {
380 digit = 1;
381 /* left shift the accumulated value and add current
382 * digit
383 */
384 localdata2 *= 10;
385 localdata2 += (*p - '0');
57d187bc 386 }
c850908b 387 p++;
d62a17ae 388 }
c850908b
WC
389
390 /* Assert str was a valid large community */
391 assert(separator == 2 && digit == 1);
392
393 /*
394 * Copy the large comm.
395 */
396 lval->val[0] = (globaladmin >> 24) & 0xff;
397 lval->val[1] = (globaladmin >> 16) & 0xff;
398 lval->val[2] = (globaladmin >> 8) & 0xff;
399 lval->val[3] = globaladmin & 0xff;
400 lval->val[4] = (localdata1 >> 24) & 0xff;
401 lval->val[5] = (localdata1 >> 16) & 0xff;
402 lval->val[6] = (localdata1 >> 8) & 0xff;
403 lval->val[7] = localdata1 & 0xff;
404 lval->val[8] = (localdata2 >> 24) & 0xff;
405 lval->val[9] = (localdata2 >> 16) & 0xff;
406 lval->val[10] = (localdata2 >> 8) & 0xff;
407 lval->val[11] = localdata2 & 0xff;
408
d62a17ae 409 return p;
57d187bc
JS
410}
411
412/*
413 Convert string to large community attribute.
414 When type is already known, please specify both str and type.
415
416 When string includes keyword for each large community value.
417 Please specify keyword_included as non-zero value.
418*/
d62a17ae 419struct lcommunity *lcommunity_str2com(const char *str)
57d187bc 420{
d62a17ae 421 struct lcommunity *lcom = NULL;
d62a17ae 422 struct lcommunity_val lval;
423
c850908b
WC
424 if (!lcommunity_list_valid(str, LARGE_COMMUNITY_LIST_STANDARD))
425 return NULL;
426
6aee3848 427 do {
c850908b
WC
428 str = lcommunity_gettoken(str, &lval);
429 if (lcom == NULL)
430 lcom = lcommunity_new();
431 lcommunity_add_val(lcom, &lval);
6aee3848
NT
432 } while (str);
433
d62a17ae 434 return lcom;
57d187bc
JS
435}
436
3dc339cd 437bool lcommunity_include(struct lcommunity *lcom, uint8_t *ptr)
57d187bc 438{
d62a17ae 439 int i;
d7c0a89a 440 uint8_t *lcom_ptr;
d62a17ae 441
d62a17ae 442 for (i = 0; i < lcom->size; i++) {
3ac053e6 443 lcom_ptr = lcom->val + (i * LCOMMUNITY_SIZE);
d62a17ae 444 if (memcmp(ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0)
3dc339cd 445 return true;
d62a17ae 446 }
3dc339cd 447 return false;
57d187bc
JS
448}
449
3dc339cd
DA
450bool lcommunity_match(const struct lcommunity *lcom1,
451 const struct lcommunity *lcom2)
57d187bc 452{
d62a17ae 453 int i = 0;
454 int j = 0;
455
456 if (lcom1 == NULL && lcom2 == NULL)
3dc339cd 457 return true;
d62a17ae 458
459 if (lcom1 == NULL || lcom2 == NULL)
3dc339cd 460 return false;
d62a17ae 461
462 if (lcom1->size < lcom2->size)
3dc339cd 463 return false;
d62a17ae 464
465 /* Every community on com2 needs to be on com1 for this to match */
466 while (i < lcom1->size && j < lcom2->size) {
996c9314
LB
467 if (memcmp(lcom1->val + (i * LCOMMUNITY_SIZE),
468 lcom2->val + (j * LCOMMUNITY_SIZE), LCOMMUNITY_SIZE)
d62a17ae 469 == 0)
470 j++;
471 i++;
472 }
473
474 if (j == lcom2->size)
3dc339cd 475 return true;
d62a17ae 476 else
3dc339cd 477 return false;
57d187bc
JS
478}
479
480/* Delete one lcommunity. */
d7c0a89a 481void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr)
57d187bc 482{
d62a17ae 483 int i = 0;
484 int c = 0;
485
486 if (!lcom->val)
487 return;
488
489 while (i < lcom->size) {
490 if (memcmp(lcom->val + i * LCOMMUNITY_SIZE, ptr,
491 LCOMMUNITY_SIZE)
492 == 0) {
493 c = lcom->size - i - 1;
494
495 if (c > 0)
496 memmove(lcom->val + i * LCOMMUNITY_SIZE,
497 lcom->val + (i + 1) * LCOMMUNITY_SIZE,
498 c * LCOMMUNITY_SIZE);
499
500 lcom->size--;
501
502 if (lcom->size > 0)
503 lcom->val =
996c9314
LB
504 XREALLOC(MTYPE_LCOMMUNITY_VAL,
505 lcom->val, lcom_length(lcom));
d62a17ae 506 else {
600d7ff8 507 XFREE(MTYPE_LCOMMUNITY_VAL, lcom->val);
d62a17ae 508 }
509 return;
510 }
511 i++;
57d187bc 512 }
57d187bc 513}
4c99b6c2
NT
514
515static struct lcommunity *bgp_aggr_lcommunity_lookup(
516 struct bgp_aggregate *aggregate,
517 struct lcommunity *lcommunity)
518{
519 return hash_lookup(aggregate->lcommunity_hash, lcommunity);
520}
521
522static void *bgp_aggr_lcommunty_hash_alloc(void *p)
523{
524 struct lcommunity *ref = (struct lcommunity *)p;
525 struct lcommunity *lcommunity = NULL;
526
527 lcommunity = lcommunity_dup(ref);
528 return lcommunity;
529}
530
7f5818fb 531static void bgp_aggr_lcommunity_prepare(struct hash_bucket *hb, void *arg)
4c99b6c2 532{
4c99b6c2
NT
533 struct lcommunity *hb_lcommunity = hb->data;
534 struct lcommunity **aggr_lcommunity = arg;
535
f1eb1f05 536 if (*aggr_lcommunity)
537 *aggr_lcommunity = lcommunity_merge(*aggr_lcommunity,
538 hb_lcommunity);
539 else
4c99b6c2
NT
540 *aggr_lcommunity = lcommunity_dup(hb_lcommunity);
541}
542
543void bgp_aggr_lcommunity_remove(void *arg)
544{
545 struct lcommunity *lcommunity = arg;
546
547 lcommunity_free(&lcommunity);
548}
549
550void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate,
551 struct lcommunity *lcommunity)
552{
f1eb1f05 553
554 bgp_compute_aggregate_lcommunity_hash(aggregate, lcommunity);
555 bgp_compute_aggregate_lcommunity_val(aggregate);
556}
557
558void bgp_compute_aggregate_lcommunity_hash(struct bgp_aggregate *aggregate,
559 struct lcommunity *lcommunity)
560{
561
4c99b6c2
NT
562 struct lcommunity *aggr_lcommunity = NULL;
563
564 if ((aggregate == NULL) || (lcommunity == NULL))
565 return;
566
567 /* Create hash if not already created.
568 */
569 if (aggregate->lcommunity_hash == NULL)
570 aggregate->lcommunity_hash = hash_create(
571 lcommunity_hash_make, lcommunity_cmp,
572 "BGP Aggregator lcommunity hash");
573
574 aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
575 if (aggr_lcommunity == NULL) {
576 /* Insert lcommunity into hash.
577 */
578 aggr_lcommunity = hash_get(aggregate->lcommunity_hash,
579 lcommunity,
580 bgp_aggr_lcommunty_hash_alloc);
f1eb1f05 581 }
4c99b6c2 582
f1eb1f05 583 /* Increment reference counter.
584 */
585 aggr_lcommunity->refcnt++;
586}
587
588void bgp_compute_aggregate_lcommunity_val(struct bgp_aggregate *aggregate)
589{
590 struct lcommunity *lcommerge = NULL;
591
592 if (aggregate == NULL)
593 return;
4c99b6c2 594
f1eb1f05 595 /* Re-compute aggregate's lcommunity.
596 */
597 if (aggregate->lcommunity)
598 lcommunity_free(&aggregate->lcommunity);
599 if (aggregate->lcommunity_hash &&
600 aggregate->lcommunity_hash->count) {
4c99b6c2
NT
601 hash_iterate(aggregate->lcommunity_hash,
602 bgp_aggr_lcommunity_prepare,
603 &aggregate->lcommunity);
f1eb1f05 604 lcommerge = aggregate->lcommunity;
605 aggregate->lcommunity = lcommunity_uniq_sort(lcommerge);
606 if (lcommerge)
607 lcommunity_free(&lcommerge);
4c99b6c2 608 }
4c99b6c2
NT
609}
610
611void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate,
612 struct lcommunity *lcommunity)
613{
614 struct lcommunity *aggr_lcommunity = NULL;
615 struct lcommunity *ret_lcomm = NULL;
616
f1eb1f05 617 if ((!aggregate)
618 || (!aggregate->lcommunity_hash)
619 || (!lcommunity))
4c99b6c2
NT
620 return;
621
622 /* Look-up the lcommunity in the hash.
623 */
624 aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
625 if (aggr_lcommunity) {
626 aggr_lcommunity->refcnt--;
627
628 if (aggr_lcommunity->refcnt == 0) {
629 ret_lcomm = hash_release(aggregate->lcommunity_hash,
630 aggr_lcommunity);
631 lcommunity_free(&ret_lcomm);
632
f1eb1f05 633 bgp_compute_aggregate_lcommunity_val(aggregate);
634
635 }
636 }
637}
638
639void bgp_remove_lcomm_from_aggregate_hash(struct bgp_aggregate *aggregate,
640 struct lcommunity *lcommunity)
641{
642 struct lcommunity *aggr_lcommunity = NULL;
643 struct lcommunity *ret_lcomm = NULL;
4c99b6c2 644
f1eb1f05 645 if ((!aggregate)
646 || (!aggregate->lcommunity_hash)
647 || (!lcommunity))
648 return;
649
650 /* Look-up the lcommunity in the hash.
651 */
652 aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
653 if (aggr_lcommunity) {
654 aggr_lcommunity->refcnt--;
655
656 if (aggr_lcommunity->refcnt == 0) {
657 ret_lcomm = hash_release(aggregate->lcommunity_hash,
658 aggr_lcommunity);
659 lcommunity_free(&ret_lcomm);
4c99b6c2
NT
660 }
661 }
662}