]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_lcommunity.c
Merge pull request #8063 from ton31337/fix/typo_enum_bestpath
[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
c850908b
WC
351/* Get next Large Communities token from the string.
352 * Assumes str is space-delimeted and describes 0 or more
353 * valid large communities
354 */
d62a17ae 355static const char *lcommunity_gettoken(const char *str,
c850908b 356 struct lcommunity_val *lval)
57d187bc 357{
d62a17ae 358 const char *p = str;
359
360 /* Skip white space. */
fefa5e0f 361 while (isspace((unsigned char)*p)) {
d62a17ae 362 p++;
363 str++;
364 }
365
366 /* Check the end of the line. */
367 if (*p == '\0')
368 return NULL;
369
370 /* Community value. */
c850908b
WC
371 int separator = 0;
372 int digit = 0;
373 uint32_t globaladmin = 0;
374 uint32_t localdata1 = 0;
375 uint32_t localdata2 = 0;
376
377 while (*p && *p != ' ') {
378 /* large community valid chars */
379 assert(isdigit((unsigned char)*p) || *p == ':');
380
381 if (*p == ':') {
382 separator++;
383 digit = 0;
384 if (separator == 1) {
385 globaladmin = localdata2;
d62a17ae 386 } else {
c850908b 387 localdata1 = localdata2;
d62a17ae 388 }
c850908b
WC
389 localdata2 = 0;
390 } else {
391 digit = 1;
392 /* left shift the accumulated value and add current
393 * digit
394 */
395 localdata2 *= 10;
396 localdata2 += (*p - '0');
57d187bc 397 }
c850908b 398 p++;
d62a17ae 399 }
c850908b
WC
400
401 /* Assert str was a valid large community */
402 assert(separator == 2 && digit == 1);
403
404 /*
405 * Copy the large comm.
406 */
407 lval->val[0] = (globaladmin >> 24) & 0xff;
408 lval->val[1] = (globaladmin >> 16) & 0xff;
409 lval->val[2] = (globaladmin >> 8) & 0xff;
410 lval->val[3] = globaladmin & 0xff;
411 lval->val[4] = (localdata1 >> 24) & 0xff;
412 lval->val[5] = (localdata1 >> 16) & 0xff;
413 lval->val[6] = (localdata1 >> 8) & 0xff;
414 lval->val[7] = localdata1 & 0xff;
415 lval->val[8] = (localdata2 >> 24) & 0xff;
416 lval->val[9] = (localdata2 >> 16) & 0xff;
417 lval->val[10] = (localdata2 >> 8) & 0xff;
418 lval->val[11] = localdata2 & 0xff;
419
d62a17ae 420 return p;
57d187bc
JS
421}
422
423/*
424 Convert string to large community attribute.
425 When type is already known, please specify both str and type.
426
427 When string includes keyword for each large community value.
428 Please specify keyword_included as non-zero value.
429*/
d62a17ae 430struct lcommunity *lcommunity_str2com(const char *str)
57d187bc 431{
d62a17ae 432 struct lcommunity *lcom = NULL;
d62a17ae 433 struct lcommunity_val lval;
434
c850908b
WC
435 if (!lcommunity_list_valid(str, LARGE_COMMUNITY_LIST_STANDARD))
436 return NULL;
437
6aee3848 438 do {
c850908b
WC
439 str = lcommunity_gettoken(str, &lval);
440 if (lcom == NULL)
441 lcom = lcommunity_new();
442 lcommunity_add_val(lcom, &lval);
6aee3848
NT
443 } while (str);
444
d62a17ae 445 return lcom;
57d187bc
JS
446}
447
3dc339cd 448bool lcommunity_include(struct lcommunity *lcom, uint8_t *ptr)
57d187bc 449{
d62a17ae 450 int i;
d7c0a89a 451 uint8_t *lcom_ptr;
d62a17ae 452
d62a17ae 453 for (i = 0; i < lcom->size; i++) {
3ac053e6 454 lcom_ptr = lcom->val + (i * LCOMMUNITY_SIZE);
d62a17ae 455 if (memcmp(ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0)
3dc339cd 456 return true;
d62a17ae 457 }
3dc339cd 458 return false;
57d187bc
JS
459}
460
3dc339cd
DA
461bool lcommunity_match(const struct lcommunity *lcom1,
462 const struct lcommunity *lcom2)
57d187bc 463{
d62a17ae 464 int i = 0;
465 int j = 0;
466
467 if (lcom1 == NULL && lcom2 == NULL)
3dc339cd 468 return true;
d62a17ae 469
470 if (lcom1 == NULL || lcom2 == NULL)
3dc339cd 471 return false;
d62a17ae 472
473 if (lcom1->size < lcom2->size)
3dc339cd 474 return false;
d62a17ae 475
476 /* Every community on com2 needs to be on com1 for this to match */
477 while (i < lcom1->size && j < lcom2->size) {
996c9314
LB
478 if (memcmp(lcom1->val + (i * LCOMMUNITY_SIZE),
479 lcom2->val + (j * LCOMMUNITY_SIZE), LCOMMUNITY_SIZE)
d62a17ae 480 == 0)
481 j++;
482 i++;
483 }
484
485 if (j == lcom2->size)
3dc339cd 486 return true;
d62a17ae 487 else
3dc339cd 488 return false;
57d187bc
JS
489}
490
491/* Delete one lcommunity. */
d7c0a89a 492void lcommunity_del_val(struct lcommunity *lcom, uint8_t *ptr)
57d187bc 493{
d62a17ae 494 int i = 0;
495 int c = 0;
496
497 if (!lcom->val)
498 return;
499
500 while (i < lcom->size) {
501 if (memcmp(lcom->val + i * LCOMMUNITY_SIZE, ptr,
502 LCOMMUNITY_SIZE)
503 == 0) {
504 c = lcom->size - i - 1;
505
506 if (c > 0)
507 memmove(lcom->val + i * LCOMMUNITY_SIZE,
508 lcom->val + (i + 1) * LCOMMUNITY_SIZE,
509 c * LCOMMUNITY_SIZE);
510
511 lcom->size--;
512
513 if (lcom->size > 0)
514 lcom->val =
996c9314
LB
515 XREALLOC(MTYPE_LCOMMUNITY_VAL,
516 lcom->val, lcom_length(lcom));
d62a17ae 517 else {
600d7ff8 518 XFREE(MTYPE_LCOMMUNITY_VAL, lcom->val);
d62a17ae 519 }
520 return;
521 }
522 i++;
57d187bc 523 }
57d187bc 524}
4c99b6c2
NT
525
526static struct lcommunity *bgp_aggr_lcommunity_lookup(
527 struct bgp_aggregate *aggregate,
528 struct lcommunity *lcommunity)
529{
530 return hash_lookup(aggregate->lcommunity_hash, lcommunity);
531}
532
533static void *bgp_aggr_lcommunty_hash_alloc(void *p)
534{
535 struct lcommunity *ref = (struct lcommunity *)p;
536 struct lcommunity *lcommunity = NULL;
537
538 lcommunity = lcommunity_dup(ref);
539 return lcommunity;
540}
541
7f5818fb 542static void bgp_aggr_lcommunity_prepare(struct hash_bucket *hb, void *arg)
4c99b6c2 543{
4c99b6c2
NT
544 struct lcommunity *hb_lcommunity = hb->data;
545 struct lcommunity **aggr_lcommunity = arg;
546
f1eb1f05 547 if (*aggr_lcommunity)
548 *aggr_lcommunity = lcommunity_merge(*aggr_lcommunity,
549 hb_lcommunity);
550 else
4c99b6c2
NT
551 *aggr_lcommunity = lcommunity_dup(hb_lcommunity);
552}
553
554void bgp_aggr_lcommunity_remove(void *arg)
555{
556 struct lcommunity *lcommunity = arg;
557
558 lcommunity_free(&lcommunity);
559}
560
561void bgp_compute_aggregate_lcommunity(struct bgp_aggregate *aggregate,
562 struct lcommunity *lcommunity)
563{
f1eb1f05 564
565 bgp_compute_aggregate_lcommunity_hash(aggregate, lcommunity);
566 bgp_compute_aggregate_lcommunity_val(aggregate);
567}
568
569void bgp_compute_aggregate_lcommunity_hash(struct bgp_aggregate *aggregate,
570 struct lcommunity *lcommunity)
571{
572
4c99b6c2
NT
573 struct lcommunity *aggr_lcommunity = NULL;
574
575 if ((aggregate == NULL) || (lcommunity == NULL))
576 return;
577
578 /* Create hash if not already created.
579 */
580 if (aggregate->lcommunity_hash == NULL)
581 aggregate->lcommunity_hash = hash_create(
582 lcommunity_hash_make, lcommunity_cmp,
583 "BGP Aggregator lcommunity hash");
584
585 aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
586 if (aggr_lcommunity == NULL) {
587 /* Insert lcommunity into hash.
588 */
589 aggr_lcommunity = hash_get(aggregate->lcommunity_hash,
590 lcommunity,
591 bgp_aggr_lcommunty_hash_alloc);
f1eb1f05 592 }
4c99b6c2 593
f1eb1f05 594 /* Increment reference counter.
595 */
596 aggr_lcommunity->refcnt++;
597}
598
599void bgp_compute_aggregate_lcommunity_val(struct bgp_aggregate *aggregate)
600{
601 struct lcommunity *lcommerge = NULL;
602
603 if (aggregate == NULL)
604 return;
4c99b6c2 605
f1eb1f05 606 /* Re-compute aggregate's lcommunity.
607 */
608 if (aggregate->lcommunity)
609 lcommunity_free(&aggregate->lcommunity);
610 if (aggregate->lcommunity_hash &&
611 aggregate->lcommunity_hash->count) {
4c99b6c2
NT
612 hash_iterate(aggregate->lcommunity_hash,
613 bgp_aggr_lcommunity_prepare,
614 &aggregate->lcommunity);
f1eb1f05 615 lcommerge = aggregate->lcommunity;
616 aggregate->lcommunity = lcommunity_uniq_sort(lcommerge);
617 if (lcommerge)
618 lcommunity_free(&lcommerge);
4c99b6c2 619 }
4c99b6c2
NT
620}
621
622void bgp_remove_lcommunity_from_aggregate(struct bgp_aggregate *aggregate,
623 struct lcommunity *lcommunity)
624{
625 struct lcommunity *aggr_lcommunity = NULL;
626 struct lcommunity *ret_lcomm = NULL;
627
f1eb1f05 628 if ((!aggregate)
629 || (!aggregate->lcommunity_hash)
630 || (!lcommunity))
4c99b6c2
NT
631 return;
632
633 /* Look-up the lcommunity in the hash.
634 */
635 aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
636 if (aggr_lcommunity) {
637 aggr_lcommunity->refcnt--;
638
639 if (aggr_lcommunity->refcnt == 0) {
640 ret_lcomm = hash_release(aggregate->lcommunity_hash,
641 aggr_lcommunity);
642 lcommunity_free(&ret_lcomm);
643
f1eb1f05 644 bgp_compute_aggregate_lcommunity_val(aggregate);
645
646 }
647 }
648}
649
650void bgp_remove_lcomm_from_aggregate_hash(struct bgp_aggregate *aggregate,
651 struct lcommunity *lcommunity)
652{
653 struct lcommunity *aggr_lcommunity = NULL;
654 struct lcommunity *ret_lcomm = NULL;
4c99b6c2 655
f1eb1f05 656 if ((!aggregate)
657 || (!aggregate->lcommunity_hash)
658 || (!lcommunity))
659 return;
660
661 /* Look-up the lcommunity in the hash.
662 */
663 aggr_lcommunity = bgp_aggr_lcommunity_lookup(aggregate, lcommunity);
664 if (aggr_lcommunity) {
665 aggr_lcommunity->refcnt--;
666
667 if (aggr_lcommunity->refcnt == 0) {
668 ret_lcomm = hash_release(aggregate->lcommunity_hash,
669 aggr_lcommunity);
670 lcommunity_free(&ret_lcomm);
4c99b6c2
NT
671 }
672 }
673}