1 /* BGP Extended Communities Attribute
2 * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
4 * This file is part of GNU Zebra.
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
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.
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
32 #include "lib/printfrr.h"
34 #include "bgpd/bgpd.h"
35 #include "bgpd/bgp_ecommunity.h"
36 #include "bgpd/bgp_lcommunity.h"
37 #include "bgpd/bgp_aspath.h"
38 #include "bgpd/bgp_flowspec_private.h"
39 #include "bgpd/bgp_pbr.h"
41 /* struct used to dump the rate contained in FS set traffic-rate EC */
47 /* Hash of community attribute. */
48 static struct hash
*ecomhash
;
50 /* Allocate a new ecommunities. */
51 struct ecommunity
*ecommunity_new(void)
53 struct ecommunity
*ecom
;
55 ecom
= (struct ecommunity
*)XCALLOC(MTYPE_ECOMMUNITY
,
56 sizeof(struct ecommunity
));
57 ecom
->unit_size
= ECOMMUNITY_SIZE
;
61 void ecommunity_strfree(char **s
)
63 XFREE(MTYPE_ECOMMUNITY_STR
, *s
);
66 /* Free ecommunities. */
67 void ecommunity_free(struct ecommunity
**ecom
)
72 XFREE(MTYPE_ECOMMUNITY_VAL
, (*ecom
)->val
);
73 XFREE(MTYPE_ECOMMUNITY_STR
, (*ecom
)->str
);
74 XFREE(MTYPE_ECOMMUNITY
, *ecom
);
77 static void ecommunity_hash_free(struct ecommunity
*ecom
)
79 ecommunity_free(&ecom
);
83 /* Add a new Extended Communities value to Extended Communities
84 Attribute structure. When the value is already exists in the
85 structure, we don't add the value. Newly added value is sorted by
86 numerical order. When the value is added to the structure return 1
88 The additional parameters 'unique' and 'overwrite' ensure a particular
89 extended community (based on type and sub-type) is present only
90 once and whether the new value should replace what is existing or
93 static bool ecommunity_add_val_internal(struct ecommunity
*ecom
,
95 bool unique
, bool overwrite
,
99 const struct ecommunity_val
*eval4
= (struct ecommunity_val
*)eval
;
100 const struct ecommunity_val_ipv6
*eval6
=
101 (struct ecommunity_val_ipv6
*)eval
;
103 /* When this is fist value, just add it. */
104 if (ecom
->val
== NULL
) {
106 ecom
->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
,
107 ecom_length_size(ecom
, ecom_size
));
108 memcpy(ecom
->val
, eval
, ecom_size
);
112 /* If the value already exists in the structure return 0. */
113 /* check also if the extended community itself exists. */
116 ins_idx
= UINT32_MAX
;
117 for (uint8_t *p
= ecom
->val
; c
< ecom
->size
;
118 p
+= ecom_size
, c
++) {
120 if (ecom_size
== ECOMMUNITY_SIZE
) {
121 if (p
[0] == eval4
->val
[0] &&
122 p
[1] == eval4
->val
[1]) {
124 memcpy(p
, eval4
->val
,
131 if (p
[0] == eval6
->val
[0] &&
132 p
[1] == eval6
->val
[1]) {
134 memcpy(p
, eval6
->val
,
142 int ret
= memcmp(p
, eval
, ecom_size
);
148 if (ins_idx
== UINT32_MAX
)
153 if (ins_idx
== UINT32_MAX
)
156 /* Add the value to the structure with numerical sorting. */
158 ecom
->val
= XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->val
,
159 ecom_length_size(ecom
, ecom_size
));
161 memmove(ecom
->val
+ ((ins_idx
+ 1) * ecom_size
),
162 ecom
->val
+ (ins_idx
* ecom_size
),
163 (ecom
->size
- 1 - ins_idx
) * ecom_size
);
164 memcpy(ecom
->val
+ (ins_idx
* ecom_size
),
170 /* Add a new Extended Communities value to Extended Communities
171 * Attribute structure. When the value is already exists in the
172 * structure, we don't add the value. Newly added value is sorted by
173 * numerical order. When the value is added to the structure return 1
176 bool ecommunity_add_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
,
177 bool unique
, bool overwrite
)
179 return ecommunity_add_val_internal(ecom
, (const void *)eval
, unique
,
180 overwrite
, ECOMMUNITY_SIZE
);
183 bool ecommunity_add_val_ipv6(struct ecommunity
*ecom
,
184 struct ecommunity_val_ipv6
*eval
,
185 bool unique
, bool overwrite
)
187 return ecommunity_add_val_internal(ecom
, (const void *)eval
, unique
,
188 overwrite
, IPV6_ECOMMUNITY_SIZE
);
191 static struct ecommunity
*
192 ecommunity_uniq_sort_internal(struct ecommunity
*ecom
,
193 unsigned short ecom_size
)
196 struct ecommunity
*new;
202 new = ecommunity_new();
203 new->unit_size
= ecom_size
;
204 new->disable_ieee_floating
= ecom
->disable_ieee_floating
;
206 for (i
= 0; i
< ecom
->size
; i
++) {
207 eval
= (void *)(ecom
->val
+ (i
* ecom_size
));
208 ecommunity_add_val_internal(new, eval
, false, false, ecom_size
);
213 /* This function takes pointer to Extended Communites structure then
214 * create a new Extended Communities structure by uniq and sort each
215 * Extended Communities value.
217 struct ecommunity
*ecommunity_uniq_sort(struct ecommunity
*ecom
)
219 return ecommunity_uniq_sort_internal(ecom
, ECOMMUNITY_SIZE
);
222 /* Parse Extended Communites Attribute in BGP packet. */
223 static struct ecommunity
*ecommunity_parse_internal(uint8_t *pnt
,
224 unsigned short length
,
225 unsigned short size_ecom
,
226 bool disable_ieee_floating
)
228 struct ecommunity tmp
;
229 struct ecommunity
*new;
232 if (length
% size_ecom
)
235 /* Prepare tmporary structure for making a new Extended Communities
237 tmp
.size
= length
/ size_ecom
;
239 tmp
.disable_ieee_floating
= disable_ieee_floating
;
241 /* Create a new Extended Communities Attribute by uniq and sort each
242 Extended Communities value */
243 new = ecommunity_uniq_sort_internal(&tmp
, size_ecom
);
245 return ecommunity_intern(new);
248 struct ecommunity
*ecommunity_parse(uint8_t *pnt
, unsigned short length
,
249 bool disable_ieee_floating
)
251 return ecommunity_parse_internal(pnt
, length
, ECOMMUNITY_SIZE
,
252 disable_ieee_floating
);
255 struct ecommunity
*ecommunity_parse_ipv6(uint8_t *pnt
, unsigned short length
,
256 bool disable_ieee_floating
)
258 return ecommunity_parse_internal(pnt
, length
, IPV6_ECOMMUNITY_SIZE
,
259 disable_ieee_floating
);
262 /* Duplicate the Extended Communities Attribute structure. */
263 struct ecommunity
*ecommunity_dup(struct ecommunity
*ecom
)
265 struct ecommunity
*new;
267 new = XCALLOC(MTYPE_ECOMMUNITY
, sizeof(struct ecommunity
));
268 new->size
= ecom
->size
;
269 new->unit_size
= ecom
->unit_size
;
271 new->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
,
272 ecom
->size
* ecom
->unit_size
);
273 memcpy(new->val
, ecom
->val
,
274 (size_t)ecom
->size
* (size_t)ecom
->unit_size
);
280 /* Return string representation of ecommunities attribute. */
281 char *ecommunity_str(struct ecommunity
*ecom
)
285 ecommunity_ecom2str(ecom
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
289 /* Merge two Extended Communities Attribute structure. */
290 struct ecommunity
*ecommunity_merge(struct ecommunity
*ecom1
,
291 struct ecommunity
*ecom2
)
293 ecom1
->val
= XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom1
->val
,
294 (size_t)(ecom1
->size
+ ecom2
->size
)
295 * (size_t)ecom1
->unit_size
);
297 memcpy(ecom1
->val
+ (ecom1
->size
* ecom1
->unit_size
), ecom2
->val
,
298 (size_t)ecom2
->size
* (size_t)ecom1
->unit_size
);
299 ecom1
->size
+= ecom2
->size
;
304 /* Intern Extended Communities Attribute. */
305 struct ecommunity
*ecommunity_intern(struct ecommunity
*ecom
)
307 struct ecommunity
*find
;
309 assert(ecom
->refcnt
== 0);
310 find
= (struct ecommunity
*)hash_get(ecomhash
, ecom
, hash_alloc_intern
);
312 ecommunity_free(&ecom
);
318 ecommunity_ecom2str(find
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
323 /* Unintern Extended Communities Attribute. */
324 void ecommunity_unintern(struct ecommunity
**ecom
)
326 struct ecommunity
*ret
;
334 /* Pull off from hash. */
335 if ((*ecom
)->refcnt
== 0) {
336 /* Extended community must be in the hash. */
337 ret
= (struct ecommunity
*)hash_release(ecomhash
, *ecom
);
340 ecommunity_free(ecom
);
344 /* Utinity function to make hash key. */
345 unsigned int ecommunity_hash_make(const void *arg
)
347 const struct ecommunity
*ecom
= arg
;
348 int size
= ecom
->size
* ecom
->unit_size
;
350 return jhash(ecom
->val
, size
, 0x564321ab);
353 /* Compare two Extended Communities Attribute structure. */
354 bool ecommunity_cmp(const void *arg1
, const void *arg2
)
356 const struct ecommunity
*ecom1
= arg1
;
357 const struct ecommunity
*ecom2
= arg2
;
359 if (ecom1
== NULL
&& ecom2
== NULL
)
362 if (ecom1
== NULL
|| ecom2
== NULL
)
365 if (ecom1
->unit_size
!= ecom2
->unit_size
)
368 return (ecom1
->size
== ecom2
->size
369 && memcmp(ecom1
->val
, ecom2
->val
, ecom1
->size
*
370 ecom1
->unit_size
) == 0);
373 /* Initialize Extended Comminities related hash. */
374 void ecommunity_init(void)
376 ecomhash
= hash_create(ecommunity_hash_make
, ecommunity_cmp
,
377 "BGP ecommunity hash");
380 void ecommunity_finish(void)
382 hash_clean(ecomhash
, (void (*)(void *))ecommunity_hash_free
);
387 /* Extended Communities token enum. */
388 enum ecommunity_token
{
389 ecommunity_token_unknown
= 0,
391 ecommunity_token_soo
,
392 ecommunity_token_val
,
393 ecommunity_token_rt6
,
394 ecommunity_token_val6
,
397 static int ecommunity_encode_internal(uint8_t type
, uint8_t sub_type
,
400 struct in6_addr
*ip6
,
404 struct ecommunity_val
*eval
= (struct ecommunity_val
*)eval_ptr
;
405 struct ecommunity_val_ipv6
*eval6
=
406 (struct ecommunity_val_ipv6
*)eval_ptr
;
409 if (type
== ECOMMUNITY_ENCODE_AS
) {
412 } else if (type
== ECOMMUNITY_ENCODE_IP
413 || type
== ECOMMUNITY_ENCODE_AS4
) {
414 if (val
> UINT16_MAX
)
416 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
&&
417 sub_type
== ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
&&
418 (!ip6
|| val
> UINT16_MAX
)) {
422 /* Fill in the values. */
425 eval
->val
[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE
;
426 eval
->val
[1] = sub_type
;
427 if (type
== ECOMMUNITY_ENCODE_AS
) {
428 eval
->val
[2] = (as
>> 8) & 0xff;
429 eval
->val
[3] = as
& 0xff;
430 eval
->val
[4] = (val
>> 24) & 0xff;
431 eval
->val
[5] = (val
>> 16) & 0xff;
432 eval
->val
[6] = (val
>> 8) & 0xff;
433 eval
->val
[7] = val
& 0xff;
434 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
435 memcpy(&eval
->val
[2], ip
, sizeof(struct in_addr
));
436 eval
->val
[6] = (val
>> 8) & 0xff;
437 eval
->val
[7] = val
& 0xff;
438 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
&&
439 sub_type
== ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
) {
440 memcpy(&eval6
->val
[2], ip6
, sizeof(struct in6_addr
));
441 eval6
->val
[18] = (val
>> 8) & 0xff;
442 eval6
->val
[19] = val
& 0xff;
444 eval
->val
[2] = (as
>> 24) & 0xff;
445 eval
->val
[3] = (as
>> 16) & 0xff;
446 eval
->val
[4] = (as
>> 8) & 0xff;
447 eval
->val
[5] = as
& 0xff;
448 eval
->val
[6] = (val
>> 8) & 0xff;
449 eval
->val
[7] = val
& 0xff;
456 * Encode BGP extended community from passed values. Supports types
457 * defined in RFC 4360 and well-known sub-types.
459 static int ecommunity_encode(uint8_t type
, uint8_t sub_type
, int trans
, as_t as
,
460 struct in_addr ip
, uint32_t val
,
461 struct ecommunity_val
*eval
)
463 return ecommunity_encode_internal(type
, sub_type
, trans
, as
,
464 &ip
, NULL
, val
, (void *)eval
);
467 /* Get next Extended Communities token from the string. */
468 static const char *ecommunity_gettoken(const char *str
,
470 enum ecommunity_token
*token
)
483 char buf
[INET_ADDRSTRLEN
+ 1];
484 struct ecommunity_val
*eval
= (struct ecommunity_val
*)eval_ptr
;
485 /* Skip white space. */
486 while (isspace((unsigned char)*p
)) {
491 /* Check the end of the line. */
495 /* "rt" and "soo" keyword parse. */
496 if (!isdigit((unsigned char)*p
)) {
497 /* "rt" match check. */
498 if (tolower((unsigned char)*p
) == 'r') {
500 if (tolower((unsigned char)*p
) == 't') {
502 if (*p
!= '\0' && tolower((int)*p
) == '6')
503 *token
= ecommunity_token_rt6
;
505 *token
= ecommunity_token_rt
;
508 if (isspace((unsigned char)*p
) || *p
== '\0') {
509 *token
= ecommunity_token_rt
;
514 /* "soo" match check. */
515 else if (tolower((unsigned char)*p
) == 's') {
517 if (tolower((unsigned char)*p
) == 'o') {
519 if (tolower((unsigned char)*p
) == 'o') {
521 *token
= ecommunity_token_soo
;
524 if (isspace((unsigned char)*p
) || *p
== '\0') {
525 *token
= ecommunity_token_soo
;
530 if (isspace((unsigned char)*p
) || *p
== '\0') {
531 *token
= ecommunity_token_soo
;
539 /* What a mess, there are several possibilities:
544 * d) <IPV6>:MN (only with rt6)
546 * A.B.C.D: Four Byte IP
548 * GHJK: Four-byte ASN
550 * OPQR: Four byte value
553 /* IPv6 case : look for last ':' */
554 if (*token
== ecommunity_token_rt6
||
555 *token
== ecommunity_token_val6
) {
558 limit
= endptr
= strrchr(p
, ':');
563 as
= strtoul(endptr
, &endptr
, 10);
564 if (*endptr
!= '\0' || as
== BGP_AS4_MAX
)
567 memcpy(buf
, p
, (limit
- p
));
568 buf
[limit
- p
] = '\0';
569 ret
= inet_pton(AF_INET6
, buf
, &ip6
);
573 ecomm_type
= ECOMMUNITY_ENCODE_TRANS_EXP
;
574 if (ecommunity_encode_internal(ecomm_type
,
575 ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
,
576 1, 0, NULL
, &ip6
, as
, eval_ptr
))
579 *token
= ecommunity_token_val6
;
580 while (isdigit((int)*p
) || *p
== ':' || *p
== '.') {
585 while (isdigit((unsigned char)*p
) || *p
== ':' || *p
== '.') {
593 if ((p
- str
) > INET_ADDRSTRLEN
)
595 memset(buf
, 0, INET_ADDRSTRLEN
+ 1);
596 memcpy(buf
, str
, p
- str
);
599 /* Parsing A.B.C.D in:
602 ret
= inet_aton(buf
, &ip
);
607 as
= strtoul(buf
, &endptr
, 10);
608 if (*endptr
!= '\0' || as
== BGP_AS4_MAX
)
611 } else if (*p
== '.') {
620 /* We're past the IP/ASN part */
629 /* Low digit part must be there. */
630 if (!digit
|| !separator
)
633 /* Encode result into extended community. */
635 ecomm_type
= ECOMMUNITY_ENCODE_IP
;
636 else if (as
> BGP_AS_MAX
)
637 ecomm_type
= ECOMMUNITY_ENCODE_AS4
;
639 ecomm_type
= ECOMMUNITY_ENCODE_AS
;
640 if (ecommunity_encode(ecomm_type
, 0, 1, as
, ip
, val
, eval
))
642 *token
= ecommunity_token_val
;
646 *token
= ecommunity_token_unknown
;
650 static struct ecommunity
*ecommunity_str2com_internal(const char *str
, int type
,
651 int keyword_included
,
652 bool is_ipv6_extcomm
)
654 struct ecommunity
*ecom
= NULL
;
655 enum ecommunity_token token
= ecommunity_token_unknown
;
656 struct ecommunity_val_ipv6 eval
;
660 token
= ecommunity_token_rt6
;
661 while ((str
= ecommunity_gettoken(str
, (void *)&eval
, &token
))) {
663 case ecommunity_token_rt
:
664 case ecommunity_token_soo
:
665 if (!keyword_included
|| keyword
) {
667 ecommunity_free(&ecom
);
672 if (token
== ecommunity_token_rt
||
673 token
== ecommunity_token_rt6
) {
674 type
= ECOMMUNITY_ROUTE_TARGET
;
676 if (token
== ecommunity_token_soo
) {
677 type
= ECOMMUNITY_SITE_ORIGIN
;
680 case ecommunity_token_val
:
681 if (keyword_included
) {
683 ecommunity_free(&ecom
);
689 ecom
= ecommunity_new();
691 ecommunity_add_val_internal(ecom
, (void *)&eval
,
695 case ecommunity_token_val6
:
696 if (keyword_included
) {
698 ecommunity_free(&ecom
);
704 ecom
= ecommunity_new();
705 ecom
->unit_size
= IPV6_ECOMMUNITY_SIZE
;
707 ecommunity_add_val_internal(ecom
, (void *)&eval
, false, false,
710 case ecommunity_token_unknown
:
713 ecommunity_free(&ecom
);
720 /* Convert string to extended community attribute.
722 * When type is already known, please specify both str and type. str
723 * should not include keyword such as "rt" and "soo". Type is
724 * ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
725 * keyword_included should be zero.
727 * For example route-map's "set extcommunity" command case:
729 * "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
730 * type = ECOMMUNITY_ROUTE_TARGET
731 * keyword_included = 0
733 * "soo 100:1" -> str = "100:1"
734 * type = ECOMMUNITY_SITE_ORIGIN
735 * keyword_included = 0
737 * When string includes keyword for each extended community value.
738 * Please specify keyword_included as non-zero value.
740 * For example standard extcommunity-list case:
742 * "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
744 * keyword_include = 1
746 struct ecommunity
*ecommunity_str2com(const char *str
, int type
,
747 int keyword_included
)
749 return ecommunity_str2com_internal(str
, type
,
750 keyword_included
, false);
753 struct ecommunity
*ecommunity_str2com_ipv6(const char *str
, int type
,
754 int keyword_included
)
756 return ecommunity_str2com_internal(str
, type
,
757 keyword_included
, true);
760 static int ecommunity_rt_soo_str_internal(char *buf
, size_t bufsz
,
761 const uint8_t *pnt
, int type
,
762 int sub_type
, int format
,
763 unsigned short ecom_size
)
767 char buf_local
[INET6_ADDRSTRLEN
];
769 /* For parse Extended Community attribute tupple. */
770 struct ecommunity_as eas
;
771 struct ecommunity_ip eip
;
772 struct ecommunity_ip6 eip6
;
774 /* Determine prefix for string, if any. */
776 case ECOMMUNITY_FORMAT_COMMUNITY_LIST
:
777 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "rt " : "soo ");
779 case ECOMMUNITY_FORMAT_DISPLAY
:
780 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "RT:" : "SoO:");
782 case ECOMMUNITY_FORMAT_ROUTE_MAP
:
790 /* Put string into buffer. */
791 if (type
== ECOMMUNITY_ENCODE_AS4
) {
792 pnt
= ptr_get_be32(pnt
, &eas
.as
);
793 eas
.val
= (*pnt
++ << 8);
796 len
= snprintf(buf
, bufsz
, "%s%u:%u", prefix
, eas
.as
, eas
.val
);
797 } else if (type
== ECOMMUNITY_ENCODE_AS
) {
798 if (ecom_size
== ECOMMUNITY_SIZE
) {
799 eas
.as
= (*pnt
++ << 8);
801 pnt
= ptr_get_be32(pnt
, &eas
.val
);
803 len
= snprintf(buf
, bufsz
, "%s%u:%u", prefix
, eas
.as
,
806 /* this is an IPv6 ext community
807 * first 16 bytes stands for IPv6 addres
809 memcpy(&eip6
.ip
, pnt
, 16);
811 eip6
.val
= (*pnt
++ << 8);
812 eip6
.val
|= (*pnt
++);
814 inet_ntop(AF_INET6
, &eip6
.ip
, buf_local
,
816 len
= snprintf(buf
, bufsz
, "%s%s:%u", prefix
,
817 buf_local
, eip6
.val
);
819 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
820 memcpy(&eip
.ip
, pnt
, 4);
822 eip
.val
= (*pnt
++ << 8);
825 len
= snprintfrr(buf
, bufsz
, "%s%pI4:%u", prefix
, &eip
.ip
,
835 static int ecommunity_rt_soo_str(char *buf
, size_t bufsz
, const uint8_t *pnt
,
836 int type
, int sub_type
, int format
)
838 return ecommunity_rt_soo_str_internal(buf
, bufsz
, pnt
, type
,
843 /* Helper function to convert IEEE-754 Floating Point to uint32 */
844 static uint32_t ieee_float_uint32_to_uint32(uint32_t u
)
851 return (uint32_t)f
.r
;
854 static int ecommunity_lb_str(char *buf
, size_t bufsz
, const uint8_t *pnt
,
855 bool disable_ieee_floating
)
860 char bps_buf
[20] = {0};
862 #define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8)
863 #define ONE_MBPS_BYTES (1000 * 1000 / 8)
864 #define ONE_KBPS_BYTES (1000 / 8)
868 (void)ptr_get_be32(pnt
, &bw_tmp
);
870 bw
= disable_ieee_floating
? bw_tmp
871 : ieee_float_uint32_to_uint32(bw_tmp
);
873 if (bw
>= ONE_GBPS_BYTES
)
874 snprintf(bps_buf
, sizeof(bps_buf
), "%.3f Gbps",
875 (float)(bw
/ ONE_GBPS_BYTES
));
876 else if (bw
>= ONE_MBPS_BYTES
)
877 snprintf(bps_buf
, sizeof(bps_buf
), "%.3f Mbps",
878 (float)(bw
/ ONE_MBPS_BYTES
));
879 else if (bw
>= ONE_KBPS_BYTES
)
880 snprintf(bps_buf
, sizeof(bps_buf
), "%.3f Kbps",
881 (float)(bw
/ ONE_KBPS_BYTES
));
883 snprintf(bps_buf
, sizeof(bps_buf
), "%u bps", bw
* 8);
885 len
= snprintf(buf
, bufsz
, "LB:%u:%u (%s)", as
, bw
, bps_buf
);
889 /* Convert extended community attribute to string.
891 Due to historical reason of industry standard implementation, there
892 are three types of format.
894 route-map set extcommunity format
895 "rt 100:1 100:2soo 100:3"
898 "rt 100:1 rt 100:2 soo 100:3show [ip] bgp" and extcommunity-list regular expression matching
899 "RT:100:1 RT:100:2 SoO:100:3"
901 For each formath please use below definition for format:
903 ECOMMUNITY_FORMAT_ROUTE_MAP
904 ECOMMUNITY_FORMAT_COMMUNITY_LIST
905 ECOMMUNITY_FORMAT_DISPLAY
907 Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
910 char *ecommunity_ecom2str(struct ecommunity
*ecom
, int format
, int filter
)
915 uint8_t sub_type
= 0;
919 if (!ecom
|| ecom
->size
== 0)
920 return XCALLOC(MTYPE_ECOMMUNITY_STR
, 1);
922 /* ecom strlen + space + null term */
923 str_size
= (ecom
->size
* (ECOMMUNITY_STRLEN
+ 1)) + 1;
924 str_buf
= XCALLOC(MTYPE_ECOMMUNITY_STR
, str_size
);
928 for (i
= 0; i
< ecom
->size
; i
++) {
930 memset(encbuf
, 0x00, sizeof(encbuf
));
932 /* Space between each value. */
934 strlcat(str_buf
, " ", str_size
);
936 /* Retrieve value field */
937 pnt
= ecom
->val
+ (i
* ecom
->unit_size
);
939 /* High-order octet is the type */
942 if (type
== ECOMMUNITY_ENCODE_AS
|| type
== ECOMMUNITY_ENCODE_IP
943 || type
== ECOMMUNITY_ENCODE_AS4
) {
944 /* Low-order octet of type. */
946 if (sub_type
!= ECOMMUNITY_ROUTE_TARGET
947 && sub_type
!= ECOMMUNITY_SITE_ORIGIN
) {
949 ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4
&&
950 type
== ECOMMUNITY_ENCODE_IP
) {
951 struct in_addr
*ipv4
=
952 (struct in_addr
*)pnt
;
953 char ipv4str
[INET_ADDRSTRLEN
];
955 inet_ntop(AF_INET
, ipv4
,
958 snprintf(encbuf
, sizeof(encbuf
),
959 "NH:%s:%d", ipv4str
, pnt
[5]);
960 } else if (sub_type
==
961 ECOMMUNITY_LINK_BANDWIDTH
&&
962 type
== ECOMMUNITY_ENCODE_AS
) {
964 encbuf
, sizeof(encbuf
), pnt
,
965 ecom
->disable_ieee_floating
);
969 ecommunity_rt_soo_str(encbuf
, sizeof(encbuf
),
973 } else if (type
== ECOMMUNITY_ENCODE_OPAQUE
) {
974 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
976 if (*pnt
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
) {
978 memcpy(&tunneltype
, pnt
+ 5, 2);
979 tunneltype
= ntohs(tunneltype
);
981 snprintf(encbuf
, sizeof(encbuf
), "ET:%d",
983 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_DEF_GW
) {
984 strlcpy(encbuf
, "Default Gateway",
989 } else if (type
== ECOMMUNITY_ENCODE_EVPN
) {
990 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
992 if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC
) {
995 memcpy(&rmac
, pnt
, ETH_ALEN
);
997 snprintf(encbuf
, sizeof(encbuf
),
998 "Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
999 (uint8_t)rmac
.octet
[0],
1000 (uint8_t)rmac
.octet
[1],
1001 (uint8_t)rmac
.octet
[2],
1002 (uint8_t)rmac
.octet
[3],
1003 (uint8_t)rmac
.octet
[4],
1004 (uint8_t)rmac
.octet
[5]);
1006 == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY
) {
1008 uint8_t flags
= *++pnt
;
1010 memcpy(&seqnum
, pnt
+ 2, 4);
1011 seqnum
= ntohl(seqnum
);
1013 snprintf(encbuf
, sizeof(encbuf
), "MM:%u",
1018 ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY
))
1019 strlcat(encbuf
, ", sticky MAC",
1021 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ND
) {
1022 uint8_t flags
= *++pnt
;
1026 ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG
))
1027 strlcpy(encbuf
, "ND:Router Flag",
1031 ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG
))
1032 strlcpy(encbuf
, "ND:Proxy",
1035 == ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT
) {
1039 memcpy(&mac
, pnt
, ETH_ALEN
);
1042 "ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x",
1043 (uint8_t)mac
.octet
[0],
1044 (uint8_t)mac
.octet
[1],
1045 (uint8_t)mac
.octet
[2],
1046 (uint8_t)mac
.octet
[3],
1047 (uint8_t)mac
.octet
[4],
1048 (uint8_t)mac
.octet
[5]);
1050 == ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL
) {
1051 uint8_t flags
= *++pnt
;
1054 sizeof(encbuf
), "ESI-label-Rt:%s",
1056 ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG
) ?
1059 == ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION
) {
1065 memcpy(&bmap
, pnt
+ 2, 2);
1067 memcpy(&pref
, pnt
+ 5, 2);
1072 encbuf
, sizeof(encbuf
),
1073 "DF: (alg: %u, bmap: 0x%x pref: %u)",
1076 snprintf(encbuf
, sizeof(encbuf
),
1077 "DF: (alg: %u, pref: %u)", alg
,
1081 } else if (type
== ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) {
1083 if (sub_type
== ECOMMUNITY_REDIRECT_IP_NH
) {
1084 snprintf(encbuf
, sizeof(encbuf
),
1085 "FS:redirect IP 0x%x", *(pnt
+ 5));
1088 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
||
1089 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
1090 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
) {
1093 if (sub_type
== ECOMMUNITY_ROUTE_TARGET
) {
1094 char buf
[ECOMMUNITY_STRLEN
];
1096 memset(buf
, 0, sizeof(buf
));
1097 ecommunity_rt_soo_str_internal(buf
, sizeof(buf
),
1098 (const uint8_t *)pnt
,
1100 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1101 ECOMMUNITY_ROUTE_TARGET
,
1104 snprintf(encbuf
, sizeof(encbuf
), "%s", buf
);
1105 } else if (sub_type
==
1106 ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
) {
1109 memset(buf
, 0, sizeof(buf
));
1110 ecommunity_rt_soo_str_internal(buf
, sizeof(buf
),
1111 (const uint8_t *)pnt
,
1113 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1114 ECOMMUNITY_ROUTE_TARGET
,
1115 ECOMMUNITY_FORMAT_DISPLAY
,
1117 snprintf(encbuf
, sizeof(encbuf
),
1118 "FS:redirect VRF %s", buf
);
1119 } else if (sub_type
== ECOMMUNITY_REDIRECT_VRF
) {
1122 memset(buf
, 0, sizeof(buf
));
1123 ecommunity_rt_soo_str(buf
, sizeof(buf
),
1124 (const uint8_t *)pnt
,
1126 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1127 ECOMMUNITY_ROUTE_TARGET
,
1128 ECOMMUNITY_FORMAT_DISPLAY
);
1129 snprintf(encbuf
, sizeof(encbuf
),
1130 "FS:redirect VRF %s", buf
);
1131 snprintf(encbuf
, sizeof(encbuf
),
1132 "FS:redirect VRF %s", buf
);
1133 } else if (type
!= ECOMMUNITY_ENCODE_TRANS_EXP
)
1135 else if (sub_type
== ECOMMUNITY_TRAFFIC_ACTION
) {
1139 1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
)
1140 strlcpy(action
, "terminate (apply)",
1143 strlcpy(action
, "eval stops",
1147 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
1148 strlcat(action
, ", sample",
1152 snprintf(encbuf
, sizeof(encbuf
), "FS:action %s",
1154 } else if (sub_type
== ECOMMUNITY_TRAFFIC_RATE
) {
1155 union traffic_rate data
;
1157 data
.rate_byte
[3] = *(pnt
+2);
1158 data
.rate_byte
[2] = *(pnt
+3);
1159 data
.rate_byte
[1] = *(pnt
+4);
1160 data
.rate_byte
[0] = *(pnt
+5);
1161 snprintf(encbuf
, sizeof(encbuf
), "FS:rate %f",
1163 } else if (sub_type
== ECOMMUNITY_TRAFFIC_MARKING
) {
1164 snprintf(encbuf
, sizeof(encbuf
),
1165 "FS:marking %u", *(pnt
+ 5));
1168 } else if (type
== ECOMMUNITY_ENCODE_AS_NON_TRANS
) {
1170 if (sub_type
== ECOMMUNITY_LINK_BANDWIDTH
)
1171 ecommunity_lb_str(encbuf
, sizeof(encbuf
), pnt
,
1172 ecom
->disable_ieee_floating
);
1181 snprintf(encbuf
, sizeof(encbuf
), "UNK:%d, %d", type
,
1184 int r
= strlcat(str_buf
, encbuf
, str_size
);
1185 assert(r
< str_size
);
1191 bool ecommunity_match(const struct ecommunity
*ecom1
,
1192 const struct ecommunity
*ecom2
)
1197 if (ecom1
== NULL
&& ecom2
== NULL
)
1200 if (ecom1
== NULL
|| ecom2
== NULL
)
1203 if (ecom1
->size
< ecom2
->size
)
1206 /* Every community on com2 needs to be on com1 for this to match */
1207 while (i
< ecom1
->size
&& j
< ecom2
->size
) {
1208 if (memcmp(ecom1
->val
+ i
* ecom1
->unit_size
,
1209 ecom2
->val
+ j
* ecom2
->unit_size
,
1216 if (j
== ecom2
->size
)
1222 /* return first occurence of type */
1223 extern struct ecommunity_val
*ecommunity_lookup(const struct ecommunity
*ecom
,
1224 uint8_t type
, uint8_t subtype
)
1229 /* If the value already exists in the structure return 0. */
1231 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1235 if (p
[0] == type
&& p
[1] == subtype
)
1236 return (struct ecommunity_val
*)p
;
1241 /* remove ext. community matching type and subtype
1242 * return 1 on success ( removed ), 0 otherwise (not present)
1244 bool ecommunity_strip(struct ecommunity
*ecom
, uint8_t type
,
1247 uint8_t *p
, *q
, *new;
1248 uint32_t c
, found
= 0;
1249 /* When this is fist value, just add it. */
1250 if (ecom
== NULL
|| ecom
->val
== NULL
)
1253 /* Check if any existing ext community matches. */
1254 /* Certain extended communities like the Route Target can be present
1255 * multiple times, handle that.
1258 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1259 if (p
[0] == type
&& p
[1] == subtype
)
1262 /* If no matching ext community exists, return. */
1266 /* Handle the case where everything needs to be stripped. */
1267 if (found
== ecom
->size
) {
1268 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1273 /* Strip matching ext community(ies). */
1274 new = XMALLOC(MTYPE_ECOMMUNITY_VAL
,
1275 (ecom
->size
- found
) * ecom
->unit_size
);
1277 for (c
= 0, p
= ecom
->val
; c
< ecom
->size
; c
++, p
+= ecom
->unit_size
) {
1278 if (!(p
[0] == type
&& p
[1] == subtype
)) {
1279 memcpy(q
, p
, ecom
->unit_size
);
1280 q
+= ecom
->unit_size
;
1283 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1285 ecom
->size
-= found
;
1290 * Remove specified extended community value from extended community.
1291 * Returns 1 if value was present (and hence, removed), 0 otherwise.
1293 bool ecommunity_del_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
1296 uint32_t c
, found
= 0;
1298 /* Make sure specified value exists. */
1299 if (ecom
== NULL
|| ecom
->val
== NULL
)
1302 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1303 if (!memcmp(p
, eval
->val
, ecom
->unit_size
)) {
1311 /* Delete the selected value */
1314 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ecom
->unit_size
);
1316 memcpy(p
, ecom
->val
, c
* ecom
->unit_size
);
1317 if ((ecom
->size
- c
) != 0)
1318 memcpy(p
+ (c
)*ecom
->unit_size
,
1319 ecom
->val
+ (c
+ 1) * ecom
->unit_size
,
1320 (ecom
->size
- c
) * ecom
->unit_size
);
1321 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1329 int ecommunity_fill_pbr_action(struct ecommunity_val
*ecom_eval
,
1330 struct bgp_pbr_entry_action
*api
,
1333 if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_RATE
) {
1334 api
->action
= ACTION_TRAFFICRATE
;
1335 api
->u
.r
.rate_info
[3] = ecom_eval
->val
[4];
1336 api
->u
.r
.rate_info
[2] = ecom_eval
->val
[5];
1337 api
->u
.r
.rate_info
[1] = ecom_eval
->val
[6];
1338 api
->u
.r
.rate_info
[0] = ecom_eval
->val
[7];
1339 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_ACTION
) {
1340 api
->action
= ACTION_TRAFFIC_ACTION
;
1341 /* else distribute code is set by default */
1342 if (ecom_eval
->val
[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
))
1343 api
->u
.za
.filter
|= TRAFFIC_ACTION_TERMINATE
;
1345 api
->u
.za
.filter
|= TRAFFIC_ACTION_DISTRIBUTE
;
1346 if (ecom_eval
->val
[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
1347 api
->u
.za
.filter
|= TRAFFIC_ACTION_SAMPLE
;
1349 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_MARKING
) {
1350 api
->action
= ACTION_MARKING
;
1351 api
->u
.marking_dscp
= ecom_eval
->val
[7];
1352 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_VRF
) {
1353 /* must use external function */
1355 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_IP_NH
&&
1357 /* see draft-ietf-idr-flowspec-redirect-ip-02
1358 * Q1: how come a ext. community can host ipv6 address
1359 * Q2 : from cisco documentation:
1360 * Announces the reachability of one or more flowspec NLRI.
1361 * When a BGP speaker receives an UPDATE message with the
1362 * redirect-to-IP extended community, it is expected to
1363 * create a traffic filtering rule for every flow-spec
1364 * NLRI in the message that has this path as its best
1365 * path. The filter entry matches the IP packets
1366 * described in the NLRI field and redirects them or
1367 * copies them towards the IPv4 or IPv6 address specified
1368 * in the 'Network Address of Next- Hop'
1369 * field of the associated MP_REACH_NLRI.
1371 struct ecommunity_ip
*ip_ecom
= (struct ecommunity_ip
*)
1374 api
->u
.zr
.redirect_ip_v4
= ip_ecom
->ip
;
1380 static struct ecommunity
*bgp_aggr_ecommunity_lookup(
1381 struct bgp_aggregate
*aggregate
,
1382 struct ecommunity
*ecommunity
)
1384 return hash_lookup(aggregate
->ecommunity_hash
, ecommunity
);
1387 static void *bgp_aggr_ecommunty_hash_alloc(void *p
)
1389 struct ecommunity
*ref
= (struct ecommunity
*)p
;
1390 struct ecommunity
*ecommunity
= NULL
;
1392 ecommunity
= ecommunity_dup(ref
);
1396 static void bgp_aggr_ecommunity_prepare(struct hash_bucket
*hb
, void *arg
)
1398 struct ecommunity
*hb_ecommunity
= hb
->data
;
1399 struct ecommunity
**aggr_ecommunity
= arg
;
1401 if (*aggr_ecommunity
)
1402 *aggr_ecommunity
= ecommunity_merge(*aggr_ecommunity
,
1405 *aggr_ecommunity
= ecommunity_dup(hb_ecommunity
);
1408 void bgp_aggr_ecommunity_remove(void *arg
)
1410 struct ecommunity
*ecommunity
= arg
;
1412 ecommunity_free(&ecommunity
);
1415 void bgp_compute_aggregate_ecommunity(struct bgp_aggregate
*aggregate
,
1416 struct ecommunity
*ecommunity
)
1418 bgp_compute_aggregate_ecommunity_hash(aggregate
, ecommunity
);
1419 bgp_compute_aggregate_ecommunity_val(aggregate
);
1423 void bgp_compute_aggregate_ecommunity_hash(struct bgp_aggregate
*aggregate
,
1424 struct ecommunity
*ecommunity
)
1426 struct ecommunity
*aggr_ecommunity
= NULL
;
1428 if ((aggregate
== NULL
) || (ecommunity
== NULL
))
1431 /* Create hash if not already created.
1433 if (aggregate
->ecommunity_hash
== NULL
)
1434 aggregate
->ecommunity_hash
= hash_create(
1435 ecommunity_hash_make
, ecommunity_cmp
,
1436 "BGP Aggregator ecommunity hash");
1438 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1439 if (aggr_ecommunity
== NULL
) {
1440 /* Insert ecommunity into hash.
1442 aggr_ecommunity
= hash_get(aggregate
->ecommunity_hash
,
1444 bgp_aggr_ecommunty_hash_alloc
);
1447 /* Increment reference counter.
1449 aggr_ecommunity
->refcnt
++;
1452 void bgp_compute_aggregate_ecommunity_val(struct bgp_aggregate
*aggregate
)
1454 struct ecommunity
*ecommerge
= NULL
;
1456 if (aggregate
== NULL
)
1459 /* Re-compute aggregate's ecommunity.
1461 if (aggregate
->ecommunity
)
1462 ecommunity_free(&aggregate
->ecommunity
);
1463 if (aggregate
->ecommunity_hash
1464 && aggregate
->ecommunity_hash
->count
) {
1465 hash_iterate(aggregate
->ecommunity_hash
,
1466 bgp_aggr_ecommunity_prepare
,
1467 &aggregate
->ecommunity
);
1468 ecommerge
= aggregate
->ecommunity
;
1469 aggregate
->ecommunity
= ecommunity_uniq_sort(ecommerge
);
1471 ecommunity_free(&ecommerge
);
1475 void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate
*aggregate
,
1476 struct ecommunity
*ecommunity
)
1478 struct ecommunity
*aggr_ecommunity
= NULL
;
1479 struct ecommunity
*ret_ecomm
= NULL
;
1482 || (!aggregate
->ecommunity_hash
)
1486 /* Look-up the ecommunity in the hash.
1488 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1489 if (aggr_ecommunity
) {
1490 aggr_ecommunity
->refcnt
--;
1492 if (aggr_ecommunity
->refcnt
== 0) {
1493 ret_ecomm
= hash_release(aggregate
->ecommunity_hash
,
1495 ecommunity_free(&ret_ecomm
);
1496 bgp_compute_aggregate_ecommunity_val(aggregate
);
1501 void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate
*aggregate
,
1502 struct ecommunity
*ecommunity
)
1505 struct ecommunity
*aggr_ecommunity
= NULL
;
1506 struct ecommunity
*ret_ecomm
= NULL
;
1509 || (!aggregate
->ecommunity_hash
)
1513 /* Look-up the ecommunity in the hash.
1515 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1516 if (aggr_ecommunity
) {
1517 aggr_ecommunity
->refcnt
--;
1519 if (aggr_ecommunity
->refcnt
== 0) {
1520 ret_ecomm
= hash_release(aggregate
->ecommunity_hash
,
1522 ecommunity_free(&ret_ecomm
);
1528 * return the BGP link bandwidth extended community, if present;
1529 * the actual bandwidth is returned via param
1531 const uint8_t *ecommunity_linkbw_present(struct ecommunity
*ecom
, uint32_t *bw
)
1533 const uint8_t *eval
;
1539 if (!ecom
|| !ecom
->size
)
1542 for (i
= 0; i
< ecom
->size
; i
++) {
1544 uint8_t type
, sub_type
;
1547 eval
= pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
1551 if ((type
== ECOMMUNITY_ENCODE_AS
||
1552 type
== ECOMMUNITY_ENCODE_AS_NON_TRANS
) &&
1553 sub_type
== ECOMMUNITY_LINK_BANDWIDTH
) {
1554 pnt
+= 2; /* bandwidth is encoded as AS:val */
1555 pnt
= ptr_get_be32(pnt
, &bwval
);
1556 (void)pnt
; /* consume value */
1558 *bw
= ecom
->disable_ieee_floating
1560 : ieee_float_uint32_to_uint32(
1570 struct ecommunity
*ecommunity_replace_linkbw(as_t as
, struct ecommunity
*ecom
,
1572 bool disable_ieee_floating
)
1574 struct ecommunity
*new;
1575 struct ecommunity_val lb_eval
;
1576 const uint8_t *eval
;
1580 /* Nothing to replace if link-bandwidth doesn't exist or
1581 * is non-transitive - just return existing extcommunity.
1584 if (!ecom
|| !ecom
->size
)
1587 eval
= ecommunity_linkbw_present(ecom
, &cur_bw
);
1592 if (type
& ECOMMUNITY_FLAG_NON_TRANSITIVE
)
1595 /* Transitive link-bandwidth exists, replace with the passed
1596 * (cumulative) bandwidth value. We need to create a new
1597 * extcommunity for this - refer to AS-Path replace function
1600 if (cum_bw
> 0xFFFFFFFF)
1601 cum_bw
= 0xFFFFFFFF;
1602 encode_lb_extcomm(as
> BGP_AS_MAX
? BGP_AS_TRANS
: as
, cum_bw
, false,
1603 &lb_eval
, disable_ieee_floating
);
1604 new = ecommunity_dup(ecom
);
1605 ecommunity_add_val(new, &lb_eval
, true, true);