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 const char *ecommunity_origin_validation_state2str(
398 enum ecommunity_origin_validation_states state
)
401 case ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID
:
403 case ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND
:
405 case ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID
:
407 case ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED
:
414 static void ecommunity_origin_validation_state_str(char *buf
, size_t bufsz
,
417 /* Origin Validation State is encoded in the last octet
420 * 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
421 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
422 * | 0x43 | 0x00 | Reserved |
423 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
424 * | Reserved |validationstate|
425 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
427 uint8_t state
= *(ptr
+ ECOMMUNITY_SIZE
- 3);
429 snprintf(buf
, bufsz
, "OVS:%s",
430 ecommunity_origin_validation_state2str(state
));
432 (void)ptr
; /* consume value */
435 static int ecommunity_encode_internal(uint8_t type
, uint8_t sub_type
,
438 struct in6_addr
*ip6
,
442 struct ecommunity_val
*eval
= (struct ecommunity_val
*)eval_ptr
;
443 struct ecommunity_val_ipv6
*eval6
=
444 (struct ecommunity_val_ipv6
*)eval_ptr
;
447 if (type
== ECOMMUNITY_ENCODE_AS
) {
450 } else if (type
== ECOMMUNITY_ENCODE_IP
451 || type
== ECOMMUNITY_ENCODE_AS4
) {
452 if (val
> UINT16_MAX
)
454 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
&&
455 sub_type
== ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
&&
456 (!ip6
|| val
> UINT16_MAX
)) {
460 /* Fill in the values. */
463 eval
->val
[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE
;
464 eval
->val
[1] = sub_type
;
465 if (type
== ECOMMUNITY_ENCODE_AS
) {
466 eval
->val
[2] = (as
>> 8) & 0xff;
467 eval
->val
[3] = as
& 0xff;
468 eval
->val
[4] = (val
>> 24) & 0xff;
469 eval
->val
[5] = (val
>> 16) & 0xff;
470 eval
->val
[6] = (val
>> 8) & 0xff;
471 eval
->val
[7] = val
& 0xff;
472 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
473 memcpy(&eval
->val
[2], ip
, sizeof(struct in_addr
));
474 eval
->val
[6] = (val
>> 8) & 0xff;
475 eval
->val
[7] = val
& 0xff;
476 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
&&
477 sub_type
== ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
) {
478 memcpy(&eval6
->val
[2], ip6
, sizeof(struct in6_addr
));
479 eval6
->val
[18] = (val
>> 8) & 0xff;
480 eval6
->val
[19] = val
& 0xff;
482 eval
->val
[2] = (as
>> 24) & 0xff;
483 eval
->val
[3] = (as
>> 16) & 0xff;
484 eval
->val
[4] = (as
>> 8) & 0xff;
485 eval
->val
[5] = as
& 0xff;
486 eval
->val
[6] = (val
>> 8) & 0xff;
487 eval
->val
[7] = val
& 0xff;
494 * Encode BGP extended community from passed values. Supports types
495 * defined in RFC 4360 and well-known sub-types.
497 static int ecommunity_encode(uint8_t type
, uint8_t sub_type
, int trans
, as_t as
,
498 struct in_addr ip
, uint32_t val
,
499 struct ecommunity_val
*eval
)
501 return ecommunity_encode_internal(type
, sub_type
, trans
, as
,
502 &ip
, NULL
, val
, (void *)eval
);
505 /* Get next Extended Communities token from the string. */
506 static const char *ecommunity_gettoken(const char *str
,
508 enum ecommunity_token
*token
)
521 char buf
[INET_ADDRSTRLEN
+ 1];
522 struct ecommunity_val
*eval
= (struct ecommunity_val
*)eval_ptr
;
523 /* Skip white space. */
524 while (isspace((unsigned char)*p
)) {
529 /* Check the end of the line. */
533 /* "rt" and "soo" keyword parse. */
534 if (!isdigit((unsigned char)*p
)) {
535 /* "rt" match check. */
536 if (tolower((unsigned char)*p
) == 'r') {
538 if (tolower((unsigned char)*p
) == 't') {
540 if (*p
!= '\0' && tolower((int)*p
) == '6')
541 *token
= ecommunity_token_rt6
;
543 *token
= ecommunity_token_rt
;
546 if (isspace((unsigned char)*p
) || *p
== '\0') {
547 *token
= ecommunity_token_rt
;
552 /* "soo" match check. */
553 else if (tolower((unsigned char)*p
) == 's') {
555 if (tolower((unsigned char)*p
) == 'o') {
557 if (tolower((unsigned char)*p
) == 'o') {
559 *token
= ecommunity_token_soo
;
562 if (isspace((unsigned char)*p
) || *p
== '\0') {
563 *token
= ecommunity_token_soo
;
568 if (isspace((unsigned char)*p
) || *p
== '\0') {
569 *token
= ecommunity_token_soo
;
577 /* What a mess, there are several possibilities:
582 * d) <IPV6>:MN (only with rt6)
584 * A.B.C.D: Four Byte IP
586 * GHJK: Four-byte ASN
588 * OPQR: Four byte value
591 /* IPv6 case : look for last ':' */
592 if (*token
== ecommunity_token_rt6
||
593 *token
== ecommunity_token_val6
) {
596 limit
= endptr
= strrchr(p
, ':');
601 as
= strtoul(endptr
, &endptr
, 10);
602 if (*endptr
!= '\0' || as
== BGP_AS4_MAX
)
605 memcpy(buf
, p
, (limit
- p
));
606 buf
[limit
- p
] = '\0';
607 ret
= inet_pton(AF_INET6
, buf
, &ip6
);
611 ecomm_type
= ECOMMUNITY_ENCODE_TRANS_EXP
;
612 if (ecommunity_encode_internal(ecomm_type
,
613 ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
,
614 1, 0, NULL
, &ip6
, as
, eval_ptr
))
617 *token
= ecommunity_token_val6
;
618 while (isdigit((int)*p
) || *p
== ':' || *p
== '.') {
623 while (isdigit((unsigned char)*p
) || *p
== ':' || *p
== '.') {
631 if ((p
- str
) > INET_ADDRSTRLEN
)
633 memset(buf
, 0, INET_ADDRSTRLEN
+ 1);
634 memcpy(buf
, str
, p
- str
);
637 /* Parsing A.B.C.D in:
640 ret
= inet_aton(buf
, &ip
);
645 as
= strtoul(buf
, &endptr
, 10);
646 if (*endptr
!= '\0' || as
== BGP_AS4_MAX
)
649 } else if (*p
== '.') {
658 /* We're past the IP/ASN part */
667 /* Low digit part must be there. */
668 if (!digit
|| !separator
)
671 /* Encode result into extended community. */
673 ecomm_type
= ECOMMUNITY_ENCODE_IP
;
674 else if (as
> BGP_AS_MAX
)
675 ecomm_type
= ECOMMUNITY_ENCODE_AS4
;
677 ecomm_type
= ECOMMUNITY_ENCODE_AS
;
678 if (ecommunity_encode(ecomm_type
, 0, 1, as
, ip
, val
, eval
))
680 *token
= ecommunity_token_val
;
684 *token
= ecommunity_token_unknown
;
688 static struct ecommunity
*ecommunity_str2com_internal(const char *str
, int type
,
689 int keyword_included
,
690 bool is_ipv6_extcomm
)
692 struct ecommunity
*ecom
= NULL
;
693 enum ecommunity_token token
= ecommunity_token_unknown
;
694 struct ecommunity_val_ipv6 eval
;
698 token
= ecommunity_token_rt6
;
699 while ((str
= ecommunity_gettoken(str
, (void *)&eval
, &token
))) {
701 case ecommunity_token_rt
:
702 case ecommunity_token_soo
:
703 if (!keyword_included
|| keyword
) {
705 ecommunity_free(&ecom
);
710 if (token
== ecommunity_token_rt
||
711 token
== ecommunity_token_rt6
) {
712 type
= ECOMMUNITY_ROUTE_TARGET
;
714 if (token
== ecommunity_token_soo
) {
715 type
= ECOMMUNITY_SITE_ORIGIN
;
718 case ecommunity_token_val
:
719 if (keyword_included
) {
721 ecommunity_free(&ecom
);
727 ecom
= ecommunity_new();
729 ecommunity_add_val_internal(ecom
, (void *)&eval
,
733 case ecommunity_token_val6
:
734 if (keyword_included
) {
736 ecommunity_free(&ecom
);
742 ecom
= ecommunity_new();
743 ecom
->unit_size
= IPV6_ECOMMUNITY_SIZE
;
745 ecommunity_add_val_internal(ecom
, (void *)&eval
, false, false,
748 case ecommunity_token_unknown
:
751 ecommunity_free(&ecom
);
758 /* Convert string to extended community attribute.
760 * When type is already known, please specify both str and type. str
761 * should not include keyword such as "rt" and "soo". Type is
762 * ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
763 * keyword_included should be zero.
765 * For example route-map's "set extcommunity" command case:
767 * "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
768 * type = ECOMMUNITY_ROUTE_TARGET
769 * keyword_included = 0
771 * "soo 100:1" -> str = "100:1"
772 * type = ECOMMUNITY_SITE_ORIGIN
773 * keyword_included = 0
775 * When string includes keyword for each extended community value.
776 * Please specify keyword_included as non-zero value.
778 * For example standard extcommunity-list case:
780 * "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
782 * keyword_include = 1
784 struct ecommunity
*ecommunity_str2com(const char *str
, int type
,
785 int keyword_included
)
787 return ecommunity_str2com_internal(str
, type
,
788 keyword_included
, false);
791 struct ecommunity
*ecommunity_str2com_ipv6(const char *str
, int type
,
792 int keyword_included
)
794 return ecommunity_str2com_internal(str
, type
,
795 keyword_included
, true);
798 static int ecommunity_rt_soo_str_internal(char *buf
, size_t bufsz
,
799 const uint8_t *pnt
, int type
,
800 int sub_type
, int format
,
801 unsigned short ecom_size
)
805 char buf_local
[INET6_ADDRSTRLEN
];
807 /* For parse Extended Community attribute tupple. */
808 struct ecommunity_as eas
;
809 struct ecommunity_ip eip
;
810 struct ecommunity_ip6 eip6
;
812 /* Determine prefix for string, if any. */
814 case ECOMMUNITY_FORMAT_COMMUNITY_LIST
:
815 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "rt " : "soo ");
817 case ECOMMUNITY_FORMAT_DISPLAY
:
818 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "RT:" : "SoO:");
820 case ECOMMUNITY_FORMAT_ROUTE_MAP
:
828 /* Put string into buffer. */
829 if (type
== ECOMMUNITY_ENCODE_AS4
) {
830 pnt
= ptr_get_be32(pnt
, &eas
.as
);
831 eas
.val
= (*pnt
++ << 8);
834 len
= snprintf(buf
, bufsz
, "%s%u:%u", prefix
, eas
.as
, eas
.val
);
835 } else if (type
== ECOMMUNITY_ENCODE_AS
) {
836 if (ecom_size
== ECOMMUNITY_SIZE
) {
837 eas
.as
= (*pnt
++ << 8);
839 pnt
= ptr_get_be32(pnt
, &eas
.val
);
841 len
= snprintf(buf
, bufsz
, "%s%u:%u", prefix
, eas
.as
,
844 /* this is an IPv6 ext community
845 * first 16 bytes stands for IPv6 addres
847 memcpy(&eip6
.ip
, pnt
, 16);
849 eip6
.val
= (*pnt
++ << 8);
850 eip6
.val
|= (*pnt
++);
852 inet_ntop(AF_INET6
, &eip6
.ip
, buf_local
,
854 len
= snprintf(buf
, bufsz
, "%s%s:%u", prefix
,
855 buf_local
, eip6
.val
);
857 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
858 memcpy(&eip
.ip
, pnt
, 4);
860 eip
.val
= (*pnt
++ << 8);
863 len
= snprintfrr(buf
, bufsz
, "%s%pI4:%u", prefix
, &eip
.ip
,
873 static int ecommunity_rt_soo_str(char *buf
, size_t bufsz
, const uint8_t *pnt
,
874 int type
, int sub_type
, int format
)
876 return ecommunity_rt_soo_str_internal(buf
, bufsz
, pnt
, type
,
881 /* Helper function to convert IEEE-754 Floating Point to uint32 */
882 static uint32_t ieee_float_uint32_to_uint32(uint32_t u
)
889 return (uint32_t)f
.r
;
892 static int ecommunity_lb_str(char *buf
, size_t bufsz
, const uint8_t *pnt
,
893 bool disable_ieee_floating
)
898 char bps_buf
[20] = {0};
900 #define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8)
901 #define ONE_MBPS_BYTES (1000 * 1000 / 8)
902 #define ONE_KBPS_BYTES (1000 / 8)
906 (void)ptr_get_be32(pnt
, &bw_tmp
);
908 bw
= disable_ieee_floating
? bw_tmp
909 : ieee_float_uint32_to_uint32(bw_tmp
);
911 if (bw
>= ONE_GBPS_BYTES
)
912 snprintf(bps_buf
, sizeof(bps_buf
), "%.3f Gbps",
913 (float)(bw
/ ONE_GBPS_BYTES
));
914 else if (bw
>= ONE_MBPS_BYTES
)
915 snprintf(bps_buf
, sizeof(bps_buf
), "%.3f Mbps",
916 (float)(bw
/ ONE_MBPS_BYTES
));
917 else if (bw
>= ONE_KBPS_BYTES
)
918 snprintf(bps_buf
, sizeof(bps_buf
), "%.3f Kbps",
919 (float)(bw
/ ONE_KBPS_BYTES
));
921 snprintf(bps_buf
, sizeof(bps_buf
), "%u bps", bw
* 8);
923 len
= snprintf(buf
, bufsz
, "LB:%u:%u (%s)", as
, bw
, bps_buf
);
927 /* Convert extended community attribute to string.
929 Due to historical reason of industry standard implementation, there
930 are three types of format.
932 route-map set extcommunity format
933 "rt 100:1 100:2soo 100:3"
936 "rt 100:1 rt 100:2 soo 100:3show [ip] bgp" and extcommunity-list regular expression matching
937 "RT:100:1 RT:100:2 SoO:100:3"
939 For each formath please use below definition for format:
941 ECOMMUNITY_FORMAT_ROUTE_MAP
942 ECOMMUNITY_FORMAT_COMMUNITY_LIST
943 ECOMMUNITY_FORMAT_DISPLAY
945 Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
948 char *ecommunity_ecom2str(struct ecommunity
*ecom
, int format
, int filter
)
953 uint8_t sub_type
= 0;
957 if (!ecom
|| ecom
->size
== 0)
958 return XCALLOC(MTYPE_ECOMMUNITY_STR
, 1);
960 /* ecom strlen + space + null term */
961 str_size
= (ecom
->size
* (ECOMMUNITY_STRLEN
+ 1)) + 1;
962 str_buf
= XCALLOC(MTYPE_ECOMMUNITY_STR
, str_size
);
966 for (i
= 0; i
< ecom
->size
; i
++) {
968 memset(encbuf
, 0x00, sizeof(encbuf
));
970 /* Space between each value. */
972 strlcat(str_buf
, " ", str_size
);
974 /* Retrieve value field */
975 pnt
= ecom
->val
+ (i
* ecom
->unit_size
);
977 /* High-order octet is the type */
980 if (type
== ECOMMUNITY_ENCODE_AS
|| type
== ECOMMUNITY_ENCODE_IP
981 || type
== ECOMMUNITY_ENCODE_AS4
) {
982 /* Low-order octet of type. */
984 if (sub_type
!= ECOMMUNITY_ROUTE_TARGET
985 && sub_type
!= ECOMMUNITY_SITE_ORIGIN
) {
987 ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4
&&
988 type
== ECOMMUNITY_ENCODE_IP
) {
989 struct in_addr
*ipv4
=
990 (struct in_addr
*)pnt
;
991 snprintfrr(encbuf
, sizeof(encbuf
),
992 "NH:%pI4:%d", ipv4
, pnt
[5]);
993 } else if (sub_type
==
994 ECOMMUNITY_LINK_BANDWIDTH
&&
995 type
== ECOMMUNITY_ENCODE_AS
) {
997 encbuf
, sizeof(encbuf
), pnt
,
998 ecom
->disable_ieee_floating
);
1002 ecommunity_rt_soo_str(encbuf
, sizeof(encbuf
),
1003 pnt
, type
, sub_type
,
1006 } else if (type
== ECOMMUNITY_ENCODE_OPAQUE
) {
1007 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
1009 if (*pnt
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
) {
1010 uint16_t tunneltype
;
1011 memcpy(&tunneltype
, pnt
+ 5, 2);
1012 tunneltype
= ntohs(tunneltype
);
1014 snprintf(encbuf
, sizeof(encbuf
), "ET:%d",
1016 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_DEF_GW
) {
1017 strlcpy(encbuf
, "Default Gateway",
1022 } else if (type
== ECOMMUNITY_ENCODE_EVPN
) {
1023 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
1025 if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC
) {
1026 struct ethaddr rmac
;
1028 memcpy(&rmac
, pnt
, ETH_ALEN
);
1030 snprintf(encbuf
, sizeof(encbuf
),
1031 "Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
1032 (uint8_t)rmac
.octet
[0],
1033 (uint8_t)rmac
.octet
[1],
1034 (uint8_t)rmac
.octet
[2],
1035 (uint8_t)rmac
.octet
[3],
1036 (uint8_t)rmac
.octet
[4],
1037 (uint8_t)rmac
.octet
[5]);
1039 == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY
) {
1041 uint8_t flags
= *++pnt
;
1043 memcpy(&seqnum
, pnt
+ 2, 4);
1044 seqnum
= ntohl(seqnum
);
1046 snprintf(encbuf
, sizeof(encbuf
), "MM:%u",
1051 ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY
))
1052 strlcat(encbuf
, ", sticky MAC",
1054 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ND
) {
1055 uint8_t flags
= *++pnt
;
1059 ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG
))
1060 strlcpy(encbuf
, "ND:Router Flag",
1064 ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG
))
1065 strlcpy(encbuf
, "ND:Proxy",
1068 == ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT
) {
1072 memcpy(&mac
, pnt
, ETH_ALEN
);
1075 "ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x",
1076 (uint8_t)mac
.octet
[0],
1077 (uint8_t)mac
.octet
[1],
1078 (uint8_t)mac
.octet
[2],
1079 (uint8_t)mac
.octet
[3],
1080 (uint8_t)mac
.octet
[4],
1081 (uint8_t)mac
.octet
[5]);
1083 == ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL
) {
1084 uint8_t flags
= *++pnt
;
1087 sizeof(encbuf
), "ESI-label-Rt:%s",
1089 ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG
) ?
1092 == ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION
) {
1098 memcpy(&bmap
, pnt
+ 2, 2);
1100 memcpy(&pref
, pnt
+ 5, 2);
1105 encbuf
, sizeof(encbuf
),
1106 "DF: (alg: %u, bmap: 0x%x pref: %u)",
1109 snprintf(encbuf
, sizeof(encbuf
),
1110 "DF: (alg: %u, pref: %u)", alg
,
1114 } else if (type
== ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) {
1116 if (sub_type
== ECOMMUNITY_REDIRECT_IP_NH
) {
1117 snprintf(encbuf
, sizeof(encbuf
),
1118 "FS:redirect IP 0x%x", *(pnt
+ 5));
1121 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
||
1122 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
1123 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
) {
1126 if (sub_type
== ECOMMUNITY_ROUTE_TARGET
) {
1127 char buf
[ECOMMUNITY_STRLEN
];
1129 memset(buf
, 0, sizeof(buf
));
1130 ecommunity_rt_soo_str_internal(buf
, sizeof(buf
),
1131 (const uint8_t *)pnt
,
1133 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1134 ECOMMUNITY_ROUTE_TARGET
,
1137 snprintf(encbuf
, sizeof(encbuf
), "%s", buf
);
1138 } else if (sub_type
==
1139 ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
) {
1142 memset(buf
, 0, sizeof(buf
));
1143 ecommunity_rt_soo_str_internal(buf
, sizeof(buf
),
1144 (const uint8_t *)pnt
,
1146 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1147 ECOMMUNITY_ROUTE_TARGET
,
1148 ECOMMUNITY_FORMAT_DISPLAY
,
1150 snprintf(encbuf
, sizeof(encbuf
),
1151 "FS:redirect VRF %s", buf
);
1152 } else if (sub_type
== ECOMMUNITY_REDIRECT_VRF
) {
1155 memset(buf
, 0, sizeof(buf
));
1156 ecommunity_rt_soo_str(buf
, sizeof(buf
),
1157 (const uint8_t *)pnt
,
1159 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1160 ECOMMUNITY_ROUTE_TARGET
,
1161 ECOMMUNITY_FORMAT_DISPLAY
);
1162 snprintf(encbuf
, sizeof(encbuf
),
1163 "FS:redirect VRF %s", buf
);
1164 snprintf(encbuf
, sizeof(encbuf
),
1165 "FS:redirect VRF %s", buf
);
1166 } else if (type
!= ECOMMUNITY_ENCODE_TRANS_EXP
)
1168 else if (sub_type
== ECOMMUNITY_TRAFFIC_ACTION
) {
1172 1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
)
1173 strlcpy(action
, "terminate (apply)",
1176 strlcpy(action
, "eval stops",
1180 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
1181 strlcat(action
, ", sample",
1185 snprintf(encbuf
, sizeof(encbuf
), "FS:action %s",
1187 } else if (sub_type
== ECOMMUNITY_TRAFFIC_RATE
) {
1188 union traffic_rate data
;
1190 data
.rate_byte
[3] = *(pnt
+2);
1191 data
.rate_byte
[2] = *(pnt
+3);
1192 data
.rate_byte
[1] = *(pnt
+4);
1193 data
.rate_byte
[0] = *(pnt
+5);
1194 snprintf(encbuf
, sizeof(encbuf
), "FS:rate %f",
1196 } else if (sub_type
== ECOMMUNITY_TRAFFIC_MARKING
) {
1197 snprintf(encbuf
, sizeof(encbuf
),
1198 "FS:marking %u", *(pnt
+ 5));
1201 } else if (type
== ECOMMUNITY_ENCODE_AS_NON_TRANS
) {
1203 if (sub_type
== ECOMMUNITY_LINK_BANDWIDTH
)
1204 ecommunity_lb_str(encbuf
, sizeof(encbuf
), pnt
,
1205 ecom
->disable_ieee_floating
);
1208 } else if (type
== ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS
) {
1210 if (sub_type
== ECOMMUNITY_ORIGIN_VALIDATION_STATE
)
1211 ecommunity_origin_validation_state_str(
1212 encbuf
, sizeof(encbuf
), pnt
);
1221 snprintf(encbuf
, sizeof(encbuf
), "UNK:%d, %d", type
,
1224 int r
= strlcat(str_buf
, encbuf
, str_size
);
1225 assert(r
< str_size
);
1231 bool ecommunity_include(struct ecommunity
*e1
, struct ecommunity
*e2
)
1237 for (i
= 0; i
< e1
->size
; ++i
) {
1238 for (j
= 0; j
< e2
->size
; ++j
) {
1239 if (!memcmp(e1
->val
+ (i
* e1
->unit_size
),
1240 e2
->val
+ (j
* e2
->unit_size
),
1248 bool ecommunity_match(const struct ecommunity
*ecom1
,
1249 const struct ecommunity
*ecom2
)
1254 if (ecom1
== NULL
&& ecom2
== NULL
)
1257 if (ecom1
== NULL
|| ecom2
== NULL
)
1260 if (ecom1
->size
< ecom2
->size
)
1263 /* Every community on com2 needs to be on com1 for this to match */
1264 while (i
< ecom1
->size
&& j
< ecom2
->size
) {
1265 if (memcmp(ecom1
->val
+ i
* ecom1
->unit_size
,
1266 ecom2
->val
+ j
* ecom2
->unit_size
,
1273 if (j
== ecom2
->size
)
1279 /* return first occurence of type */
1280 extern struct ecommunity_val
*ecommunity_lookup(const struct ecommunity
*ecom
,
1281 uint8_t type
, uint8_t subtype
)
1286 /* If the value already exists in the structure return 0. */
1288 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1292 if (p
[0] == type
&& p
[1] == subtype
)
1293 return (struct ecommunity_val
*)p
;
1298 /* remove ext. community matching type and subtype
1299 * return 1 on success ( removed ), 0 otherwise (not present)
1301 bool ecommunity_strip(struct ecommunity
*ecom
, uint8_t type
,
1304 uint8_t *p
, *q
, *new;
1305 uint32_t c
, found
= 0;
1306 /* When this is fist value, just add it. */
1307 if (ecom
== NULL
|| ecom
->val
== NULL
)
1310 /* Check if any existing ext community matches. */
1311 /* Certain extended communities like the Route Target can be present
1312 * multiple times, handle that.
1315 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1316 if (p
[0] == type
&& p
[1] == subtype
)
1319 /* If no matching ext community exists, return. */
1323 /* Handle the case where everything needs to be stripped. */
1324 if (found
== ecom
->size
) {
1325 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1330 /* Strip matching ext community(ies). */
1331 new = XMALLOC(MTYPE_ECOMMUNITY_VAL
,
1332 (ecom
->size
- found
) * ecom
->unit_size
);
1334 for (c
= 0, p
= ecom
->val
; c
< ecom
->size
; c
++, p
+= ecom
->unit_size
) {
1335 if (!(p
[0] == type
&& p
[1] == subtype
)) {
1336 memcpy(q
, p
, ecom
->unit_size
);
1337 q
+= ecom
->unit_size
;
1340 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1342 ecom
->size
-= found
;
1347 * Remove specified extended community value from extended community.
1348 * Returns 1 if value was present (and hence, removed), 0 otherwise.
1350 bool ecommunity_del_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
1353 uint32_t c
, found
= 0;
1355 /* Make sure specified value exists. */
1356 if (ecom
== NULL
|| ecom
->val
== NULL
)
1359 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1360 if (!memcmp(p
, eval
->val
, ecom
->unit_size
)) {
1368 /* Delete the selected value */
1371 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ecom
->unit_size
);
1373 memcpy(p
, ecom
->val
, c
* ecom
->unit_size
);
1374 if ((ecom
->size
- c
) != 0)
1375 memcpy(p
+ (c
)*ecom
->unit_size
,
1376 ecom
->val
+ (c
+ 1) * ecom
->unit_size
,
1377 (ecom
->size
- c
) * ecom
->unit_size
);
1378 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1381 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1386 int ecommunity_fill_pbr_action(struct ecommunity_val
*ecom_eval
,
1387 struct bgp_pbr_entry_action
*api
,
1390 if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_RATE
) {
1391 api
->action
= ACTION_TRAFFICRATE
;
1392 api
->u
.r
.rate_info
[3] = ecom_eval
->val
[4];
1393 api
->u
.r
.rate_info
[2] = ecom_eval
->val
[5];
1394 api
->u
.r
.rate_info
[1] = ecom_eval
->val
[6];
1395 api
->u
.r
.rate_info
[0] = ecom_eval
->val
[7];
1396 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_ACTION
) {
1397 api
->action
= ACTION_TRAFFIC_ACTION
;
1398 /* else distribute code is set by default */
1399 if (ecom_eval
->val
[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
))
1400 api
->u
.za
.filter
|= TRAFFIC_ACTION_TERMINATE
;
1402 api
->u
.za
.filter
|= TRAFFIC_ACTION_DISTRIBUTE
;
1403 if (ecom_eval
->val
[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
1404 api
->u
.za
.filter
|= TRAFFIC_ACTION_SAMPLE
;
1406 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_MARKING
) {
1407 api
->action
= ACTION_MARKING
;
1408 api
->u
.marking_dscp
= ecom_eval
->val
[7];
1409 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_VRF
) {
1410 /* must use external function */
1412 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_IP_NH
&&
1414 /* see draft-ietf-idr-flowspec-redirect-ip-02
1415 * Q1: how come a ext. community can host ipv6 address
1416 * Q2 : from cisco documentation:
1417 * Announces the reachability of one or more flowspec NLRI.
1418 * When a BGP speaker receives an UPDATE message with the
1419 * redirect-to-IP extended community, it is expected to
1420 * create a traffic filtering rule for every flow-spec
1421 * NLRI in the message that has this path as its best
1422 * path. The filter entry matches the IP packets
1423 * described in the NLRI field and redirects them or
1424 * copies them towards the IPv4 or IPv6 address specified
1425 * in the 'Network Address of Next- Hop'
1426 * field of the associated MP_REACH_NLRI.
1428 struct ecommunity_ip
*ip_ecom
= (struct ecommunity_ip
*)
1431 api
->u
.zr
.redirect_ip_v4
= ip_ecom
->ip
;
1437 static struct ecommunity
*bgp_aggr_ecommunity_lookup(
1438 struct bgp_aggregate
*aggregate
,
1439 struct ecommunity
*ecommunity
)
1441 return hash_lookup(aggregate
->ecommunity_hash
, ecommunity
);
1444 static void *bgp_aggr_ecommunty_hash_alloc(void *p
)
1446 struct ecommunity
*ref
= (struct ecommunity
*)p
;
1447 struct ecommunity
*ecommunity
= NULL
;
1449 ecommunity
= ecommunity_dup(ref
);
1453 static void bgp_aggr_ecommunity_prepare(struct hash_bucket
*hb
, void *arg
)
1455 struct ecommunity
*hb_ecommunity
= hb
->data
;
1456 struct ecommunity
**aggr_ecommunity
= arg
;
1458 if (*aggr_ecommunity
)
1459 *aggr_ecommunity
= ecommunity_merge(*aggr_ecommunity
,
1462 *aggr_ecommunity
= ecommunity_dup(hb_ecommunity
);
1465 void bgp_aggr_ecommunity_remove(void *arg
)
1467 struct ecommunity
*ecommunity
= arg
;
1469 ecommunity_free(&ecommunity
);
1472 void bgp_compute_aggregate_ecommunity(struct bgp_aggregate
*aggregate
,
1473 struct ecommunity
*ecommunity
)
1475 bgp_compute_aggregate_ecommunity_hash(aggregate
, ecommunity
);
1476 bgp_compute_aggregate_ecommunity_val(aggregate
);
1480 void bgp_compute_aggregate_ecommunity_hash(struct bgp_aggregate
*aggregate
,
1481 struct ecommunity
*ecommunity
)
1483 struct ecommunity
*aggr_ecommunity
= NULL
;
1485 if ((aggregate
== NULL
) || (ecommunity
== NULL
))
1488 /* Create hash if not already created.
1490 if (aggregate
->ecommunity_hash
== NULL
)
1491 aggregate
->ecommunity_hash
= hash_create(
1492 ecommunity_hash_make
, ecommunity_cmp
,
1493 "BGP Aggregator ecommunity hash");
1495 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1496 if (aggr_ecommunity
== NULL
) {
1497 /* Insert ecommunity into hash.
1499 aggr_ecommunity
= hash_get(aggregate
->ecommunity_hash
,
1501 bgp_aggr_ecommunty_hash_alloc
);
1504 /* Increment reference counter.
1506 aggr_ecommunity
->refcnt
++;
1509 void bgp_compute_aggregate_ecommunity_val(struct bgp_aggregate
*aggregate
)
1511 struct ecommunity
*ecommerge
= NULL
;
1513 if (aggregate
== NULL
)
1516 /* Re-compute aggregate's ecommunity.
1518 if (aggregate
->ecommunity
)
1519 ecommunity_free(&aggregate
->ecommunity
);
1520 if (aggregate
->ecommunity_hash
1521 && aggregate
->ecommunity_hash
->count
) {
1522 hash_iterate(aggregate
->ecommunity_hash
,
1523 bgp_aggr_ecommunity_prepare
,
1524 &aggregate
->ecommunity
);
1525 ecommerge
= aggregate
->ecommunity
;
1526 aggregate
->ecommunity
= ecommunity_uniq_sort(ecommerge
);
1528 ecommunity_free(&ecommerge
);
1532 void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate
*aggregate
,
1533 struct ecommunity
*ecommunity
)
1535 struct ecommunity
*aggr_ecommunity
= NULL
;
1536 struct ecommunity
*ret_ecomm
= NULL
;
1539 || (!aggregate
->ecommunity_hash
)
1543 /* Look-up the ecommunity in the hash.
1545 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1546 if (aggr_ecommunity
) {
1547 aggr_ecommunity
->refcnt
--;
1549 if (aggr_ecommunity
->refcnt
== 0) {
1550 ret_ecomm
= hash_release(aggregate
->ecommunity_hash
,
1552 ecommunity_free(&ret_ecomm
);
1553 bgp_compute_aggregate_ecommunity_val(aggregate
);
1558 void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate
*aggregate
,
1559 struct ecommunity
*ecommunity
)
1562 struct ecommunity
*aggr_ecommunity
= NULL
;
1563 struct ecommunity
*ret_ecomm
= NULL
;
1566 || (!aggregate
->ecommunity_hash
)
1570 /* Look-up the ecommunity in the hash.
1572 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1573 if (aggr_ecommunity
) {
1574 aggr_ecommunity
->refcnt
--;
1576 if (aggr_ecommunity
->refcnt
== 0) {
1577 ret_ecomm
= hash_release(aggregate
->ecommunity_hash
,
1579 ecommunity_free(&ret_ecomm
);
1585 ecommunity_add_origin_validation_state(enum rpki_states rpki_state
,
1586 struct ecommunity
*old
)
1588 struct ecommunity
*new = NULL
;
1589 struct ecommunity ovs_ecomm
= {0};
1590 struct ecommunity_val ovs_eval
;
1592 encode_origin_validation_state(rpki_state
, &ovs_eval
);
1595 new = ecommunity_dup(old
);
1596 ecommunity_add_val(new, &ovs_eval
, true, true);
1598 ecommunity_free(&old
);
1601 ovs_ecomm
.unit_size
= ECOMMUNITY_SIZE
;
1602 ovs_ecomm
.val
= (uint8_t *)&ovs_eval
.val
;
1603 new = ecommunity_dup(&ovs_ecomm
);
1610 * return the BGP link bandwidth extended community, if present;
1611 * the actual bandwidth is returned via param
1613 const uint8_t *ecommunity_linkbw_present(struct ecommunity
*ecom
, uint32_t *bw
)
1615 const uint8_t *eval
;
1621 if (!ecom
|| !ecom
->size
)
1624 for (i
= 0; i
< ecom
->size
; i
++) {
1626 uint8_t type
, sub_type
;
1629 eval
= pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
1633 if ((type
== ECOMMUNITY_ENCODE_AS
||
1634 type
== ECOMMUNITY_ENCODE_AS_NON_TRANS
) &&
1635 sub_type
== ECOMMUNITY_LINK_BANDWIDTH
) {
1636 pnt
+= 2; /* bandwidth is encoded as AS:val */
1637 pnt
= ptr_get_be32(pnt
, &bwval
);
1638 (void)pnt
; /* consume value */
1640 *bw
= ecom
->disable_ieee_floating
1642 : ieee_float_uint32_to_uint32(
1652 struct ecommunity
*ecommunity_replace_linkbw(as_t as
, struct ecommunity
*ecom
,
1654 bool disable_ieee_floating
)
1656 struct ecommunity
*new;
1657 struct ecommunity_val lb_eval
;
1658 const uint8_t *eval
;
1662 /* Nothing to replace if link-bandwidth doesn't exist or
1663 * is non-transitive - just return existing extcommunity.
1666 if (!ecom
|| !ecom
->size
)
1669 eval
= ecommunity_linkbw_present(ecom
, &cur_bw
);
1674 if (type
& ECOMMUNITY_FLAG_NON_TRANSITIVE
)
1677 /* Transitive link-bandwidth exists, replace with the passed
1678 * (cumulative) bandwidth value. We need to create a new
1679 * extcommunity for this - refer to AS-Path replace function
1682 if (cum_bw
> 0xFFFFFFFF)
1683 cum_bw
= 0xFFFFFFFF;
1684 encode_lb_extcomm(as
> BGP_AS_MAX
? BGP_AS_TRANS
: as
, cum_bw
, false,
1685 &lb_eval
, disable_ieee_floating
);
1686 new = ecommunity_dup(ecom
);
1687 ecommunity_add_val(new, &lb_eval
, true, true);