1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* BGP Extended Communities Attribute
3 * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
17 #include "lib/printfrr.h"
19 #include "bgpd/bgpd.h"
20 #include "bgpd/bgp_ecommunity.h"
21 #include "bgpd/bgp_lcommunity.h"
22 #include "bgpd/bgp_aspath.h"
23 #include "bgpd/bgp_flowspec_private.h"
24 #include "bgpd/bgp_pbr.h"
26 /* struct used to dump the rate contained in FS set traffic-rate EC */
32 /* Hash of community attribute. */
33 static struct hash
*ecomhash
;
35 /* Allocate a new ecommunities. */
36 struct ecommunity
*ecommunity_new(void)
38 struct ecommunity
*ecom
;
40 ecom
= (struct ecommunity
*)XCALLOC(MTYPE_ECOMMUNITY
,
41 sizeof(struct ecommunity
));
42 ecom
->unit_size
= ECOMMUNITY_SIZE
;
46 void ecommunity_strfree(char **s
)
48 XFREE(MTYPE_ECOMMUNITY_STR
, *s
);
51 /* Free ecommunities. */
52 void ecommunity_free(struct ecommunity
**ecom
)
57 XFREE(MTYPE_ECOMMUNITY_VAL
, (*ecom
)->val
);
58 XFREE(MTYPE_ECOMMUNITY_STR
, (*ecom
)->str
);
59 XFREE(MTYPE_ECOMMUNITY
, *ecom
);
62 static void ecommunity_hash_free(struct ecommunity
*ecom
)
64 ecommunity_free(&ecom
);
68 /* Add a new Extended Communities value to Extended Communities
69 Attribute structure. When the value is already exists in the
70 structure, we don't add the value. Newly added value is sorted by
71 numerical order. When the value is added to the structure return 1
73 The additional parameters 'unique' and 'overwrite' ensure a particular
74 extended community (based on type and sub-type) is present only
75 once and whether the new value should replace what is existing or
78 static bool ecommunity_add_val_internal(struct ecommunity
*ecom
,
80 bool unique
, bool overwrite
,
84 const struct ecommunity_val
*eval4
= (struct ecommunity_val
*)eval
;
85 const struct ecommunity_val_ipv6
*eval6
=
86 (struct ecommunity_val_ipv6
*)eval
;
88 /* When this is fist value, just add it. */
89 if (ecom
->val
== NULL
) {
91 ecom
->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
,
92 ecom_length_size(ecom
, ecom_size
));
93 memcpy(ecom
->val
, eval
, ecom_size
);
97 /* If the value already exists in the structure return 0. */
98 /* check also if the extended community itself exists. */
101 ins_idx
= UINT32_MAX
;
102 for (uint8_t *p
= ecom
->val
; c
< ecom
->size
;
103 p
+= ecom_size
, c
++) {
105 if (ecom_size
== ECOMMUNITY_SIZE
) {
106 if (p
[0] == eval4
->val
[0] &&
107 p
[1] == eval4
->val
[1]) {
109 memcpy(p
, eval4
->val
,
116 if (p
[0] == eval6
->val
[0] &&
117 p
[1] == eval6
->val
[1]) {
119 memcpy(p
, eval6
->val
,
127 int ret
= memcmp(p
, eval
, ecom_size
);
133 if (ins_idx
== UINT32_MAX
)
138 if (ins_idx
== UINT32_MAX
)
141 /* Add the value to the structure with numerical sorting. */
143 ecom
->val
= XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->val
,
144 ecom_length_size(ecom
, ecom_size
));
146 memmove(ecom
->val
+ ((ins_idx
+ 1) * ecom_size
),
147 ecom
->val
+ (ins_idx
* ecom_size
),
148 (ecom
->size
- 1 - ins_idx
) * ecom_size
);
149 memcpy(ecom
->val
+ (ins_idx
* ecom_size
),
155 /* Add a new Extended Communities value to Extended Communities
156 * Attribute structure. When the value is already exists in the
157 * structure, we don't add the value. Newly added value is sorted by
158 * numerical order. When the value is added to the structure return 1
161 bool ecommunity_add_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
,
162 bool unique
, bool overwrite
)
164 return ecommunity_add_val_internal(ecom
, (const void *)eval
, unique
,
165 overwrite
, ECOMMUNITY_SIZE
);
168 bool ecommunity_add_val_ipv6(struct ecommunity
*ecom
,
169 struct ecommunity_val_ipv6
*eval
,
170 bool unique
, bool overwrite
)
172 return ecommunity_add_val_internal(ecom
, (const void *)eval
, unique
,
173 overwrite
, IPV6_ECOMMUNITY_SIZE
);
176 static struct ecommunity
*
177 ecommunity_uniq_sort_internal(struct ecommunity
*ecom
,
178 unsigned short ecom_size
)
181 struct ecommunity
*new;
187 new = ecommunity_new();
188 new->unit_size
= ecom_size
;
189 new->disable_ieee_floating
= ecom
->disable_ieee_floating
;
191 for (i
= 0; i
< ecom
->size
; i
++) {
192 eval
= (void *)(ecom
->val
+ (i
* ecom_size
));
193 ecommunity_add_val_internal(new, eval
, false, false, ecom_size
);
198 /* This function takes pointer to Extended Communites structure then
199 * create a new Extended Communities structure by uniq and sort each
200 * Extended Communities value.
202 struct ecommunity
*ecommunity_uniq_sort(struct ecommunity
*ecom
)
204 return ecommunity_uniq_sort_internal(ecom
, ECOMMUNITY_SIZE
);
207 /* Parse Extended Communites Attribute in BGP packet. */
208 static struct ecommunity
*ecommunity_parse_internal(uint8_t *pnt
,
209 unsigned short length
,
210 unsigned short size_ecom
,
211 bool disable_ieee_floating
)
213 struct ecommunity tmp
;
214 struct ecommunity
*new;
217 if (length
% size_ecom
)
220 /* Prepare tmporary structure for making a new Extended Communities
222 tmp
.size
= length
/ size_ecom
;
224 tmp
.disable_ieee_floating
= disable_ieee_floating
;
226 /* Create a new Extended Communities Attribute by uniq and sort each
227 Extended Communities value */
228 new = ecommunity_uniq_sort_internal(&tmp
, size_ecom
);
230 return ecommunity_intern(new);
233 struct ecommunity
*ecommunity_parse(uint8_t *pnt
, unsigned short length
,
234 bool disable_ieee_floating
)
236 return ecommunity_parse_internal(pnt
, length
, ECOMMUNITY_SIZE
,
237 disable_ieee_floating
);
240 struct ecommunity
*ecommunity_parse_ipv6(uint8_t *pnt
, unsigned short length
,
241 bool disable_ieee_floating
)
243 return ecommunity_parse_internal(pnt
, length
, IPV6_ECOMMUNITY_SIZE
,
244 disable_ieee_floating
);
247 /* Duplicate the Extended Communities Attribute structure. */
248 struct ecommunity
*ecommunity_dup(struct ecommunity
*ecom
)
250 struct ecommunity
*new;
252 new = XCALLOC(MTYPE_ECOMMUNITY
, sizeof(struct ecommunity
));
253 new->size
= ecom
->size
;
254 new->unit_size
= ecom
->unit_size
;
256 new->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
,
257 ecom
->size
* ecom
->unit_size
);
258 memcpy(new->val
, ecom
->val
,
259 (size_t)ecom
->size
* (size_t)ecom
->unit_size
);
265 /* Return string representation of ecommunities attribute. */
266 char *ecommunity_str(struct ecommunity
*ecom
)
270 ecommunity_ecom2str(ecom
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
274 /* Merge two Extended Communities Attribute structure. */
275 struct ecommunity
*ecommunity_merge(struct ecommunity
*ecom1
,
276 struct ecommunity
*ecom2
)
278 ecom1
->val
= XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom1
->val
,
279 (size_t)(ecom1
->size
+ ecom2
->size
)
280 * (size_t)ecom1
->unit_size
);
282 memcpy(ecom1
->val
+ (ecom1
->size
* ecom1
->unit_size
), ecom2
->val
,
283 (size_t)ecom2
->size
* (size_t)ecom1
->unit_size
);
284 ecom1
->size
+= ecom2
->size
;
289 /* Intern Extended Communities Attribute. */
290 struct ecommunity
*ecommunity_intern(struct ecommunity
*ecom
)
292 struct ecommunity
*find
;
294 assert(ecom
->refcnt
== 0);
295 find
= (struct ecommunity
*)hash_get(ecomhash
, ecom
, hash_alloc_intern
);
297 ecommunity_free(&ecom
);
303 ecommunity_ecom2str(find
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
308 /* Unintern Extended Communities Attribute. */
309 void ecommunity_unintern(struct ecommunity
**ecom
)
311 struct ecommunity
*ret
;
319 /* Pull off from hash. */
320 if ((*ecom
)->refcnt
== 0) {
321 /* Extended community must be in the hash. */
322 ret
= (struct ecommunity
*)hash_release(ecomhash
, *ecom
);
325 ecommunity_free(ecom
);
329 /* Utinity function to make hash key. */
330 unsigned int ecommunity_hash_make(const void *arg
)
332 const struct ecommunity
*ecom
= arg
;
333 int size
= ecom
->size
* ecom
->unit_size
;
335 return jhash(ecom
->val
, size
, 0x564321ab);
338 /* Compare two Extended Communities Attribute structure. */
339 bool ecommunity_cmp(const void *arg1
, const void *arg2
)
341 const struct ecommunity
*ecom1
= arg1
;
342 const struct ecommunity
*ecom2
= arg2
;
344 if (ecom1
== NULL
&& ecom2
== NULL
)
347 if (ecom1
== NULL
|| ecom2
== NULL
)
350 if (ecom1
->unit_size
!= ecom2
->unit_size
)
353 return (ecom1
->size
== ecom2
->size
354 && memcmp(ecom1
->val
, ecom2
->val
, ecom1
->size
*
355 ecom1
->unit_size
) == 0);
358 /* Initialize Extended Comminities related hash. */
359 void ecommunity_init(void)
361 ecomhash
= hash_create(ecommunity_hash_make
, ecommunity_cmp
,
362 "BGP ecommunity hash");
365 void ecommunity_finish(void)
367 hash_clean(ecomhash
, (void (*)(void *))ecommunity_hash_free
);
372 /* Extended Communities token enum. */
373 enum ecommunity_token
{
374 ecommunity_token_unknown
= 0,
376 ecommunity_token_soo
,
377 ecommunity_token_val
,
378 ecommunity_token_rt6
,
379 ecommunity_token_val6
,
382 static const char *ecommunity_origin_validation_state2str(
383 enum ecommunity_origin_validation_states state
)
386 case ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID
:
388 case ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND
:
390 case ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID
:
392 case ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED
:
399 static void ecommunity_origin_validation_state_str(char *buf
, size_t bufsz
,
402 /* Origin Validation State is encoded in the last octet
405 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
406 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
407 * | 0x43 | 0x00 | Reserved |
408 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
409 * | Reserved |validationstate|
410 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
412 uint8_t state
= *(ptr
+ ECOMMUNITY_SIZE
- 3);
414 snprintf(buf
, bufsz
, "OVS:%s",
415 ecommunity_origin_validation_state2str(state
));
417 (void)ptr
; /* consume value */
420 static int ecommunity_encode_internal(uint8_t type
, uint8_t sub_type
,
423 struct in6_addr
*ip6
,
427 struct ecommunity_val
*eval
= (struct ecommunity_val
*)eval_ptr
;
428 struct ecommunity_val_ipv6
*eval6
=
429 (struct ecommunity_val_ipv6
*)eval_ptr
;
432 if (type
== ECOMMUNITY_ENCODE_AS
) {
435 } else if (type
== ECOMMUNITY_ENCODE_IP
436 || type
== ECOMMUNITY_ENCODE_AS4
) {
437 if (val
> UINT16_MAX
)
439 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
&&
440 sub_type
== ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
&&
441 (!ip6
|| val
> UINT16_MAX
)) {
445 /* Fill in the values. */
448 eval
->val
[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE
;
449 eval
->val
[1] = sub_type
;
450 if (type
== ECOMMUNITY_ENCODE_AS
) {
451 eval
->val
[2] = (as
>> 8) & 0xff;
452 eval
->val
[3] = as
& 0xff;
453 eval
->val
[4] = (val
>> 24) & 0xff;
454 eval
->val
[5] = (val
>> 16) & 0xff;
455 eval
->val
[6] = (val
>> 8) & 0xff;
456 eval
->val
[7] = val
& 0xff;
457 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
458 memcpy(&eval
->val
[2], ip
, sizeof(struct in_addr
));
459 eval
->val
[6] = (val
>> 8) & 0xff;
460 eval
->val
[7] = val
& 0xff;
461 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
&&
462 sub_type
== ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
) {
463 memcpy(&eval6
->val
[2], ip6
, sizeof(struct in6_addr
));
464 eval6
->val
[18] = (val
>> 8) & 0xff;
465 eval6
->val
[19] = val
& 0xff;
467 eval
->val
[2] = (as
>> 24) & 0xff;
468 eval
->val
[3] = (as
>> 16) & 0xff;
469 eval
->val
[4] = (as
>> 8) & 0xff;
470 eval
->val
[5] = as
& 0xff;
471 eval
->val
[6] = (val
>> 8) & 0xff;
472 eval
->val
[7] = val
& 0xff;
479 * Encode BGP extended community from passed values. Supports types
480 * defined in RFC 4360 and well-known sub-types.
482 static int ecommunity_encode(uint8_t type
, uint8_t sub_type
, int trans
, as_t as
,
483 struct in_addr ip
, uint32_t val
,
484 struct ecommunity_val
*eval
)
486 return ecommunity_encode_internal(type
, sub_type
, trans
, as
,
487 &ip
, NULL
, val
, (void *)eval
);
490 /* Get next Extended Communities token from the string. */
491 static const char *ecommunity_gettoken(const char *str
,
493 enum ecommunity_token
*token
)
506 char buf
[INET_ADDRSTRLEN
+ 1];
507 struct ecommunity_val
*eval
= (struct ecommunity_val
*)eval_ptr
;
508 /* Skip white space. */
509 while (isspace((unsigned char)*p
)) {
514 /* Check the end of the line. */
518 /* "rt" and "soo" keyword parse. */
519 if (!isdigit((unsigned char)*p
)) {
520 /* "rt" match check. */
521 if (tolower((unsigned char)*p
) == 'r') {
523 if (tolower((unsigned char)*p
) == 't') {
525 if (*p
!= '\0' && tolower((int)*p
) == '6')
526 *token
= ecommunity_token_rt6
;
528 *token
= ecommunity_token_rt
;
531 if (isspace((unsigned char)*p
) || *p
== '\0') {
532 *token
= ecommunity_token_rt
;
537 /* "soo" match check. */
538 else if (tolower((unsigned char)*p
) == 's') {
540 if (tolower((unsigned char)*p
) == 'o') {
542 if (tolower((unsigned char)*p
) == 'o') {
544 *token
= ecommunity_token_soo
;
547 if (isspace((unsigned char)*p
) || *p
== '\0') {
548 *token
= ecommunity_token_soo
;
553 if (isspace((unsigned char)*p
) || *p
== '\0') {
554 *token
= ecommunity_token_soo
;
562 /* What a mess, there are several possibilities:
567 * d) <IPV6>:MN (only with rt6)
569 * A.B.C.D: Four Byte IP
571 * GHJK: Four-byte ASN
573 * OPQR: Four byte value
576 /* IPv6 case : look for last ':' */
577 if (*token
== ecommunity_token_rt6
||
578 *token
== ecommunity_token_val6
) {
581 limit
= endptr
= strrchr(p
, ':');
586 as
= strtoul(endptr
, &endptr
, 10);
587 if (*endptr
!= '\0' || as
== BGP_AS4_MAX
)
590 memcpy(buf
, p
, (limit
- p
));
591 buf
[limit
- p
] = '\0';
592 ret
= inet_pton(AF_INET6
, buf
, &ip6
);
596 ecomm_type
= ECOMMUNITY_ENCODE_TRANS_EXP
;
597 if (ecommunity_encode_internal(ecomm_type
,
598 ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
,
599 1, 0, NULL
, &ip6
, as
, eval_ptr
))
602 *token
= ecommunity_token_val6
;
603 while (isdigit((int)*p
) || *p
== ':' || *p
== '.') {
608 while (isdigit((unsigned char)*p
) || *p
== ':' || *p
== '.') {
616 if ((p
- str
) > INET_ADDRSTRLEN
)
618 memset(buf
, 0, INET_ADDRSTRLEN
+ 1);
619 memcpy(buf
, str
, p
- str
);
622 /* Parsing A.B.C.D in:
625 ret
= inet_aton(buf
, &ip
);
630 as
= strtoul(buf
, &endptr
, 10);
631 if (*endptr
!= '\0' || as
== BGP_AS4_MAX
)
634 } else if (*p
== '.') {
643 /* We're past the IP/ASN part */
652 /* Low digit part must be there. */
653 if (!digit
|| !separator
)
656 /* Encode result into extended community. */
658 ecomm_type
= ECOMMUNITY_ENCODE_IP
;
659 else if (as
> BGP_AS_MAX
)
660 ecomm_type
= ECOMMUNITY_ENCODE_AS4
;
662 ecomm_type
= ECOMMUNITY_ENCODE_AS
;
663 if (ecommunity_encode(ecomm_type
, 0, 1, as
, ip
, val
, eval
))
665 *token
= ecommunity_token_val
;
669 *token
= ecommunity_token_unknown
;
673 static struct ecommunity
*ecommunity_str2com_internal(const char *str
, int type
,
674 int keyword_included
,
675 bool is_ipv6_extcomm
)
677 struct ecommunity
*ecom
= NULL
;
678 enum ecommunity_token token
= ecommunity_token_unknown
;
679 struct ecommunity_val_ipv6 eval
;
683 token
= ecommunity_token_rt6
;
684 while ((str
= ecommunity_gettoken(str
, (void *)&eval
, &token
))) {
686 case ecommunity_token_rt
:
687 case ecommunity_token_rt6
:
688 case ecommunity_token_soo
:
689 if (!keyword_included
|| keyword
) {
691 ecommunity_free(&ecom
);
696 if (token
== ecommunity_token_rt
||
697 token
== ecommunity_token_rt6
) {
698 type
= ECOMMUNITY_ROUTE_TARGET
;
700 if (token
== ecommunity_token_soo
) {
701 type
= ECOMMUNITY_SITE_ORIGIN
;
704 case ecommunity_token_val
:
705 if (keyword_included
) {
707 ecommunity_free(&ecom
);
713 ecom
= ecommunity_new();
715 ecommunity_add_val_internal(ecom
, (void *)&eval
,
719 case ecommunity_token_val6
:
720 if (keyword_included
) {
722 ecommunity_free(&ecom
);
728 ecom
= ecommunity_new();
729 ecom
->unit_size
= IPV6_ECOMMUNITY_SIZE
;
731 ecommunity_add_val_internal(ecom
, (void *)&eval
, false, false,
734 case ecommunity_token_unknown
:
736 ecommunity_free(&ecom
);
743 /* Convert string to extended community attribute.
745 * When type is already known, please specify both str and type. str
746 * should not include keyword such as "rt" and "soo". Type is
747 * ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
748 * keyword_included should be zero.
750 * For example route-map's "set extcommunity" command case:
752 * "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
753 * type = ECOMMUNITY_ROUTE_TARGET
754 * keyword_included = 0
756 * "soo 100:1" -> str = "100:1"
757 * type = ECOMMUNITY_SITE_ORIGIN
758 * keyword_included = 0
760 * When string includes keyword for each extended community value.
761 * Please specify keyword_included as non-zero value.
763 * For example standard extcommunity-list case:
765 * "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
767 * keyword_include = 1
769 struct ecommunity
*ecommunity_str2com(const char *str
, int type
,
770 int keyword_included
)
772 return ecommunity_str2com_internal(str
, type
,
773 keyword_included
, false);
776 struct ecommunity
*ecommunity_str2com_ipv6(const char *str
, int type
,
777 int keyword_included
)
779 return ecommunity_str2com_internal(str
, type
,
780 keyword_included
, true);
783 static int ecommunity_rt_soo_str_internal(char *buf
, size_t bufsz
,
784 const uint8_t *pnt
, int type
,
785 int sub_type
, int format
,
786 unsigned short ecom_size
)
790 char buf_local
[INET6_ADDRSTRLEN
];
792 /* For parse Extended Community attribute tupple. */
793 struct ecommunity_as eas
;
794 struct ecommunity_ip eip
;
795 struct ecommunity_ip6 eip6
;
797 /* Determine prefix for string, if any. */
799 case ECOMMUNITY_FORMAT_COMMUNITY_LIST
:
800 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "rt " : "soo ");
802 case ECOMMUNITY_FORMAT_DISPLAY
:
803 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "RT:" : "SoO:");
805 case ECOMMUNITY_FORMAT_ROUTE_MAP
:
813 /* Put string into buffer. */
814 if (type
== ECOMMUNITY_ENCODE_AS4
) {
815 pnt
= ptr_get_be32(pnt
, &eas
.as
);
816 eas
.val
= (*pnt
++ << 8);
819 len
= snprintf(buf
, bufsz
, "%s%u:%u", prefix
, eas
.as
, eas
.val
);
820 } else if (type
== ECOMMUNITY_ENCODE_AS
) {
821 if (ecom_size
== ECOMMUNITY_SIZE
) {
822 eas
.as
= (*pnt
++ << 8);
824 pnt
= ptr_get_be32(pnt
, &eas
.val
);
826 len
= snprintf(buf
, bufsz
, "%s%u:%u", prefix
, eas
.as
,
829 /* this is an IPv6 ext community
830 * first 16 bytes stands for IPv6 addres
832 memcpy(&eip6
.ip
, pnt
, 16);
834 eip6
.val
= (*pnt
++ << 8);
835 eip6
.val
|= (*pnt
++);
837 inet_ntop(AF_INET6
, &eip6
.ip
, buf_local
,
839 len
= snprintf(buf
, bufsz
, "%s%s:%u", prefix
,
840 buf_local
, eip6
.val
);
842 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
843 memcpy(&eip
.ip
, pnt
, 4);
845 eip
.val
= (*pnt
++ << 8);
848 len
= snprintfrr(buf
, bufsz
, "%s%pI4:%u", prefix
, &eip
.ip
,
858 static int ecommunity_rt_soo_str(char *buf
, size_t bufsz
, const uint8_t *pnt
,
859 int type
, int sub_type
, int format
)
861 return ecommunity_rt_soo_str_internal(buf
, bufsz
, pnt
, type
,
866 /* Helper function to convert IEEE-754 Floating Point to uint32 */
867 static uint32_t ieee_float_uint32_to_uint32(uint32_t u
)
874 return (uint32_t)f
.r
;
877 static int ecommunity_lb_str(char *buf
, size_t bufsz
, const uint8_t *pnt
,
878 bool disable_ieee_floating
)
883 char bps_buf
[20] = {0};
885 #define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8)
886 #define ONE_MBPS_BYTES (1000 * 1000 / 8)
887 #define ONE_KBPS_BYTES (1000 / 8)
891 (void)ptr_get_be32(pnt
, &bw_tmp
);
893 bw
= disable_ieee_floating
? bw_tmp
894 : ieee_float_uint32_to_uint32(bw_tmp
);
896 if (bw
>= ONE_GBPS_BYTES
)
897 snprintf(bps_buf
, sizeof(bps_buf
), "%.3f Gbps",
898 (float)(bw
/ ONE_GBPS_BYTES
));
899 else if (bw
>= ONE_MBPS_BYTES
)
900 snprintf(bps_buf
, sizeof(bps_buf
), "%.3f Mbps",
901 (float)(bw
/ ONE_MBPS_BYTES
));
902 else if (bw
>= ONE_KBPS_BYTES
)
903 snprintf(bps_buf
, sizeof(bps_buf
), "%.3f Kbps",
904 (float)(bw
/ ONE_KBPS_BYTES
));
906 snprintf(bps_buf
, sizeof(bps_buf
), "%u bps", bw
* 8);
908 len
= snprintf(buf
, bufsz
, "LB:%u:%u (%s)", as
, bw
, bps_buf
);
912 /* Convert extended community attribute to string.
914 Due to historical reason of industry standard implementation, there
915 are three types of format.
917 route-map set extcommunity format
918 "rt 100:1 100:2soo 100:3"
921 "rt 100:1 rt 100:2 soo 100:3show [ip] bgp" and extcommunity-list regular expression matching
922 "RT:100:1 RT:100:2 SoO:100:3"
924 For each formath please use below definition for format:
926 ECOMMUNITY_FORMAT_ROUTE_MAP
927 ECOMMUNITY_FORMAT_COMMUNITY_LIST
928 ECOMMUNITY_FORMAT_DISPLAY
930 Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
933 char *ecommunity_ecom2str(struct ecommunity
*ecom
, int format
, int filter
)
938 uint8_t sub_type
= 0;
942 if (!ecom
|| ecom
->size
== 0)
943 return XCALLOC(MTYPE_ECOMMUNITY_STR
, 1);
945 /* ecom strlen + space + null term */
946 str_size
= (ecom
->size
* (ECOMMUNITY_STRLEN
+ 1)) + 1;
947 str_buf
= XCALLOC(MTYPE_ECOMMUNITY_STR
, str_size
);
951 for (i
= 0; i
< ecom
->size
; i
++) {
953 memset(encbuf
, 0x00, sizeof(encbuf
));
955 /* Space between each value. */
957 strlcat(str_buf
, " ", str_size
);
959 /* Retrieve value field */
960 pnt
= ecom
->val
+ (i
* ecom
->unit_size
);
962 /* High-order octet is the type */
965 if (type
== ECOMMUNITY_ENCODE_AS
|| type
== ECOMMUNITY_ENCODE_IP
966 || type
== ECOMMUNITY_ENCODE_AS4
) {
967 /* Low-order octet of type. */
969 if (sub_type
!= ECOMMUNITY_ROUTE_TARGET
970 && sub_type
!= ECOMMUNITY_SITE_ORIGIN
) {
972 ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4
&&
973 type
== ECOMMUNITY_ENCODE_IP
) {
974 struct in_addr
*ipv4
=
975 (struct in_addr
*)pnt
;
976 snprintfrr(encbuf
, sizeof(encbuf
),
977 "NH:%pI4:%d", ipv4
, pnt
[5]);
978 } else if (sub_type
==
979 ECOMMUNITY_LINK_BANDWIDTH
&&
980 type
== ECOMMUNITY_ENCODE_AS
) {
982 encbuf
, sizeof(encbuf
), pnt
,
983 ecom
->disable_ieee_floating
);
987 ecommunity_rt_soo_str(encbuf
, sizeof(encbuf
),
991 } else if (type
== ECOMMUNITY_ENCODE_OPAQUE
) {
992 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
994 if (*pnt
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
) {
996 memcpy(&tunneltype
, pnt
+ 5, 2);
997 tunneltype
= ntohs(tunneltype
);
999 snprintf(encbuf
, sizeof(encbuf
), "ET:%d",
1001 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_DEF_GW
) {
1002 strlcpy(encbuf
, "Default Gateway",
1007 } else if (type
== ECOMMUNITY_ENCODE_EVPN
) {
1008 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
1010 if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC
) {
1011 struct ethaddr rmac
;
1013 memcpy(&rmac
, pnt
, ETH_ALEN
);
1015 snprintf(encbuf
, sizeof(encbuf
),
1016 "Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
1017 (uint8_t)rmac
.octet
[0],
1018 (uint8_t)rmac
.octet
[1],
1019 (uint8_t)rmac
.octet
[2],
1020 (uint8_t)rmac
.octet
[3],
1021 (uint8_t)rmac
.octet
[4],
1022 (uint8_t)rmac
.octet
[5]);
1024 == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY
) {
1026 uint8_t flags
= *++pnt
;
1028 memcpy(&seqnum
, pnt
+ 2, 4);
1029 seqnum
= ntohl(seqnum
);
1031 snprintf(encbuf
, sizeof(encbuf
), "MM:%u",
1036 ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY
))
1037 strlcat(encbuf
, ", sticky MAC",
1039 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ND
) {
1040 uint8_t flags
= *++pnt
;
1044 ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG
))
1045 strlcpy(encbuf
, "ND:Router Flag",
1049 ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG
))
1050 strlcpy(encbuf
, "ND:Proxy",
1053 == ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT
) {
1057 memcpy(&mac
, pnt
, ETH_ALEN
);
1060 "ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x",
1061 (uint8_t)mac
.octet
[0],
1062 (uint8_t)mac
.octet
[1],
1063 (uint8_t)mac
.octet
[2],
1064 (uint8_t)mac
.octet
[3],
1065 (uint8_t)mac
.octet
[4],
1066 (uint8_t)mac
.octet
[5]);
1068 == ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL
) {
1069 uint8_t flags
= *++pnt
;
1072 sizeof(encbuf
), "ESI-label-Rt:%s",
1074 ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG
) ?
1077 == ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION
) {
1083 memcpy(&bmap
, pnt
+ 2, 2);
1085 memcpy(&pref
, pnt
+ 5, 2);
1090 encbuf
, sizeof(encbuf
),
1091 "DF: (alg: %u, bmap: 0x%x pref: %u)",
1094 snprintf(encbuf
, sizeof(encbuf
),
1095 "DF: (alg: %u, pref: %u)", alg
,
1099 } else if (type
== ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) {
1101 if (sub_type
== ECOMMUNITY_REDIRECT_IP_NH
) {
1102 snprintf(encbuf
, sizeof(encbuf
),
1103 "FS:redirect IP 0x%x", *(pnt
+ 5));
1106 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
||
1107 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
1108 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
) {
1111 if (sub_type
== ECOMMUNITY_ROUTE_TARGET
) {
1112 char buf
[ECOMMUNITY_STRLEN
];
1114 memset(buf
, 0, sizeof(buf
));
1115 ecommunity_rt_soo_str_internal(buf
, sizeof(buf
),
1116 (const uint8_t *)pnt
,
1118 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1119 ECOMMUNITY_ROUTE_TARGET
,
1122 snprintf(encbuf
, sizeof(encbuf
), "%s", buf
);
1123 } else if (sub_type
==
1124 ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
) {
1127 memset(buf
, 0, sizeof(buf
));
1128 ecommunity_rt_soo_str_internal(buf
, sizeof(buf
),
1129 (const uint8_t *)pnt
,
1131 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1132 ECOMMUNITY_ROUTE_TARGET
,
1133 ECOMMUNITY_FORMAT_DISPLAY
,
1135 snprintf(encbuf
, sizeof(encbuf
),
1136 "FS:redirect VRF %s", buf
);
1137 } else if (sub_type
== ECOMMUNITY_REDIRECT_VRF
) {
1140 memset(buf
, 0, sizeof(buf
));
1141 ecommunity_rt_soo_str(buf
, sizeof(buf
),
1142 (const uint8_t *)pnt
,
1144 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1145 ECOMMUNITY_ROUTE_TARGET
,
1146 ECOMMUNITY_FORMAT_DISPLAY
);
1147 snprintf(encbuf
, sizeof(encbuf
),
1148 "FS:redirect VRF %s", buf
);
1149 snprintf(encbuf
, sizeof(encbuf
),
1150 "FS:redirect VRF %s", buf
);
1151 } else if (type
!= ECOMMUNITY_ENCODE_TRANS_EXP
)
1153 else if (sub_type
== ECOMMUNITY_TRAFFIC_ACTION
) {
1157 1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
)
1158 strlcpy(action
, "terminate (apply)",
1161 strlcpy(action
, "eval stops",
1165 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
1166 strlcat(action
, ", sample",
1170 snprintf(encbuf
, sizeof(encbuf
), "FS:action %s",
1172 } else if (sub_type
== ECOMMUNITY_TRAFFIC_RATE
) {
1173 union traffic_rate data
;
1175 data
.rate_byte
[3] = *(pnt
+2);
1176 data
.rate_byte
[2] = *(pnt
+3);
1177 data
.rate_byte
[1] = *(pnt
+4);
1178 data
.rate_byte
[0] = *(pnt
+5);
1179 snprintf(encbuf
, sizeof(encbuf
), "FS:rate %f",
1181 } else if (sub_type
== ECOMMUNITY_TRAFFIC_MARKING
) {
1182 snprintf(encbuf
, sizeof(encbuf
),
1183 "FS:marking %u", *(pnt
+ 5));
1186 } else if (type
== ECOMMUNITY_ENCODE_AS_NON_TRANS
) {
1188 if (sub_type
== ECOMMUNITY_LINK_BANDWIDTH
)
1189 ecommunity_lb_str(encbuf
, sizeof(encbuf
), pnt
,
1190 ecom
->disable_ieee_floating
);
1193 } else if (type
== ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS
) {
1195 if (sub_type
== ECOMMUNITY_ORIGIN_VALIDATION_STATE
)
1196 ecommunity_origin_validation_state_str(
1197 encbuf
, sizeof(encbuf
), pnt
);
1206 snprintf(encbuf
, sizeof(encbuf
), "UNK:%d, %d", type
,
1209 int r
= strlcat(str_buf
, encbuf
, str_size
);
1210 assert(r
< str_size
);
1216 bool ecommunity_include(struct ecommunity
*e1
, struct ecommunity
*e2
)
1222 for (i
= 0; i
< e1
->size
; ++i
) {
1223 for (j
= 0; j
< e2
->size
; ++j
) {
1224 if (!memcmp(e1
->val
+ (i
* e1
->unit_size
),
1225 e2
->val
+ (j
* e2
->unit_size
),
1233 bool ecommunity_match(const struct ecommunity
*ecom1
,
1234 const struct ecommunity
*ecom2
)
1239 if (ecom1
== NULL
&& ecom2
== NULL
)
1242 if (ecom1
== NULL
|| ecom2
== NULL
)
1245 if (ecom1
->size
< ecom2
->size
)
1248 /* Every community on com2 needs to be on com1 for this to match */
1249 while (i
< ecom1
->size
&& j
< ecom2
->size
) {
1250 if (memcmp(ecom1
->val
+ i
* ecom1
->unit_size
,
1251 ecom2
->val
+ j
* ecom2
->unit_size
,
1258 if (j
== ecom2
->size
)
1264 /* return first occurence of type */
1265 extern struct ecommunity_val
*ecommunity_lookup(const struct ecommunity
*ecom
,
1266 uint8_t type
, uint8_t subtype
)
1271 /* If the value already exists in the structure return 0. */
1273 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1277 if (p
[0] == type
&& p
[1] == subtype
)
1278 return (struct ecommunity_val
*)p
;
1283 /* remove ext. community matching type and subtype
1284 * return 1 on success ( removed ), 0 otherwise (not present)
1286 bool ecommunity_strip(struct ecommunity
*ecom
, uint8_t type
,
1289 uint8_t *p
, *q
, *new;
1290 uint32_t c
, found
= 0;
1291 /* When this is fist value, just add it. */
1292 if (ecom
== NULL
|| ecom
->val
== NULL
)
1295 /* Check if any existing ext community matches. */
1296 /* Certain extended communities like the Route Target can be present
1297 * multiple times, handle that.
1300 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1301 if (p
[0] == type
&& p
[1] == subtype
)
1304 /* If no matching ext community exists, return. */
1308 /* Handle the case where everything needs to be stripped. */
1309 if (found
== ecom
->size
) {
1310 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1315 /* Strip matching ext community(ies). */
1316 new = XMALLOC(MTYPE_ECOMMUNITY_VAL
,
1317 (ecom
->size
- found
) * ecom
->unit_size
);
1319 for (c
= 0, p
= ecom
->val
; c
< ecom
->size
; c
++, p
+= ecom
->unit_size
) {
1320 if (!(p
[0] == type
&& p
[1] == subtype
)) {
1321 memcpy(q
, p
, ecom
->unit_size
);
1322 q
+= ecom
->unit_size
;
1325 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1327 ecom
->size
-= found
;
1332 * Remove specified extended community value from extended community.
1333 * Returns 1 if value was present (and hence, removed), 0 otherwise.
1335 bool ecommunity_del_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
1338 uint32_t c
, found
= 0;
1340 /* Make sure specified value exists. */
1341 if (ecom
== NULL
|| ecom
->val
== NULL
)
1344 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1345 if (!memcmp(p
, eval
->val
, ecom
->unit_size
)) {
1353 /* Delete the selected value */
1356 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ecom
->unit_size
);
1358 memcpy(p
, ecom
->val
, c
* ecom
->unit_size
);
1359 if ((ecom
->size
- c
) != 0)
1360 memcpy(p
+ (c
)*ecom
->unit_size
,
1361 ecom
->val
+ (c
+ 1) * ecom
->unit_size
,
1362 (ecom
->size
- c
) * ecom
->unit_size
);
1363 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1366 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1371 int ecommunity_fill_pbr_action(struct ecommunity_val
*ecom_eval
,
1372 struct bgp_pbr_entry_action
*api
,
1375 if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_RATE
) {
1376 api
->action
= ACTION_TRAFFICRATE
;
1377 api
->u
.r
.rate_info
[3] = ecom_eval
->val
[4];
1378 api
->u
.r
.rate_info
[2] = ecom_eval
->val
[5];
1379 api
->u
.r
.rate_info
[1] = ecom_eval
->val
[6];
1380 api
->u
.r
.rate_info
[0] = ecom_eval
->val
[7];
1381 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_ACTION
) {
1382 api
->action
= ACTION_TRAFFIC_ACTION
;
1383 /* else distribute code is set by default */
1384 if (ecom_eval
->val
[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
))
1385 api
->u
.za
.filter
|= TRAFFIC_ACTION_TERMINATE
;
1387 api
->u
.za
.filter
|= TRAFFIC_ACTION_DISTRIBUTE
;
1388 if (ecom_eval
->val
[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
1389 api
->u
.za
.filter
|= TRAFFIC_ACTION_SAMPLE
;
1391 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_MARKING
) {
1392 api
->action
= ACTION_MARKING
;
1393 api
->u
.marking_dscp
= ecom_eval
->val
[7];
1394 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_VRF
) {
1395 /* must use external function */
1397 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_IP_NH
&&
1399 /* see draft-ietf-idr-flowspec-redirect-ip-02
1400 * Q1: how come a ext. community can host ipv6 address
1401 * Q2 : from cisco documentation:
1402 * Announces the reachability of one or more flowspec NLRI.
1403 * When a BGP speaker receives an UPDATE message with the
1404 * redirect-to-IP extended community, it is expected to
1405 * create a traffic filtering rule for every flow-spec
1406 * NLRI in the message that has this path as its best
1407 * path. The filter entry matches the IP packets
1408 * described in the NLRI field and redirects them or
1409 * copies them towards the IPv4 or IPv6 address specified
1410 * in the 'Network Address of Next- Hop'
1411 * field of the associated MP_REACH_NLRI.
1413 struct ecommunity_ip
*ip_ecom
= (struct ecommunity_ip
*)
1416 api
->u
.zr
.redirect_ip_v4
= ip_ecom
->ip
;
1422 static struct ecommunity
*bgp_aggr_ecommunity_lookup(
1423 struct bgp_aggregate
*aggregate
,
1424 struct ecommunity
*ecommunity
)
1426 return hash_lookup(aggregate
->ecommunity_hash
, ecommunity
);
1429 static void *bgp_aggr_ecommunty_hash_alloc(void *p
)
1431 struct ecommunity
*ref
= (struct ecommunity
*)p
;
1432 struct ecommunity
*ecommunity
= NULL
;
1434 ecommunity
= ecommunity_dup(ref
);
1438 static void bgp_aggr_ecommunity_prepare(struct hash_bucket
*hb
, void *arg
)
1440 struct ecommunity
*hb_ecommunity
= hb
->data
;
1441 struct ecommunity
**aggr_ecommunity
= arg
;
1443 if (*aggr_ecommunity
)
1444 *aggr_ecommunity
= ecommunity_merge(*aggr_ecommunity
,
1447 *aggr_ecommunity
= ecommunity_dup(hb_ecommunity
);
1450 void bgp_aggr_ecommunity_remove(void *arg
)
1452 struct ecommunity
*ecommunity
= arg
;
1454 ecommunity_free(&ecommunity
);
1457 void bgp_compute_aggregate_ecommunity(struct bgp_aggregate
*aggregate
,
1458 struct ecommunity
*ecommunity
)
1460 bgp_compute_aggregate_ecommunity_hash(aggregate
, ecommunity
);
1461 bgp_compute_aggregate_ecommunity_val(aggregate
);
1465 void bgp_compute_aggregate_ecommunity_hash(struct bgp_aggregate
*aggregate
,
1466 struct ecommunity
*ecommunity
)
1468 struct ecommunity
*aggr_ecommunity
= NULL
;
1470 if ((aggregate
== NULL
) || (ecommunity
== NULL
))
1473 /* Create hash if not already created.
1475 if (aggregate
->ecommunity_hash
== NULL
)
1476 aggregate
->ecommunity_hash
= hash_create(
1477 ecommunity_hash_make
, ecommunity_cmp
,
1478 "BGP Aggregator ecommunity hash");
1480 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1481 if (aggr_ecommunity
== NULL
) {
1482 /* Insert ecommunity into hash.
1484 aggr_ecommunity
= hash_get(aggregate
->ecommunity_hash
,
1486 bgp_aggr_ecommunty_hash_alloc
);
1489 /* Increment reference counter.
1491 aggr_ecommunity
->refcnt
++;
1494 void bgp_compute_aggregate_ecommunity_val(struct bgp_aggregate
*aggregate
)
1496 struct ecommunity
*ecommerge
= NULL
;
1498 if (aggregate
== NULL
)
1501 /* Re-compute aggregate's ecommunity.
1503 if (aggregate
->ecommunity
)
1504 ecommunity_free(&aggregate
->ecommunity
);
1505 if (aggregate
->ecommunity_hash
1506 && aggregate
->ecommunity_hash
->count
) {
1507 hash_iterate(aggregate
->ecommunity_hash
,
1508 bgp_aggr_ecommunity_prepare
,
1509 &aggregate
->ecommunity
);
1510 ecommerge
= aggregate
->ecommunity
;
1511 aggregate
->ecommunity
= ecommunity_uniq_sort(ecommerge
);
1513 ecommunity_free(&ecommerge
);
1517 void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate
*aggregate
,
1518 struct ecommunity
*ecommunity
)
1520 struct ecommunity
*aggr_ecommunity
= NULL
;
1521 struct ecommunity
*ret_ecomm
= NULL
;
1524 || (!aggregate
->ecommunity_hash
)
1528 /* Look-up the ecommunity in the hash.
1530 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1531 if (aggr_ecommunity
) {
1532 aggr_ecommunity
->refcnt
--;
1534 if (aggr_ecommunity
->refcnt
== 0) {
1535 ret_ecomm
= hash_release(aggregate
->ecommunity_hash
,
1537 ecommunity_free(&ret_ecomm
);
1538 bgp_compute_aggregate_ecommunity_val(aggregate
);
1543 void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate
*aggregate
,
1544 struct ecommunity
*ecommunity
)
1547 struct ecommunity
*aggr_ecommunity
= NULL
;
1548 struct ecommunity
*ret_ecomm
= NULL
;
1551 || (!aggregate
->ecommunity_hash
)
1555 /* Look-up the ecommunity in the hash.
1557 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1558 if (aggr_ecommunity
) {
1559 aggr_ecommunity
->refcnt
--;
1561 if (aggr_ecommunity
->refcnt
== 0) {
1562 ret_ecomm
= hash_release(aggregate
->ecommunity_hash
,
1564 ecommunity_free(&ret_ecomm
);
1570 ecommunity_add_origin_validation_state(enum rpki_states rpki_state
,
1571 struct ecommunity
*old
)
1573 struct ecommunity
*new = NULL
;
1574 struct ecommunity ovs_ecomm
= {0};
1575 struct ecommunity_val ovs_eval
;
1577 encode_origin_validation_state(rpki_state
, &ovs_eval
);
1580 new = ecommunity_dup(old
);
1581 ecommunity_add_val(new, &ovs_eval
, true, true);
1583 ecommunity_free(&old
);
1586 ovs_ecomm
.unit_size
= ECOMMUNITY_SIZE
;
1587 ovs_ecomm
.val
= (uint8_t *)&ovs_eval
.val
;
1588 new = ecommunity_dup(&ovs_ecomm
);
1595 * return the BGP link bandwidth extended community, if present;
1596 * the actual bandwidth is returned via param
1598 const uint8_t *ecommunity_linkbw_present(struct ecommunity
*ecom
, uint32_t *bw
)
1600 const uint8_t *eval
;
1606 if (!ecom
|| !ecom
->size
)
1609 for (i
= 0; i
< ecom
->size
; i
++) {
1611 uint8_t type
, sub_type
;
1614 eval
= pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
1618 if ((type
== ECOMMUNITY_ENCODE_AS
||
1619 type
== ECOMMUNITY_ENCODE_AS_NON_TRANS
) &&
1620 sub_type
== ECOMMUNITY_LINK_BANDWIDTH
) {
1621 pnt
+= 2; /* bandwidth is encoded as AS:val */
1622 pnt
= ptr_get_be32(pnt
, &bwval
);
1623 (void)pnt
; /* consume value */
1625 *bw
= ecom
->disable_ieee_floating
1627 : ieee_float_uint32_to_uint32(
1637 struct ecommunity
*ecommunity_replace_linkbw(as_t as
, struct ecommunity
*ecom
,
1639 bool disable_ieee_floating
)
1641 struct ecommunity
*new;
1642 struct ecommunity_val lb_eval
;
1643 const uint8_t *eval
;
1647 /* Nothing to replace if link-bandwidth doesn't exist or
1648 * is non-transitive - just return existing extcommunity.
1651 if (!ecom
|| !ecom
->size
)
1654 eval
= ecommunity_linkbw_present(ecom
, &cur_bw
);
1659 if (type
& ECOMMUNITY_FLAG_NON_TRANSITIVE
)
1662 /* Transitive link-bandwidth exists, replace with the passed
1663 * (cumulative) bandwidth value. We need to create a new
1664 * extcommunity for this - refer to AS-Path replace function
1667 if (cum_bw
> 0xFFFFFFFF)
1668 cum_bw
= 0xFFFFFFFF;
1669 encode_lb_extcomm(as
> BGP_AS_MAX
? BGP_AS_TRANS
: as
, cum_bw
, false,
1670 &lb_eval
, disable_ieee_floating
);
1671 new = ecommunity_dup(ecom
);
1672 ecommunity_add_val(new, &lb_eval
, true, true);