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_include(struct ecommunity
*e1
, struct ecommunity
*e2
)
1197 for (i
= 0; i
< e1
->size
; ++i
) {
1198 for (j
= 0; j
< e2
->size
; ++j
) {
1199 if (!memcmp(e1
->val
+ (i
* e1
->unit_size
),
1200 e2
->val
+ (j
* e2
->unit_size
),
1208 bool ecommunity_match(const struct ecommunity
*ecom1
,
1209 const struct ecommunity
*ecom2
)
1214 if (ecom1
== NULL
&& ecom2
== NULL
)
1217 if (ecom1
== NULL
|| ecom2
== NULL
)
1220 if (ecom1
->size
< ecom2
->size
)
1223 /* Every community on com2 needs to be on com1 for this to match */
1224 while (i
< ecom1
->size
&& j
< ecom2
->size
) {
1225 if (memcmp(ecom1
->val
+ i
* ecom1
->unit_size
,
1226 ecom2
->val
+ j
* ecom2
->unit_size
,
1233 if (j
== ecom2
->size
)
1239 /* return first occurence of type */
1240 extern struct ecommunity_val
*ecommunity_lookup(const struct ecommunity
*ecom
,
1241 uint8_t type
, uint8_t subtype
)
1246 /* If the value already exists in the structure return 0. */
1248 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1252 if (p
[0] == type
&& p
[1] == subtype
)
1253 return (struct ecommunity_val
*)p
;
1258 /* remove ext. community matching type and subtype
1259 * return 1 on success ( removed ), 0 otherwise (not present)
1261 bool ecommunity_strip(struct ecommunity
*ecom
, uint8_t type
,
1264 uint8_t *p
, *q
, *new;
1265 uint32_t c
, found
= 0;
1266 /* When this is fist value, just add it. */
1267 if (ecom
== NULL
|| ecom
->val
== NULL
)
1270 /* Check if any existing ext community matches. */
1271 /* Certain extended communities like the Route Target can be present
1272 * multiple times, handle that.
1275 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1276 if (p
[0] == type
&& p
[1] == subtype
)
1279 /* If no matching ext community exists, return. */
1283 /* Handle the case where everything needs to be stripped. */
1284 if (found
== ecom
->size
) {
1285 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1290 /* Strip matching ext community(ies). */
1291 new = XMALLOC(MTYPE_ECOMMUNITY_VAL
,
1292 (ecom
->size
- found
) * ecom
->unit_size
);
1294 for (c
= 0, p
= ecom
->val
; c
< ecom
->size
; c
++, p
+= ecom
->unit_size
) {
1295 if (!(p
[0] == type
&& p
[1] == subtype
)) {
1296 memcpy(q
, p
, ecom
->unit_size
);
1297 q
+= ecom
->unit_size
;
1300 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1302 ecom
->size
-= found
;
1307 * Remove specified extended community value from extended community.
1308 * Returns 1 if value was present (and hence, removed), 0 otherwise.
1310 bool ecommunity_del_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
1313 uint32_t c
, found
= 0;
1315 /* Make sure specified value exists. */
1316 if (ecom
== NULL
|| ecom
->val
== NULL
)
1319 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1320 if (!memcmp(p
, eval
->val
, ecom
->unit_size
)) {
1328 /* Delete the selected value */
1331 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ecom
->unit_size
);
1333 memcpy(p
, ecom
->val
, c
* ecom
->unit_size
);
1334 if ((ecom
->size
- c
) != 0)
1335 memcpy(p
+ (c
)*ecom
->unit_size
,
1336 ecom
->val
+ (c
+ 1) * ecom
->unit_size
,
1337 (ecom
->size
- c
) * ecom
->unit_size
);
1338 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1346 int ecommunity_fill_pbr_action(struct ecommunity_val
*ecom_eval
,
1347 struct bgp_pbr_entry_action
*api
,
1350 if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_RATE
) {
1351 api
->action
= ACTION_TRAFFICRATE
;
1352 api
->u
.r
.rate_info
[3] = ecom_eval
->val
[4];
1353 api
->u
.r
.rate_info
[2] = ecom_eval
->val
[5];
1354 api
->u
.r
.rate_info
[1] = ecom_eval
->val
[6];
1355 api
->u
.r
.rate_info
[0] = ecom_eval
->val
[7];
1356 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_ACTION
) {
1357 api
->action
= ACTION_TRAFFIC_ACTION
;
1358 /* else distribute code is set by default */
1359 if (ecom_eval
->val
[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
))
1360 api
->u
.za
.filter
|= TRAFFIC_ACTION_TERMINATE
;
1362 api
->u
.za
.filter
|= TRAFFIC_ACTION_DISTRIBUTE
;
1363 if (ecom_eval
->val
[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
1364 api
->u
.za
.filter
|= TRAFFIC_ACTION_SAMPLE
;
1366 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_MARKING
) {
1367 api
->action
= ACTION_MARKING
;
1368 api
->u
.marking_dscp
= ecom_eval
->val
[7];
1369 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_VRF
) {
1370 /* must use external function */
1372 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_IP_NH
&&
1374 /* see draft-ietf-idr-flowspec-redirect-ip-02
1375 * Q1: how come a ext. community can host ipv6 address
1376 * Q2 : from cisco documentation:
1377 * Announces the reachability of one or more flowspec NLRI.
1378 * When a BGP speaker receives an UPDATE message with the
1379 * redirect-to-IP extended community, it is expected to
1380 * create a traffic filtering rule for every flow-spec
1381 * NLRI in the message that has this path as its best
1382 * path. The filter entry matches the IP packets
1383 * described in the NLRI field and redirects them or
1384 * copies them towards the IPv4 or IPv6 address specified
1385 * in the 'Network Address of Next- Hop'
1386 * field of the associated MP_REACH_NLRI.
1388 struct ecommunity_ip
*ip_ecom
= (struct ecommunity_ip
*)
1391 api
->u
.zr
.redirect_ip_v4
= ip_ecom
->ip
;
1397 static struct ecommunity
*bgp_aggr_ecommunity_lookup(
1398 struct bgp_aggregate
*aggregate
,
1399 struct ecommunity
*ecommunity
)
1401 return hash_lookup(aggregate
->ecommunity_hash
, ecommunity
);
1404 static void *bgp_aggr_ecommunty_hash_alloc(void *p
)
1406 struct ecommunity
*ref
= (struct ecommunity
*)p
;
1407 struct ecommunity
*ecommunity
= NULL
;
1409 ecommunity
= ecommunity_dup(ref
);
1413 static void bgp_aggr_ecommunity_prepare(struct hash_bucket
*hb
, void *arg
)
1415 struct ecommunity
*hb_ecommunity
= hb
->data
;
1416 struct ecommunity
**aggr_ecommunity
= arg
;
1418 if (*aggr_ecommunity
)
1419 *aggr_ecommunity
= ecommunity_merge(*aggr_ecommunity
,
1422 *aggr_ecommunity
= ecommunity_dup(hb_ecommunity
);
1425 void bgp_aggr_ecommunity_remove(void *arg
)
1427 struct ecommunity
*ecommunity
= arg
;
1429 ecommunity_free(&ecommunity
);
1432 void bgp_compute_aggregate_ecommunity(struct bgp_aggregate
*aggregate
,
1433 struct ecommunity
*ecommunity
)
1435 bgp_compute_aggregate_ecommunity_hash(aggregate
, ecommunity
);
1436 bgp_compute_aggregate_ecommunity_val(aggregate
);
1440 void bgp_compute_aggregate_ecommunity_hash(struct bgp_aggregate
*aggregate
,
1441 struct ecommunity
*ecommunity
)
1443 struct ecommunity
*aggr_ecommunity
= NULL
;
1445 if ((aggregate
== NULL
) || (ecommunity
== NULL
))
1448 /* Create hash if not already created.
1450 if (aggregate
->ecommunity_hash
== NULL
)
1451 aggregate
->ecommunity_hash
= hash_create(
1452 ecommunity_hash_make
, ecommunity_cmp
,
1453 "BGP Aggregator ecommunity hash");
1455 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1456 if (aggr_ecommunity
== NULL
) {
1457 /* Insert ecommunity into hash.
1459 aggr_ecommunity
= hash_get(aggregate
->ecommunity_hash
,
1461 bgp_aggr_ecommunty_hash_alloc
);
1464 /* Increment reference counter.
1466 aggr_ecommunity
->refcnt
++;
1469 void bgp_compute_aggregate_ecommunity_val(struct bgp_aggregate
*aggregate
)
1471 struct ecommunity
*ecommerge
= NULL
;
1473 if (aggregate
== NULL
)
1476 /* Re-compute aggregate's ecommunity.
1478 if (aggregate
->ecommunity
)
1479 ecommunity_free(&aggregate
->ecommunity
);
1480 if (aggregate
->ecommunity_hash
1481 && aggregate
->ecommunity_hash
->count
) {
1482 hash_iterate(aggregate
->ecommunity_hash
,
1483 bgp_aggr_ecommunity_prepare
,
1484 &aggregate
->ecommunity
);
1485 ecommerge
= aggregate
->ecommunity
;
1486 aggregate
->ecommunity
= ecommunity_uniq_sort(ecommerge
);
1488 ecommunity_free(&ecommerge
);
1492 void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate
*aggregate
,
1493 struct ecommunity
*ecommunity
)
1495 struct ecommunity
*aggr_ecommunity
= NULL
;
1496 struct ecommunity
*ret_ecomm
= NULL
;
1499 || (!aggregate
->ecommunity_hash
)
1503 /* Look-up the ecommunity in the hash.
1505 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1506 if (aggr_ecommunity
) {
1507 aggr_ecommunity
->refcnt
--;
1509 if (aggr_ecommunity
->refcnt
== 0) {
1510 ret_ecomm
= hash_release(aggregate
->ecommunity_hash
,
1512 ecommunity_free(&ret_ecomm
);
1513 bgp_compute_aggregate_ecommunity_val(aggregate
);
1518 void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate
*aggregate
,
1519 struct ecommunity
*ecommunity
)
1522 struct ecommunity
*aggr_ecommunity
= NULL
;
1523 struct ecommunity
*ret_ecomm
= NULL
;
1526 || (!aggregate
->ecommunity_hash
)
1530 /* Look-up the ecommunity in the hash.
1532 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1533 if (aggr_ecommunity
) {
1534 aggr_ecommunity
->refcnt
--;
1536 if (aggr_ecommunity
->refcnt
== 0) {
1537 ret_ecomm
= hash_release(aggregate
->ecommunity_hash
,
1539 ecommunity_free(&ret_ecomm
);
1545 * return the BGP link bandwidth extended community, if present;
1546 * the actual bandwidth is returned via param
1548 const uint8_t *ecommunity_linkbw_present(struct ecommunity
*ecom
, uint32_t *bw
)
1550 const uint8_t *eval
;
1556 if (!ecom
|| !ecom
->size
)
1559 for (i
= 0; i
< ecom
->size
; i
++) {
1561 uint8_t type
, sub_type
;
1564 eval
= pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
1568 if ((type
== ECOMMUNITY_ENCODE_AS
||
1569 type
== ECOMMUNITY_ENCODE_AS_NON_TRANS
) &&
1570 sub_type
== ECOMMUNITY_LINK_BANDWIDTH
) {
1571 pnt
+= 2; /* bandwidth is encoded as AS:val */
1572 pnt
= ptr_get_be32(pnt
, &bwval
);
1573 (void)pnt
; /* consume value */
1575 *bw
= ecom
->disable_ieee_floating
1577 : ieee_float_uint32_to_uint32(
1587 struct ecommunity
*ecommunity_replace_linkbw(as_t as
, struct ecommunity
*ecom
,
1589 bool disable_ieee_floating
)
1591 struct ecommunity
*new;
1592 struct ecommunity_val lb_eval
;
1593 const uint8_t *eval
;
1597 /* Nothing to replace if link-bandwidth doesn't exist or
1598 * is non-transitive - just return existing extcommunity.
1601 if (!ecom
|| !ecom
->size
)
1604 eval
= ecommunity_linkbw_present(ecom
, &cur_bw
);
1609 if (type
& ECOMMUNITY_FLAG_NON_TRANSITIVE
)
1612 /* Transitive link-bandwidth exists, replace with the passed
1613 * (cumulative) bandwidth value. We need to create a new
1614 * extcommunity for this - refer to AS-Path replace function
1617 if (cum_bw
> 0xFFFFFFFF)
1618 cum_bw
= 0xFFFFFFFF;
1619 encode_lb_extcomm(as
> BGP_AS_MAX
? BGP_AS_TRANS
: as
, cum_bw
, false,
1620 &lb_eval
, disable_ieee_floating
);
1621 new = ecommunity_dup(ecom
);
1622 ecommunity_add_val(new, &lb_eval
, true, true);