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