]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_ecommunity.c
bgpd: Install multipath routes with weights
[mirror_frr.git] / bgpd / bgp_ecommunity.c
CommitLineData
718e3744 1/* BGP Extended Communities Attribute
896014f4
DL
2 * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
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
19 */
718e3744 20
21#include <zebra.h>
22
23#include "hash.h"
24#include "memory.h"
25#include "prefix.h"
26#include "command.h"
3f9c7369 27#include "queue.h"
039f3a34 28#include "filter.h"
3f65c5b1 29#include "jhash.h"
937652c6 30#include "stream.h"
718e3744 31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_ecommunity.h"
57d187bc 34#include "bgpd/bgp_lcommunity.h"
0b2aa3a0 35#include "bgpd/bgp_aspath.h"
a8d72b61 36#include "bgpd/bgp_flowspec_private.h"
dacf6ec1 37#include "bgpd/bgp_pbr.h"
a8d72b61
PG
38
39/* struct used to dump the rate contained in FS set traffic-rate EC */
40union traffic_rate {
41 float rate_float;
42 uint8_t rate_byte[4];
43};
718e3744 44
45/* Hash of community attribute. */
ffa4e2c4 46static struct hash *ecomhash;
6b0655a2 47
718e3744 48/* Allocate a new ecommunities. */
d62a17ae 49struct ecommunity *ecommunity_new(void)
718e3744 50{
9f5dc319 51 return XCALLOC(MTYPE_ECOMMUNITY, sizeof(struct ecommunity));
718e3744 52}
53
c7ee6c35
DS
54void ecommunity_strfree(char **s)
55{
56 XFREE(MTYPE_ECOMMUNITY_STR, *s);
57}
58
718e3744 59/* Allocate ecommunities. */
d62a17ae 60void ecommunity_free(struct ecommunity **ecom)
718e3744 61{
0a22ddfb
QY
62 XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
63 XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str);
d62a17ae 64 XFREE(MTYPE_ECOMMUNITY, *ecom);
718e3744 65}
66
d62a17ae 67static void ecommunity_hash_free(struct ecommunity *ecom)
7bae2fb9 68{
d62a17ae 69 ecommunity_free(&ecom);
7bae2fb9
LB
70}
71
72
718e3744 73/* Add a new Extended Communities value to Extended Communities
74 Attribute structure. When the value is already exists in the
75 structure, we don't add the value. Newly added value is sorted by
76 numerical order. When the value is added to the structure return 1
77 else return 0. */
3dc339cd 78bool ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval)
718e3744 79{
d62a17ae 80 int c;
81
91085f97 82 /* When this is fist value, just add it. */
d62a17ae 83 if (ecom->val == NULL) {
91085f97
QY
84 ecom->size = 1;
85 ecom->val = XCALLOC(MTYPE_ECOMMUNITY_VAL, ECOMMUNITY_SIZE);
d62a17ae 86 memcpy(ecom->val, eval->val, ECOMMUNITY_SIZE);
3dc339cd 87 return true;
d62a17ae 88 }
89
90 /* If the value already exists in the structure return 0. */
91 c = 0;
91085f97
QY
92 for (uint8_t *p = ecom->val; c < ecom->size;
93 p += ECOMMUNITY_SIZE, c++) {
94 int ret = memcmp(p, eval->val, ECOMMUNITY_SIZE);
d62a17ae 95 if (ret == 0)
3dc339cd 96 return false;
91085f97 97 else if (ret > 0)
d62a17ae 98 break;
99 }
100
101 /* Add the value to the structure with numerical sorting. */
102 ecom->size++;
91085f97
QY
103 ecom->val = XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom->val,
104 ecom->size * ECOMMUNITY_SIZE);
d62a17ae 105
91085f97
QY
106 memmove(ecom->val + ((c + 1) * ECOMMUNITY_SIZE),
107 ecom->val + (c * ECOMMUNITY_SIZE),
d62a17ae 108 (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
91085f97 109 memcpy(ecom->val + (c * ECOMMUNITY_SIZE), eval->val, ECOMMUNITY_SIZE);
d62a17ae 110
3dc339cd 111 return true;
718e3744 112}
113
114/* This function takes pointer to Extended Communites strucutre then
115 create a new Extended Communities structure by uniq and sort each
e6b6a564 116 Extended Communities value. */
d62a17ae 117struct ecommunity *ecommunity_uniq_sort(struct ecommunity *ecom)
718e3744 118{
d62a17ae 119 int i;
120 struct ecommunity *new;
121 struct ecommunity_val *eval;
122
123 if (!ecom)
124 return NULL;
125
126 new = ecommunity_new();
127
128 for (i = 0; i < ecom->size; i++) {
129 eval = (struct ecommunity_val *)(ecom->val
130 + (i * ECOMMUNITY_SIZE));
131 ecommunity_add_val(new, eval);
132 }
133 return new;
718e3744 134}
135
136/* Parse Extended Communites Attribute in BGP packet. */
d7c0a89a 137struct ecommunity *ecommunity_parse(uint8_t *pnt, unsigned short length)
718e3744 138{
d62a17ae 139 struct ecommunity tmp;
140 struct ecommunity *new;
718e3744 141
d62a17ae 142 /* Length check. */
143 if (length % ECOMMUNITY_SIZE)
144 return NULL;
718e3744 145
d62a17ae 146 /* Prepare tmporary structure for making a new Extended Communities
147 Attribute. */
148 tmp.size = length / ECOMMUNITY_SIZE;
149 tmp.val = pnt;
718e3744 150
d62a17ae 151 /* Create a new Extended Communities Attribute by uniq and sort each
152 Extended Communities value */
153 new = ecommunity_uniq_sort(&tmp);
718e3744 154
d62a17ae 155 return ecommunity_intern(new);
718e3744 156}
157
158/* Duplicate the Extended Communities Attribute structure. */
d62a17ae 159struct ecommunity *ecommunity_dup(struct ecommunity *ecom)
718e3744 160{
d62a17ae 161 struct ecommunity *new;
162
163 new = XCALLOC(MTYPE_ECOMMUNITY, sizeof(struct ecommunity));
164 new->size = ecom->size;
165 if (new->size) {
166 new->val = XMALLOC(MTYPE_ECOMMUNITY_VAL,
167 ecom->size * ECOMMUNITY_SIZE);
168 memcpy(new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
169 } else
170 new->val = NULL;
171 return new;
718e3744 172}
173
4372df71 174/* Retrun string representation of communities attribute. */
d62a17ae 175char *ecommunity_str(struct ecommunity *ecom)
4372df71 176{
d62a17ae 177 if (!ecom->str)
178 ecom->str =
179 ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
180 return ecom->str;
4372df71 181}
182
718e3744 183/* Merge two Extended Communities Attribute structure. */
d62a17ae 184struct ecommunity *ecommunity_merge(struct ecommunity *ecom1,
185 struct ecommunity *ecom2)
718e3744 186{
d62a17ae 187 if (ecom1->val)
188 ecom1->val =
189 XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom1->val,
190 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
191 else
192 ecom1->val =
193 XMALLOC(MTYPE_ECOMMUNITY_VAL,
194 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
195
196 memcpy(ecom1->val + (ecom1->size * ECOMMUNITY_SIZE), ecom2->val,
197 ecom2->size * ECOMMUNITY_SIZE);
198 ecom1->size += ecom2->size;
199
200 return ecom1;
718e3744 201}
202
203/* Intern Extended Communities Attribute. */
d62a17ae 204struct ecommunity *ecommunity_intern(struct ecommunity *ecom)
718e3744 205{
d62a17ae 206 struct ecommunity *find;
718e3744 207
d62a17ae 208 assert(ecom->refcnt == 0);
718e3744 209
d62a17ae 210 find = (struct ecommunity *)hash_get(ecomhash, ecom, hash_alloc_intern);
718e3744 211
d62a17ae 212 if (find != ecom)
213 ecommunity_free(&ecom);
718e3744 214
d62a17ae 215 find->refcnt++;
718e3744 216
d62a17ae 217 if (!find->str)
218 find->str =
219 ecommunity_ecom2str(find, ECOMMUNITY_FORMAT_DISPLAY, 0);
718e3744 220
d62a17ae 221 return find;
718e3744 222}
223
224/* Unintern Extended Communities Attribute. */
d62a17ae 225void ecommunity_unintern(struct ecommunity **ecom)
718e3744 226{
d62a17ae 227 struct ecommunity *ret;
228
229 if ((*ecom)->refcnt)
230 (*ecom)->refcnt--;
231
232 /* Pull off from hash. */
233 if ((*ecom)->refcnt == 0) {
234 /* Extended community must be in the hash. */
235 ret = (struct ecommunity *)hash_release(ecomhash, *ecom);
236 assert(ret != NULL);
237
238 ecommunity_free(ecom);
239 }
718e3744 240}
241
242/* Utinity function to make hash key. */
d8b87afe 243unsigned int ecommunity_hash_make(const void *arg)
718e3744 244{
d62a17ae 245 const struct ecommunity *ecom = arg;
246 int size = ecom->size * ECOMMUNITY_SIZE;
d62a17ae 247
3f65c5b1 248 return jhash(ecom->val, size, 0x564321ab);
718e3744 249}
250
251/* Compare two Extended Communities Attribute structure. */
74df8d6d 252bool ecommunity_cmp(const void *arg1, const void *arg2)
718e3744 253{
d62a17ae 254 const struct ecommunity *ecom1 = arg1;
255 const struct ecommunity *ecom2 = arg2;
256
257 if (ecom1 == NULL && ecom2 == NULL)
74df8d6d 258 return true;
813d4307 259
d62a17ae 260 if (ecom1 == NULL || ecom2 == NULL)
74df8d6d 261 return false;
813d4307 262
d62a17ae 263 return (ecom1->size == ecom2->size
264 && memcmp(ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE)
265 == 0);
718e3744 266}
267
268/* Initialize Extended Comminities related hash. */
d62a17ae 269void ecommunity_init(void)
718e3744 270{
996c9314 271 ecomhash = hash_create(ecommunity_hash_make, ecommunity_cmp,
3f65c5b1 272 "BGP ecommunity hash");
718e3744 273}
228da428 274
d62a17ae 275void ecommunity_finish(void)
228da428 276{
d62a17ae 277 hash_clean(ecomhash, (void (*)(void *))ecommunity_hash_free);
278 hash_free(ecomhash);
279 ecomhash = NULL;
228da428 280}
6b0655a2 281
718e3744 282/* Extended Communities token enum. */
d62a17ae 283enum ecommunity_token {
284 ecommunity_token_unknown = 0,
285 ecommunity_token_rt,
286 ecommunity_token_soo,
287 ecommunity_token_val,
718e3744 288};
289
c5900768 290/*
291 * Encode BGP extended community from passed values. Supports types
292 * defined in RFC 4360 and well-known sub-types.
293 */
d7c0a89a
QY
294static int ecommunity_encode(uint8_t type, uint8_t sub_type, int trans, as_t as,
295 struct in_addr ip, uint32_t val,
d62a17ae 296 struct ecommunity_val *eval)
c5900768 297{
d62a17ae 298 assert(eval);
299 if (type == ECOMMUNITY_ENCODE_AS) {
300 if (as > BGP_AS_MAX)
301 return -1;
302 } else if (type == ECOMMUNITY_ENCODE_IP
303 || type == ECOMMUNITY_ENCODE_AS4) {
304 if (val > UINT16_MAX)
305 return -1;
306 }
307
308 /* Fill in the values. */
309 eval->val[0] = type;
310 if (!trans)
311 eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
312 eval->val[1] = sub_type;
313 if (type == ECOMMUNITY_ENCODE_AS) {
314 eval->val[2] = (as >> 8) & 0xff;
315 eval->val[3] = as & 0xff;
316 eval->val[4] = (val >> 24) & 0xff;
317 eval->val[5] = (val >> 16) & 0xff;
318 eval->val[6] = (val >> 8) & 0xff;
319 eval->val[7] = val & 0xff;
320 } else if (type == ECOMMUNITY_ENCODE_IP) {
321 memcpy(&eval->val[2], &ip, sizeof(struct in_addr));
322 eval->val[6] = (val >> 8) & 0xff;
323 eval->val[7] = val & 0xff;
324 } else {
325 eval->val[2] = (as >> 24) & 0xff;
326 eval->val[3] = (as >> 16) & 0xff;
327 eval->val[4] = (as >> 8) & 0xff;
328 eval->val[5] = as & 0xff;
329 eval->val[6] = (val >> 8) & 0xff;
330 eval->val[7] = val & 0xff;
331 }
332
333 return 0;
c5900768 334}
335
718e3744 336/* Get next Extended Communities token from the string. */
d62a17ae 337static const char *ecommunity_gettoken(const char *str,
338 struct ecommunity_val *eval,
339 enum ecommunity_token *token)
718e3744 340{
d62a17ae 341 int ret;
342 int dot = 0;
343 int digit = 0;
344 int separator = 0;
345 const char *p = str;
346 char *endptr;
347 struct in_addr ip;
348 as_t as = 0;
d7c0a89a
QY
349 uint32_t val = 0;
350 uint8_t ecomm_type;
d62a17ae 351 char buf[INET_ADDRSTRLEN + 1];
352
353 /* Skip white space. */
fefa5e0f 354 while (isspace((unsigned char)*p)) {
d62a17ae 355 p++;
356 str++;
718e3744 357 }
d62a17ae 358
359 /* Check the end of the line. */
360 if (*p == '\0')
361 return NULL;
362
363 /* "rt" and "soo" keyword parse. */
fefa5e0f 364 if (!isdigit((unsigned char)*p)) {
d62a17ae 365 /* "rt" match check. */
fefa5e0f 366 if (tolower((unsigned char)*p) == 'r') {
d62a17ae 367 p++;
fefa5e0f 368 if (tolower((unsigned char)*p) == 't') {
d62a17ae 369 p++;
370 *token = ecommunity_token_rt;
371 return p;
372 }
fefa5e0f 373 if (isspace((unsigned char)*p) || *p == '\0') {
d62a17ae 374 *token = ecommunity_token_rt;
375 return p;
376 }
377 goto error;
718e3744 378 }
d62a17ae 379 /* "soo" match check. */
fefa5e0f 380 else if (tolower((unsigned char)*p) == 's') {
d62a17ae 381 p++;
fefa5e0f 382 if (tolower((unsigned char)*p) == 'o') {
d62a17ae 383 p++;
fefa5e0f 384 if (tolower((unsigned char)*p) == 'o') {
d62a17ae 385 p++;
386 *token = ecommunity_token_soo;
387 return p;
388 }
fefa5e0f 389 if (isspace((unsigned char)*p) || *p == '\0') {
d62a17ae 390 *token = ecommunity_token_soo;
391 return p;
392 }
393 goto error;
394 }
fefa5e0f 395 if (isspace((unsigned char)*p) || *p == '\0') {
d62a17ae 396 *token = ecommunity_token_soo;
397 return p;
398 }
399 goto error;
718e3744 400 }
d62a17ae 401 goto error;
718e3744 402 }
d62a17ae 403
404 /* What a mess, there are several possibilities:
405 *
406 * a) A.B.C.D:MN
407 * b) EF:OPQR
408 * c) GHJK:MN
409 *
410 * A.B.C.D: Four Byte IP
411 * EF: Two byte ASN
412 * GHJK: Four-byte ASN
413 * MN: Two byte value
414 * OPQR: Four byte value
415 *
416 */
fefa5e0f 417 while (isdigit((unsigned char)*p) || *p == ':' || *p == '.') {
d62a17ae 418 if (*p == ':') {
419 if (separator)
420 goto error;
421
422 separator = 1;
423 digit = 0;
424
425 if ((p - str) > INET_ADDRSTRLEN)
426 goto error;
427 memset(buf, 0, INET_ADDRSTRLEN + 1);
428 memcpy(buf, str, p - str);
429
430 if (dot) {
431 /* Parsing A.B.C.D in:
432 * A.B.C.D:MN
433 */
434 ret = inet_aton(buf, &ip);
435 if (ret == 0)
436 goto error;
437 } else {
438 /* ASN */
439 as = strtoul(buf, &endptr, 10);
440 if (*endptr != '\0' || as == BGP_AS4_MAX)
441 goto error;
442 }
443 } else if (*p == '.') {
444 if (separator)
445 goto error;
446 dot++;
447 if (dot > 4)
448 goto error;
449 } else {
450 digit = 1;
451
452 /* We're past the IP/ASN part */
453 if (separator) {
454 val *= 10;
455 val += (*p - '0');
456 }
457 }
458 p++;
718e3744 459 }
d62a17ae 460
461 /* Low digit part must be there. */
462 if (!digit || !separator)
463 goto error;
464
465 /* Encode result into extended community. */
466 if (dot)
467 ecomm_type = ECOMMUNITY_ENCODE_IP;
468 else if (as > BGP_AS_MAX)
469 ecomm_type = ECOMMUNITY_ENCODE_AS4;
470 else
471 ecomm_type = ECOMMUNITY_ENCODE_AS;
472 if (ecommunity_encode(ecomm_type, 0, 1, as, ip, val, eval))
473 goto error;
474 *token = ecommunity_token_val;
475 return p;
476
477error:
478 *token = ecommunity_token_unknown;
479 return p;
718e3744 480}
481
d62a17ae 482/* Convert string to extended community attribute.
718e3744 483
484 When type is already known, please specify both str and type. str
485 should not include keyword such as "rt" and "soo". Type is
486 ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
487 keyword_included should be zero.
488
489 For example route-map's "set extcommunity" command case:
490
491 "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
d62a17ae 492 type = ECOMMUNITY_ROUTE_TARGET
493 keyword_included = 0
718e3744 494
495 "soo 100:1" -> str = "100:1"
d62a17ae 496 type = ECOMMUNITY_SITE_ORIGIN
497 keyword_included = 0
718e3744 498
499 When string includes keyword for each extended community value.
500 Please specify keyword_included as non-zero value.
501
502 For example standard extcommunity-list case:
503
504 "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
d62a17ae 505 type = 0
506 keyword_include = 1
718e3744 507*/
d62a17ae 508struct ecommunity *ecommunity_str2com(const char *str, int type,
509 int keyword_included)
718e3744 510{
d62a17ae 511 struct ecommunity *ecom = NULL;
512 enum ecommunity_token token = ecommunity_token_unknown;
513 struct ecommunity_val eval;
514 int keyword = 0;
515
516 while ((str = ecommunity_gettoken(str, &eval, &token))) {
517 switch (token) {
518 case ecommunity_token_rt:
519 case ecommunity_token_soo:
520 if (!keyword_included || keyword) {
521 if (ecom)
522 ecommunity_free(&ecom);
523 return NULL;
524 }
525 keyword = 1;
526
527 if (token == ecommunity_token_rt) {
528 type = ECOMMUNITY_ROUTE_TARGET;
529 }
530 if (token == ecommunity_token_soo) {
531 type = ECOMMUNITY_SITE_ORIGIN;
532 }
533 break;
534 case ecommunity_token_val:
535 if (keyword_included) {
536 if (!keyword) {
537 if (ecom)
538 ecommunity_free(&ecom);
539 return NULL;
540 }
541 keyword = 0;
542 }
543 if (ecom == NULL)
544 ecom = ecommunity_new();
545 eval.val[1] = type;
546 ecommunity_add_val(ecom, &eval);
547 break;
548 case ecommunity_token_unknown:
549 default:
550 if (ecom)
551 ecommunity_free(&ecom);
552 return NULL;
718e3744 553 }
718e3744 554 }
d62a17ae 555 return ecom;
718e3744 556}
557
1be1693e 558static int ecommunity_rt_soo_str(char *buf, size_t bufsz, const uint8_t *pnt,
91085f97 559 int type, int sub_type, int format)
c5900768 560{
d62a17ae 561 int len = 0;
562 const char *prefix;
563
564 /* For parse Extended Community attribute tupple. */
5a0ccebf
QY
565 struct ecommunity_as eas;
566 struct ecommunity_ip eip;
d62a17ae 567
568
569 /* Determine prefix for string, if any. */
570 switch (format) {
571 case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
572 prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
573 break;
574 case ECOMMUNITY_FORMAT_DISPLAY:
575 prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
576 break;
577 case ECOMMUNITY_FORMAT_ROUTE_MAP:
578 prefix = "";
579 break;
580 default:
581 prefix = "";
582 break;
583 }
584
585 /* Put string into buffer. */
586 if (type == ECOMMUNITY_ENCODE_AS4) {
937652c6 587 pnt = ptr_get_be32(pnt, &eas.as);
d62a17ae 588 eas.val = (*pnt++ << 8);
589 eas.val |= (*pnt++);
590
91085f97 591 len = snprintf(buf, bufsz, "%s%u:%u", prefix, eas.as, eas.val);
d62a17ae 592 } else if (type == ECOMMUNITY_ENCODE_AS) {
593 eas.as = (*pnt++ << 8);
594 eas.as |= (*pnt++);
937652c6 595 pnt = ptr_get_be32(pnt, &eas.val);
d62a17ae 596
91085f97 597 len = snprintf(buf, bufsz, "%s%u:%u", prefix, eas.as, eas.val);
d62a17ae 598 } else if (type == ECOMMUNITY_ENCODE_IP) {
599 memcpy(&eip.ip, pnt, 4);
600 pnt += 4;
601 eip.val = (*pnt++ << 8);
602 eip.val |= (*pnt++);
603
91085f97
QY
604 len = snprintf(buf, bufsz, "%s%s:%u", prefix, inet_ntoa(eip.ip),
605 eip.val);
d62a17ae 606 }
91085f97
QY
607
608 /* consume value */
609 (void)pnt;
d62a17ae 610
611 return len;
c5900768 612}
613
7e3ebfd1 614static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt)
615{
616 int len = 0;
617 as_t as;
618 uint32_t bw;
619 char bps_buf[20] = {0};
620
621#define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8)
622#define ONE_MBPS_BYTES (1000 * 1000 / 8)
623#define ONE_KBPS_BYTES (1000 / 8)
624
625 as = (*pnt++ << 8);
626 as |= (*pnt++);
627 pnt = ptr_get_be32(pnt, &bw);
628 if (bw >= ONE_GBPS_BYTES)
629 sprintf(bps_buf, "%.3f Gbps", (float)(bw/ONE_GBPS_BYTES));
630 else if (bw >= ONE_MBPS_BYTES)
631 sprintf(bps_buf, "%.3f Mbps", (float)(bw/ONE_MBPS_BYTES));
632 else if (bw >= ONE_KBPS_BYTES)
633 sprintf(bps_buf, "%.3f Kbps", (float)(bw/ONE_KBPS_BYTES));
634 else
635 sprintf(bps_buf, "%u bps", bw * 8);
636
637 len = snprintf(buf, bufsz, "LB:%u:%u (%s)", as, bw, bps_buf);
638 return len;
639}
640
d62a17ae 641/* Convert extended community attribute to string.
718e3744 642
643 Due to historical reason of industry standard implementation, there
644 are three types of format.
645
646 route-map set extcommunity format
d62a17ae 647 "rt 100:1 100:2"
648 "soo 100:3"
718e3744 649
650 extcommunity-list
d62a17ae 651 "rt 100:1 rt 100:2 soo 100:3"
718e3744 652
716b2d8a 653 "show [ip] bgp" and extcommunity-list regular expression matching
d62a17ae 654 "RT:100:1 RT:100:2 SoO:100:3"
718e3744 655
656 For each formath please use below definition for format:
657
658 ECOMMUNITY_FORMAT_ROUTE_MAP
659 ECOMMUNITY_FORMAT_COMMUNITY_LIST
660 ECOMMUNITY_FORMAT_DISPLAY
e82202b7 661
d62a17ae 662 Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
e82202b7 663 0 value displays all
718e3744 664*/
d62a17ae 665char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
718e3744 666{
d62a17ae 667 int i;
d7c0a89a 668 uint8_t *pnt;
1ef3c51f
PG
669 uint8_t type = 0;
670 uint8_t sub_type = 0;
91085f97 671#define ECOMMUNITY_STRLEN 64
d62a17ae 672 int str_size;
d62a17ae 673 char *str_buf;
d62a17ae 674
91085f97
QY
675 if (ecom->size == 0)
676 return XCALLOC(MTYPE_ECOMMUNITY_STR, 1);
677
678 /* ecom strlen + space + null term */
679 str_size = (ecom->size * (ECOMMUNITY_STRLEN + 1)) + 1;
680 str_buf = XCALLOC(MTYPE_ECOMMUNITY_STR, str_size);
d62a17ae 681
91085f97 682 char encbuf[128];
d62a17ae 683
684 for (i = 0; i < ecom->size; i++) {
685 int unk_ecom = 0;
91085f97 686 memset(encbuf, 0x00, sizeof(encbuf));
d62a17ae 687
688 /* Space between each value. */
91085f97
QY
689 if (i > 0)
690 strlcat(str_buf, " ", str_size);
d62a17ae 691
91085f97 692 /* Retrieve value field */
d62a17ae 693 pnt = ecom->val + (i * 8);
694
91085f97 695 /* High-order octet is the type */
d62a17ae 696 type = *pnt++;
697
698 if (type == ECOMMUNITY_ENCODE_AS || type == ECOMMUNITY_ENCODE_IP
699 || type == ECOMMUNITY_ENCODE_AS4) {
700 /* Low-order octet of type. */
701 sub_type = *pnt++;
702 if (sub_type != ECOMMUNITY_ROUTE_TARGET
2551b26e
PG
703 && sub_type != ECOMMUNITY_SITE_ORIGIN) {
704 if (sub_type ==
705 ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4 &&
706 type == ECOMMUNITY_ENCODE_IP) {
707 struct in_addr *ipv4 =
708 (struct in_addr *)pnt;
709 char ipv4str[INET_ADDRSTRLEN];
710
711 inet_ntop(AF_INET, ipv4,
712 ipv4str,
713 INET_ADDRSTRLEN);
91085f97
QY
714 snprintf(encbuf, sizeof(encbuf),
715 "NH:%s:%d", ipv4str, pnt[5]);
7e3ebfd1 716 } else if (sub_type ==
717 ECOMMUNITY_LINK_BANDWIDTH &&
718 type == ECOMMUNITY_ENCODE_AS) {
719 ecommunity_lb_str(encbuf,
720 sizeof(encbuf), pnt);
2551b26e
PG
721 } else
722 unk_ecom = 1;
91085f97
QY
723 } else {
724 ecommunity_rt_soo_str(encbuf, sizeof(encbuf),
725 pnt, type, sub_type,
726 format);
727 }
d62a17ae 728 } else if (type == ECOMMUNITY_ENCODE_OPAQUE) {
729 if (filter == ECOMMUNITY_ROUTE_TARGET)
730 continue;
731 if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) {
732 uint16_t tunneltype;
733 memcpy(&tunneltype, pnt + 5, 2);
734 tunneltype = ntohs(tunneltype);
91085f97
QY
735
736 snprintf(encbuf, sizeof(encbuf), "ET:%d",
737 tunneltype);
996c9314 738 } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) {
91085f97
QY
739 strlcpy(encbuf, "Default Gateway",
740 sizeof(encbuf));
741 } else {
d62a17ae 742 unk_ecom = 1;
91085f97 743 }
d62a17ae 744 } else if (type == ECOMMUNITY_ENCODE_EVPN) {
745 if (filter == ECOMMUNITY_ROUTE_TARGET)
746 continue;
bc59a672
MK
747 if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC) {
748 struct ethaddr rmac;
d62a17ae 749 pnt++;
bc59a672 750 memcpy(&rmac, pnt, ETH_ALEN);
91085f97
QY
751
752 snprintf(encbuf, sizeof(encbuf),
753 "Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
754 (uint8_t)rmac.octet[0],
755 (uint8_t)rmac.octet[1],
756 (uint8_t)rmac.octet[2],
757 (uint8_t)rmac.octet[3],
758 (uint8_t)rmac.octet[4],
759 (uint8_t)rmac.octet[5]);
d62a17ae 760 } else if (*pnt
761 == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) {
d7c0a89a
QY
762 uint32_t seqnum;
763 uint8_t flags = *++pnt;
d62a17ae 764
765 memcpy(&seqnum, pnt + 2, 4);
766 seqnum = ntohl(seqnum);
91085f97
QY
767
768 snprintf(encbuf, sizeof(encbuf), "MM:%u",
769 seqnum);
770
771 if (CHECK_FLAG(
772 flags,
773 ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY))
774 strlcat(encbuf, ", sticky MAC",
775 sizeof(encbuf));
5cc359b2
CS
776 } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_ND) {
777 uint8_t flags = *++pnt;
778
91085f97
QY
779 if (CHECK_FLAG(
780 flags,
781 ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG))
782 strlcpy(encbuf, "ND:Router Flag",
783 sizeof(encbuf));
d62a17ae 784 } else
785 unk_ecom = 1;
b72220fc
PG
786 } else if (type == ECOMMUNITY_ENCODE_REDIRECT_IP_NH) {
787 sub_type = *pnt++;
788 if (sub_type == ECOMMUNITY_REDIRECT_IP_NH) {
91085f97
QY
789 snprintf(encbuf, sizeof(encbuf),
790 "FS:redirect IP 0x%x", *(pnt + 5));
b72220fc
PG
791 } else
792 unk_ecom = 1;
1ef3c51f
PG
793 } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP ||
794 type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
795 type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_3) {
a8d72b61 796 sub_type = *pnt++;
1ef3c51f 797 if (sub_type == ECOMMUNITY_REDIRECT_VRF) {
91085f97
QY
798 char buf[16] = {};
799 ecommunity_rt_soo_str(
800 buf, sizeof(buf), (uint8_t *)pnt,
801 type & ~ECOMMUNITY_ENCODE_TRANS_EXP,
802 ECOMMUNITY_ROUTE_TARGET,
803 ECOMMUNITY_FORMAT_DISPLAY);
804 snprintf(encbuf, sizeof(encbuf),
805 "FS:redirect VRF %s", buf);
1ef3c51f
PG
806 } else if (type != ECOMMUNITY_ENCODE_TRANS_EXP)
807 unk_ecom = 1;
808 else if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) {
a8d72b61 809 char action[64];
a8d72b61
PG
810
811 if (*(pnt+3) ==
812 1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL)
91085f97
QY
813 strlcpy(action, "terminate (apply)",
814 sizeof(action));
a8d72b61 815 else
91085f97
QY
816 strlcpy(action, "eval stops",
817 sizeof(action));
818
a8d72b61
PG
819 if (*(pnt+3) ==
820 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE)
91085f97
QY
821 strlcat(action, ", sample",
822 sizeof(action));
823
824
825 snprintf(encbuf, sizeof(encbuf), "FS:action %s",
826 action);
a8d72b61
PG
827 } else if (sub_type == ECOMMUNITY_TRAFFIC_RATE) {
828 union traffic_rate data;
829
830 data.rate_byte[3] = *(pnt+2);
831 data.rate_byte[2] = *(pnt+3);
832 data.rate_byte[1] = *(pnt+4);
833 data.rate_byte[0] = *(pnt+5);
91085f97
QY
834 snprintf(encbuf, sizeof(encbuf), "FS:rate %f",
835 data.rate_float);
a8d72b61 836 } else if (sub_type == ECOMMUNITY_TRAFFIC_MARKING) {
91085f97
QY
837 snprintf(encbuf, sizeof(encbuf),
838 "FS:marking %u", *(pnt + 5));
50f74cf1 839 } else if (*pnt
840 == ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT) {
841 struct ethaddr mac;
2bb9eff4 842
50f74cf1 843 memcpy(&mac, pnt, ETH_ALEN);
91085f97
QY
844
845 snprintf(
846 encbuf, sizeof(encbuf),
50f74cf1 847 "ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x",
848 (uint8_t)mac.octet[0],
849 (uint8_t)mac.octet[1],
850 (uint8_t)mac.octet[2],
851 (uint8_t)mac.octet[3],
852 (uint8_t)mac.octet[4],
853 (uint8_t)mac.octet[5]);
a8d72b61
PG
854 } else
855 unk_ecom = 1;
7e3ebfd1 856 } else if (type == ECOMMUNITY_ENCODE_AS_NON_TRANS) {
857 sub_type = *pnt++;
858 if (sub_type == ECOMMUNITY_LINK_BANDWIDTH)
859 ecommunity_lb_str(encbuf, sizeof(encbuf), pnt);
860 else
861 unk_ecom = 1;
1ef3c51f
PG
862 } else {
863 sub_type = *pnt++;
d62a17ae 864 unk_ecom = 1;
1ef3c51f 865 }
d62a17ae 866
867 if (unk_ecom)
91085f97
QY
868 snprintf(encbuf, sizeof(encbuf), "UNK:%d, %d", type,
869 sub_type);
d62a17ae 870
91085f97
QY
871 int r = strlcat(str_buf, encbuf, str_size);
872 assert(r < str_size);
94431dbc
C
873 }
874
d62a17ae 875 return str_buf;
718e3744 876}
4372df71 877
3dc339cd
DA
878bool ecommunity_match(const struct ecommunity *ecom1,
879 const struct ecommunity *ecom2)
4372df71 880{
d62a17ae 881 int i = 0;
882 int j = 0;
883
884 if (ecom1 == NULL && ecom2 == NULL)
3dc339cd 885 return true;
d62a17ae 886
887 if (ecom1 == NULL || ecom2 == NULL)
3dc339cd 888 return false;
d62a17ae 889
890 if (ecom1->size < ecom2->size)
3dc339cd 891 return false;
d62a17ae 892
893 /* Every community on com2 needs to be on com1 for this to match */
894 while (i < ecom1->size && j < ecom2->size) {
895 if (memcmp(ecom1->val + i * ECOMMUNITY_SIZE,
896 ecom2->val + j * ECOMMUNITY_SIZE, ECOMMUNITY_SIZE)
897 == 0)
898 j++;
899 i++;
900 }
901
902 if (j == ecom2->size)
3dc339cd 903 return true;
d62a17ae 904 else
3dc339cd 905 return false;
4372df71 906}
1e27ef50
PG
907
908/* return first occurence of type */
d62a17ae 909extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom,
910 uint8_t type, uint8_t subtype)
1e27ef50 911{
d7c0a89a 912 uint8_t *p;
d62a17ae 913 int c;
914
915 /* If the value already exists in the structure return 0. */
916 c = 0;
917 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
918 if (p == NULL) {
919 continue;
920 }
921 if (p[0] == type && p[1] == subtype)
922 return (struct ecommunity_val *)p;
923 }
924 return NULL;
1e27ef50
PG
925}
926
927/* remove ext. community matching type and subtype
928 * return 1 on success ( removed ), 0 otherwise (not present)
929 */
3dc339cd
DA
930extern bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
931 uint8_t subtype)
1e27ef50 932{
003bc275 933 uint8_t *p, *q, *new;
d62a17ae 934 int c, found = 0;
935 /* When this is fist value, just add it. */
3dc339cd
DA
936 if (ecom == NULL || ecom->val == NULL)
937 return false;
d62a17ae 938
003bc275 939 /* Check if any existing ext community matches. */
940 /* Certain extended communities like the Route Target can be present
941 * multiple times, handle that.
942 */
d62a17ae 943 c = 0;
944 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
003bc275 945 if (p[0] == type && p[1] == subtype)
946 found++;
d62a17ae 947 }
003bc275 948 /* If no matching ext community exists, return. */
d62a17ae 949 if (found == 0)
3dc339cd 950 return false;
003bc275 951
952 /* Handle the case where everything needs to be stripped. */
953 if (found == ecom->size) {
954 XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
955 ecom->size = 0;
3dc339cd 956 return true;
003bc275 957 }
958
959 /* Strip matching ext community(ies). */
960 new = XMALLOC(MTYPE_ECOMMUNITY_VAL,
961 (ecom->size - found) * ECOMMUNITY_SIZE);
962 q = new;
963 for (c = 0, p = ecom->val; c < ecom->size; c++, p += ECOMMUNITY_SIZE) {
964 if (!(p[0] == type && p[1] == subtype)) {
965 memcpy(q, p, ECOMMUNITY_SIZE);
966 q += ECOMMUNITY_SIZE;
967 }
968 }
969 XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
970 ecom->val = new;
971 ecom->size -= found;
3dc339cd 972 return true;
1e27ef50 973}
44338987 974
975/*
976 * Remove specified extended community value from extended community.
977 * Returns 1 if value was present (and hence, removed), 0 otherwise.
978 */
3dc339cd 979bool ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval)
44338987 980{
f27f864e 981 uint8_t *p;
44338987 982 int c, found = 0;
983
984 /* Make sure specified value exists. */
985 if (ecom == NULL || ecom->val == NULL)
3dc339cd 986 return false;
44338987 987 c = 0;
988 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
989 if (!memcmp(p, eval->val, ECOMMUNITY_SIZE)) {
990 found = 1;
991 break;
992 }
993 }
994 if (found == 0)
3dc339cd 995 return false;
44338987 996
997 /* Delete the selected value */
998 ecom->size--;
999 p = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
1000 if (c != 0)
1001 memcpy(p, ecom->val, c * ECOMMUNITY_SIZE);
1002 if ((ecom->size - c) != 0)
1003 memcpy(p + (c)*ECOMMUNITY_SIZE,
1004 ecom->val + (c + 1) * ECOMMUNITY_SIZE,
1005 (ecom->size - c) * ECOMMUNITY_SIZE);
e6a6870b 1006 XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
44338987 1007 ecom->val = p;
3dc339cd 1008 return true;
44338987 1009}
dacf6ec1
PG
1010
1011int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
1012 struct bgp_pbr_entry_action *api)
1013{
1014 if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_RATE) {
1015 api->action = ACTION_TRAFFICRATE;
1016 api->u.r.rate_info[3] = ecom_eval->val[4];
1017 api->u.r.rate_info[2] = ecom_eval->val[5];
1018 api->u.r.rate_info[1] = ecom_eval->val[6];
1019 api->u.r.rate_info[0] = ecom_eval->val[7];
1020 } else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_ACTION) {
1021 api->action = ACTION_TRAFFIC_ACTION;
1022 /* else distribute code is set by default */
1023 if (ecom_eval->val[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL))
1024 api->u.za.filter |= TRAFFIC_ACTION_TERMINATE;
1025 else
1026 api->u.za.filter |= TRAFFIC_ACTION_DISTRIBUTE;
1027 if (ecom_eval->val[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE)
1028 api->u.za.filter |= TRAFFIC_ACTION_SAMPLE;
1029
1030 } else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_MARKING) {
1031 api->action = ACTION_MARKING;
1032 api->u.marking_dscp = ecom_eval->val[7];
1033 } else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_VRF) {
1034 /* must use external function */
1035 return 0;
1036 } else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_IP_NH) {
1037 /* see draft-ietf-idr-flowspec-redirect-ip-02
1038 * Q1: how come a ext. community can host ipv6 address
1039 * Q2 : from cisco documentation:
1040 * Announces the reachability of one or more flowspec NLRI.
1041 * When a BGP speaker receives an UPDATE message with the
1042 * redirect-to-IP extended community, it is expected to
1043 * create a traffic filtering rule for every flow-spec
1044 * NLRI in the message that has this path as its best
1045 * path. The filter entry matches the IP packets
1046 * described in the NLRI field and redirects them or
1047 * copies them towards the IPv4 or IPv6 address specified
1048 * in the 'Network Address of Next- Hop'
1049 * field of the associated MP_REACH_NLRI.
1050 */
1051 struct ecommunity_ip *ip_ecom = (struct ecommunity_ip *)
1052 ecom_eval + 2;
1053
1054 api->u.zr.redirect_ip_v4 = ip_ecom->ip;
1055 } else
1056 return -1;
1057 return 0;
1058}
5b820d9e
NT
1059
1060static struct ecommunity *bgp_aggr_ecommunity_lookup(
1061 struct bgp_aggregate *aggregate,
1062 struct ecommunity *ecommunity)
1063{
1064 return hash_lookup(aggregate->ecommunity_hash, ecommunity);
1065}
1066
1067static void *bgp_aggr_ecommunty_hash_alloc(void *p)
1068{
1069 struct ecommunity *ref = (struct ecommunity *)p;
1070 struct ecommunity *ecommunity = NULL;
1071
1072 ecommunity = ecommunity_dup(ref);
1073 return ecommunity;
1074}
1075
7f5818fb 1076static void bgp_aggr_ecommunity_prepare(struct hash_bucket *hb, void *arg)
5b820d9e 1077{
5b820d9e
NT
1078 struct ecommunity *hb_ecommunity = hb->data;
1079 struct ecommunity **aggr_ecommunity = arg;
1080
4edd83f9 1081 if (*aggr_ecommunity)
1082 *aggr_ecommunity = ecommunity_merge(*aggr_ecommunity,
1083 hb_ecommunity);
1084 else
5b820d9e
NT
1085 *aggr_ecommunity = ecommunity_dup(hb_ecommunity);
1086}
1087
1088void bgp_aggr_ecommunity_remove(void *arg)
1089{
1090 struct ecommunity *ecommunity = arg;
1091
1092 ecommunity_free(&ecommunity);
1093}
1094
1095void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate,
1096 struct ecommunity *ecommunity)
4edd83f9 1097{
1098 bgp_compute_aggregate_ecommunity_hash(aggregate, ecommunity);
1099 bgp_compute_aggregate_ecommunity_val(aggregate);
1100}
1101
1102
1103void bgp_compute_aggregate_ecommunity_hash(struct bgp_aggregate *aggregate,
1104 struct ecommunity *ecommunity)
5b820d9e
NT
1105{
1106 struct ecommunity *aggr_ecommunity = NULL;
1107
1108 if ((aggregate == NULL) || (ecommunity == NULL))
1109 return;
1110
1111 /* Create hash if not already created.
1112 */
1113 if (aggregate->ecommunity_hash == NULL)
1114 aggregate->ecommunity_hash = hash_create(
1115 ecommunity_hash_make, ecommunity_cmp,
1116 "BGP Aggregator ecommunity hash");
1117
1118 aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity);
1119 if (aggr_ecommunity == NULL) {
1120 /* Insert ecommunity into hash.
1121 */
1122 aggr_ecommunity = hash_get(aggregate->ecommunity_hash,
1123 ecommunity,
1124 bgp_aggr_ecommunty_hash_alloc);
4edd83f9 1125 }
5b820d9e 1126
4edd83f9 1127 /* Increment reference counter.
1128 */
1129 aggr_ecommunity->refcnt++;
1130}
5b820d9e 1131
4edd83f9 1132void bgp_compute_aggregate_ecommunity_val(struct bgp_aggregate *aggregate)
1133{
1134 struct ecommunity *ecommerge = NULL;
1135
1136 if (aggregate == NULL)
1137 return;
1138
1139 /* Re-compute aggregate's ecommunity.
1140 */
1141 if (aggregate->ecommunity)
1142 ecommunity_free(&aggregate->ecommunity);
1143 if (aggregate->ecommunity_hash
1144 && aggregate->ecommunity_hash->count) {
5b820d9e
NT
1145 hash_iterate(aggregate->ecommunity_hash,
1146 bgp_aggr_ecommunity_prepare,
1147 &aggregate->ecommunity);
4edd83f9 1148 ecommerge = aggregate->ecommunity;
1149 aggregate->ecommunity = ecommunity_uniq_sort(ecommerge);
1150 if (ecommerge)
1151 ecommunity_free(&ecommerge);
5b820d9e 1152 }
5b820d9e
NT
1153}
1154
1155void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate,
1156 struct ecommunity *ecommunity)
1157{
1158 struct ecommunity *aggr_ecommunity = NULL;
1159 struct ecommunity *ret_ecomm = NULL;
1160
4edd83f9 1161 if ((!aggregate)
1162 || (!aggregate->ecommunity_hash)
1163 || (!ecommunity))
5b820d9e
NT
1164 return;
1165
1166 /* Look-up the ecommunity in the hash.
1167 */
1168 aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity);
1169 if (aggr_ecommunity) {
1170 aggr_ecommunity->refcnt--;
1171
1172 if (aggr_ecommunity->refcnt == 0) {
1173 ret_ecomm = hash_release(aggregate->ecommunity_hash,
1174 aggr_ecommunity);
1175 ecommunity_free(&ret_ecomm);
4edd83f9 1176 bgp_compute_aggregate_ecommunity_val(aggregate);
1177 }
1178 }
1179}
1180
1181void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate *aggregate,
1182 struct ecommunity *ecommunity)
1183{
1184
1185 struct ecommunity *aggr_ecommunity = NULL;
1186 struct ecommunity *ret_ecomm = NULL;
5b820d9e 1187
4edd83f9 1188 if ((!aggregate)
1189 || (!aggregate->ecommunity_hash)
1190 || (!ecommunity))
1191 return;
5b820d9e 1192
4edd83f9 1193 /* Look-up the ecommunity in the hash.
1194 */
1195 aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity);
1196 if (aggr_ecommunity) {
1197 aggr_ecommunity->refcnt--;
1198
1199 if (aggr_ecommunity->refcnt == 0) {
1200 ret_ecomm = hash_release(aggregate->ecommunity_hash,
1201 aggr_ecommunity);
1202 ecommunity_free(&ret_ecomm);
5b820d9e
NT
1203 }
1204 }
1205}
d901dc13 1206
1207/*
1208 * return the BGP link bandwidth extended community, if present;
1209 * the actual bandwidth is returned via param
1210 */
1211const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
1212{
1213 const uint8_t *eval;
1214 int i;
1215
1216 if (bw)
1217 *bw = 0;
1218
1219 if (!ecom || !ecom->size)
1220 return NULL;
1221
1222 for (i = 0; i < ecom->size; i++) {
1223 const uint8_t *pnt;
1224 uint8_t type, sub_type;
1225 uint32_t bwval;
1226
1227 eval = pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
1228 type = *pnt++;
1229 sub_type = *pnt++;
1230
1231 if ((type == ECOMMUNITY_ENCODE_AS ||
1232 type == ECOMMUNITY_ENCODE_AS_NON_TRANS) &&
1233 sub_type == ECOMMUNITY_LINK_BANDWIDTH) {
1234 pnt += 2; /* bandwidth is encoded as AS:val */
1235 pnt = ptr_get_be32(pnt, &bwval);
1236 (void)pnt; /* consume value */
1237 if (bw)
1238 *bw = bwval;
1239 return eval;
1240 }
1241 }
1242
1243 return NULL;
1244}