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 char ipv4str
[INET_ADDRSTRLEN
];
993 inet_ntop(AF_INET
, ipv4
,
996 snprintf(encbuf
, sizeof(encbuf
),
997 "NH:%s:%d", ipv4str
, pnt
[5]);
998 } else if (sub_type
==
999 ECOMMUNITY_LINK_BANDWIDTH
&&
1000 type
== ECOMMUNITY_ENCODE_AS
) {
1002 encbuf
, sizeof(encbuf
), pnt
,
1003 ecom
->disable_ieee_floating
);
1007 ecommunity_rt_soo_str(encbuf
, sizeof(encbuf
),
1008 pnt
, type
, sub_type
,
1011 } else if (type
== ECOMMUNITY_ENCODE_OPAQUE
) {
1012 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
1014 if (*pnt
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
) {
1015 uint16_t tunneltype
;
1016 memcpy(&tunneltype
, pnt
+ 5, 2);
1017 tunneltype
= ntohs(tunneltype
);
1019 snprintf(encbuf
, sizeof(encbuf
), "ET:%d",
1021 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_DEF_GW
) {
1022 strlcpy(encbuf
, "Default Gateway",
1027 } else if (type
== ECOMMUNITY_ENCODE_EVPN
) {
1028 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
1030 if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC
) {
1031 struct ethaddr rmac
;
1033 memcpy(&rmac
, pnt
, ETH_ALEN
);
1035 snprintf(encbuf
, sizeof(encbuf
),
1036 "Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
1037 (uint8_t)rmac
.octet
[0],
1038 (uint8_t)rmac
.octet
[1],
1039 (uint8_t)rmac
.octet
[2],
1040 (uint8_t)rmac
.octet
[3],
1041 (uint8_t)rmac
.octet
[4],
1042 (uint8_t)rmac
.octet
[5]);
1044 == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY
) {
1046 uint8_t flags
= *++pnt
;
1048 memcpy(&seqnum
, pnt
+ 2, 4);
1049 seqnum
= ntohl(seqnum
);
1051 snprintf(encbuf
, sizeof(encbuf
), "MM:%u",
1056 ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY
))
1057 strlcat(encbuf
, ", sticky MAC",
1059 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ND
) {
1060 uint8_t flags
= *++pnt
;
1064 ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG
))
1065 strlcpy(encbuf
, "ND:Router Flag",
1069 ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG
))
1070 strlcpy(encbuf
, "ND:Proxy",
1073 == ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT
) {
1077 memcpy(&mac
, pnt
, ETH_ALEN
);
1080 "ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x",
1081 (uint8_t)mac
.octet
[0],
1082 (uint8_t)mac
.octet
[1],
1083 (uint8_t)mac
.octet
[2],
1084 (uint8_t)mac
.octet
[3],
1085 (uint8_t)mac
.octet
[4],
1086 (uint8_t)mac
.octet
[5]);
1088 == ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL
) {
1089 uint8_t flags
= *++pnt
;
1092 sizeof(encbuf
), "ESI-label-Rt:%s",
1094 ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG
) ?
1097 == ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION
) {
1103 memcpy(&bmap
, pnt
+ 2, 2);
1105 memcpy(&pref
, pnt
+ 5, 2);
1110 encbuf
, sizeof(encbuf
),
1111 "DF: (alg: %u, bmap: 0x%x pref: %u)",
1114 snprintf(encbuf
, sizeof(encbuf
),
1115 "DF: (alg: %u, pref: %u)", alg
,
1119 } else if (type
== ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) {
1121 if (sub_type
== ECOMMUNITY_REDIRECT_IP_NH
) {
1122 snprintf(encbuf
, sizeof(encbuf
),
1123 "FS:redirect IP 0x%x", *(pnt
+ 5));
1126 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
||
1127 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
1128 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
) {
1131 if (sub_type
== ECOMMUNITY_ROUTE_TARGET
) {
1132 char buf
[ECOMMUNITY_STRLEN
];
1134 memset(buf
, 0, sizeof(buf
));
1135 ecommunity_rt_soo_str_internal(buf
, sizeof(buf
),
1136 (const uint8_t *)pnt
,
1138 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1139 ECOMMUNITY_ROUTE_TARGET
,
1142 snprintf(encbuf
, sizeof(encbuf
), "%s", buf
);
1143 } else if (sub_type
==
1144 ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6
) {
1147 memset(buf
, 0, sizeof(buf
));
1148 ecommunity_rt_soo_str_internal(buf
, sizeof(buf
),
1149 (const uint8_t *)pnt
,
1151 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1152 ECOMMUNITY_ROUTE_TARGET
,
1153 ECOMMUNITY_FORMAT_DISPLAY
,
1155 snprintf(encbuf
, sizeof(encbuf
),
1156 "FS:redirect VRF %s", buf
);
1157 } else if (sub_type
== ECOMMUNITY_REDIRECT_VRF
) {
1160 memset(buf
, 0, sizeof(buf
));
1161 ecommunity_rt_soo_str(buf
, sizeof(buf
),
1162 (const uint8_t *)pnt
,
1164 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
1165 ECOMMUNITY_ROUTE_TARGET
,
1166 ECOMMUNITY_FORMAT_DISPLAY
);
1167 snprintf(encbuf
, sizeof(encbuf
),
1168 "FS:redirect VRF %s", buf
);
1169 snprintf(encbuf
, sizeof(encbuf
),
1170 "FS:redirect VRF %s", buf
);
1171 } else if (type
!= ECOMMUNITY_ENCODE_TRANS_EXP
)
1173 else if (sub_type
== ECOMMUNITY_TRAFFIC_ACTION
) {
1177 1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
)
1178 strlcpy(action
, "terminate (apply)",
1181 strlcpy(action
, "eval stops",
1185 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
1186 strlcat(action
, ", sample",
1190 snprintf(encbuf
, sizeof(encbuf
), "FS:action %s",
1192 } else if (sub_type
== ECOMMUNITY_TRAFFIC_RATE
) {
1193 union traffic_rate data
;
1195 data
.rate_byte
[3] = *(pnt
+2);
1196 data
.rate_byte
[2] = *(pnt
+3);
1197 data
.rate_byte
[1] = *(pnt
+4);
1198 data
.rate_byte
[0] = *(pnt
+5);
1199 snprintf(encbuf
, sizeof(encbuf
), "FS:rate %f",
1201 } else if (sub_type
== ECOMMUNITY_TRAFFIC_MARKING
) {
1202 snprintf(encbuf
, sizeof(encbuf
),
1203 "FS:marking %u", *(pnt
+ 5));
1206 } else if (type
== ECOMMUNITY_ENCODE_AS_NON_TRANS
) {
1208 if (sub_type
== ECOMMUNITY_LINK_BANDWIDTH
)
1209 ecommunity_lb_str(encbuf
, sizeof(encbuf
), pnt
,
1210 ecom
->disable_ieee_floating
);
1213 } else if (type
== ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS
) {
1215 if (sub_type
== ECOMMUNITY_ORIGIN_VALIDATION_STATE
)
1216 ecommunity_origin_validation_state_str(
1217 encbuf
, sizeof(encbuf
), pnt
);
1226 snprintf(encbuf
, sizeof(encbuf
), "UNK:%d, %d", type
,
1229 int r
= strlcat(str_buf
, encbuf
, str_size
);
1230 assert(r
< str_size
);
1236 bool ecommunity_include(struct ecommunity
*e1
, struct ecommunity
*e2
)
1242 for (i
= 0; i
< e1
->size
; ++i
) {
1243 for (j
= 0; j
< e2
->size
; ++j
) {
1244 if (!memcmp(e1
->val
+ (i
* e1
->unit_size
),
1245 e2
->val
+ (j
* e2
->unit_size
),
1253 bool ecommunity_match(const struct ecommunity
*ecom1
,
1254 const struct ecommunity
*ecom2
)
1259 if (ecom1
== NULL
&& ecom2
== NULL
)
1262 if (ecom1
== NULL
|| ecom2
== NULL
)
1265 if (ecom1
->size
< ecom2
->size
)
1268 /* Every community on com2 needs to be on com1 for this to match */
1269 while (i
< ecom1
->size
&& j
< ecom2
->size
) {
1270 if (memcmp(ecom1
->val
+ i
* ecom1
->unit_size
,
1271 ecom2
->val
+ j
* ecom2
->unit_size
,
1278 if (j
== ecom2
->size
)
1284 /* return first occurence of type */
1285 extern struct ecommunity_val
*ecommunity_lookup(const struct ecommunity
*ecom
,
1286 uint8_t type
, uint8_t subtype
)
1291 /* If the value already exists in the structure return 0. */
1293 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1297 if (p
[0] == type
&& p
[1] == subtype
)
1298 return (struct ecommunity_val
*)p
;
1303 /* remove ext. community matching type and subtype
1304 * return 1 on success ( removed ), 0 otherwise (not present)
1306 bool ecommunity_strip(struct ecommunity
*ecom
, uint8_t type
,
1309 uint8_t *p
, *q
, *new;
1310 uint32_t c
, found
= 0;
1311 /* When this is fist value, just add it. */
1312 if (ecom
== NULL
|| ecom
->val
== NULL
)
1315 /* Check if any existing ext community matches. */
1316 /* Certain extended communities like the Route Target can be present
1317 * multiple times, handle that.
1320 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1321 if (p
[0] == type
&& p
[1] == subtype
)
1324 /* If no matching ext community exists, return. */
1328 /* Handle the case where everything needs to be stripped. */
1329 if (found
== ecom
->size
) {
1330 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1335 /* Strip matching ext community(ies). */
1336 new = XMALLOC(MTYPE_ECOMMUNITY_VAL
,
1337 (ecom
->size
- found
) * ecom
->unit_size
);
1339 for (c
= 0, p
= ecom
->val
; c
< ecom
->size
; c
++, p
+= ecom
->unit_size
) {
1340 if (!(p
[0] == type
&& p
[1] == subtype
)) {
1341 memcpy(q
, p
, ecom
->unit_size
);
1342 q
+= ecom
->unit_size
;
1345 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1347 ecom
->size
-= found
;
1352 * Remove specified extended community value from extended community.
1353 * Returns 1 if value was present (and hence, removed), 0 otherwise.
1355 bool ecommunity_del_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
1358 uint32_t c
, found
= 0;
1360 /* Make sure specified value exists. */
1361 if (ecom
== NULL
|| ecom
->val
== NULL
)
1364 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ecom
->unit_size
, c
++) {
1365 if (!memcmp(p
, eval
->val
, ecom
->unit_size
)) {
1373 /* Delete the selected value */
1376 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ecom
->unit_size
);
1378 memcpy(p
, ecom
->val
, c
* ecom
->unit_size
);
1379 if ((ecom
->size
- c
) != 0)
1380 memcpy(p
+ (c
)*ecom
->unit_size
,
1381 ecom
->val
+ (c
+ 1) * ecom
->unit_size
,
1382 (ecom
->size
- c
) * ecom
->unit_size
);
1383 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1386 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
1391 int ecommunity_fill_pbr_action(struct ecommunity_val
*ecom_eval
,
1392 struct bgp_pbr_entry_action
*api
,
1395 if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_RATE
) {
1396 api
->action
= ACTION_TRAFFICRATE
;
1397 api
->u
.r
.rate_info
[3] = ecom_eval
->val
[4];
1398 api
->u
.r
.rate_info
[2] = ecom_eval
->val
[5];
1399 api
->u
.r
.rate_info
[1] = ecom_eval
->val
[6];
1400 api
->u
.r
.rate_info
[0] = ecom_eval
->val
[7];
1401 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_ACTION
) {
1402 api
->action
= ACTION_TRAFFIC_ACTION
;
1403 /* else distribute code is set by default */
1404 if (ecom_eval
->val
[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
))
1405 api
->u
.za
.filter
|= TRAFFIC_ACTION_TERMINATE
;
1407 api
->u
.za
.filter
|= TRAFFIC_ACTION_DISTRIBUTE
;
1408 if (ecom_eval
->val
[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
1409 api
->u
.za
.filter
|= TRAFFIC_ACTION_SAMPLE
;
1411 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_MARKING
) {
1412 api
->action
= ACTION_MARKING
;
1413 api
->u
.marking_dscp
= ecom_eval
->val
[7];
1414 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_VRF
) {
1415 /* must use external function */
1417 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_IP_NH
&&
1419 /* see draft-ietf-idr-flowspec-redirect-ip-02
1420 * Q1: how come a ext. community can host ipv6 address
1421 * Q2 : from cisco documentation:
1422 * Announces the reachability of one or more flowspec NLRI.
1423 * When a BGP speaker receives an UPDATE message with the
1424 * redirect-to-IP extended community, it is expected to
1425 * create a traffic filtering rule for every flow-spec
1426 * NLRI in the message that has this path as its best
1427 * path. The filter entry matches the IP packets
1428 * described in the NLRI field and redirects them or
1429 * copies them towards the IPv4 or IPv6 address specified
1430 * in the 'Network Address of Next- Hop'
1431 * field of the associated MP_REACH_NLRI.
1433 struct ecommunity_ip
*ip_ecom
= (struct ecommunity_ip
*)
1436 api
->u
.zr
.redirect_ip_v4
= ip_ecom
->ip
;
1442 static struct ecommunity
*bgp_aggr_ecommunity_lookup(
1443 struct bgp_aggregate
*aggregate
,
1444 struct ecommunity
*ecommunity
)
1446 return hash_lookup(aggregate
->ecommunity_hash
, ecommunity
);
1449 static void *bgp_aggr_ecommunty_hash_alloc(void *p
)
1451 struct ecommunity
*ref
= (struct ecommunity
*)p
;
1452 struct ecommunity
*ecommunity
= NULL
;
1454 ecommunity
= ecommunity_dup(ref
);
1458 static void bgp_aggr_ecommunity_prepare(struct hash_bucket
*hb
, void *arg
)
1460 struct ecommunity
*hb_ecommunity
= hb
->data
;
1461 struct ecommunity
**aggr_ecommunity
= arg
;
1463 if (*aggr_ecommunity
)
1464 *aggr_ecommunity
= ecommunity_merge(*aggr_ecommunity
,
1467 *aggr_ecommunity
= ecommunity_dup(hb_ecommunity
);
1470 void bgp_aggr_ecommunity_remove(void *arg
)
1472 struct ecommunity
*ecommunity
= arg
;
1474 ecommunity_free(&ecommunity
);
1477 void bgp_compute_aggregate_ecommunity(struct bgp_aggregate
*aggregate
,
1478 struct ecommunity
*ecommunity
)
1480 bgp_compute_aggregate_ecommunity_hash(aggregate
, ecommunity
);
1481 bgp_compute_aggregate_ecommunity_val(aggregate
);
1485 void bgp_compute_aggregate_ecommunity_hash(struct bgp_aggregate
*aggregate
,
1486 struct ecommunity
*ecommunity
)
1488 struct ecommunity
*aggr_ecommunity
= NULL
;
1490 if ((aggregate
== NULL
) || (ecommunity
== NULL
))
1493 /* Create hash if not already created.
1495 if (aggregate
->ecommunity_hash
== NULL
)
1496 aggregate
->ecommunity_hash
= hash_create(
1497 ecommunity_hash_make
, ecommunity_cmp
,
1498 "BGP Aggregator ecommunity hash");
1500 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1501 if (aggr_ecommunity
== NULL
) {
1502 /* Insert ecommunity into hash.
1504 aggr_ecommunity
= hash_get(aggregate
->ecommunity_hash
,
1506 bgp_aggr_ecommunty_hash_alloc
);
1509 /* Increment reference counter.
1511 aggr_ecommunity
->refcnt
++;
1514 void bgp_compute_aggregate_ecommunity_val(struct bgp_aggregate
*aggregate
)
1516 struct ecommunity
*ecommerge
= NULL
;
1518 if (aggregate
== NULL
)
1521 /* Re-compute aggregate's ecommunity.
1523 if (aggregate
->ecommunity
)
1524 ecommunity_free(&aggregate
->ecommunity
);
1525 if (aggregate
->ecommunity_hash
1526 && aggregate
->ecommunity_hash
->count
) {
1527 hash_iterate(aggregate
->ecommunity_hash
,
1528 bgp_aggr_ecommunity_prepare
,
1529 &aggregate
->ecommunity
);
1530 ecommerge
= aggregate
->ecommunity
;
1531 aggregate
->ecommunity
= ecommunity_uniq_sort(ecommerge
);
1533 ecommunity_free(&ecommerge
);
1537 void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate
*aggregate
,
1538 struct ecommunity
*ecommunity
)
1540 struct ecommunity
*aggr_ecommunity
= NULL
;
1541 struct ecommunity
*ret_ecomm
= NULL
;
1544 || (!aggregate
->ecommunity_hash
)
1548 /* Look-up the ecommunity in the hash.
1550 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1551 if (aggr_ecommunity
) {
1552 aggr_ecommunity
->refcnt
--;
1554 if (aggr_ecommunity
->refcnt
== 0) {
1555 ret_ecomm
= hash_release(aggregate
->ecommunity_hash
,
1557 ecommunity_free(&ret_ecomm
);
1558 bgp_compute_aggregate_ecommunity_val(aggregate
);
1563 void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate
*aggregate
,
1564 struct ecommunity
*ecommunity
)
1567 struct ecommunity
*aggr_ecommunity
= NULL
;
1568 struct ecommunity
*ret_ecomm
= NULL
;
1571 || (!aggregate
->ecommunity_hash
)
1575 /* Look-up the ecommunity in the hash.
1577 aggr_ecommunity
= bgp_aggr_ecommunity_lookup(aggregate
, ecommunity
);
1578 if (aggr_ecommunity
) {
1579 aggr_ecommunity
->refcnt
--;
1581 if (aggr_ecommunity
->refcnt
== 0) {
1582 ret_ecomm
= hash_release(aggregate
->ecommunity_hash
,
1584 ecommunity_free(&ret_ecomm
);
1590 ecommunity_add_origin_validation_state(enum rpki_states rpki_state
,
1591 struct ecommunity
*old
)
1593 struct ecommunity
*new = NULL
;
1594 struct ecommunity ovs_ecomm
= {0};
1595 struct ecommunity_val ovs_eval
;
1597 encode_origin_validation_state(rpki_state
, &ovs_eval
);
1600 new = ecommunity_dup(old
);
1601 ecommunity_add_val(new, &ovs_eval
, true, true);
1603 ecommunity_free(&old
);
1606 ovs_ecomm
.unit_size
= ECOMMUNITY_SIZE
;
1607 ovs_ecomm
.val
= (uint8_t *)&ovs_eval
.val
;
1608 new = ecommunity_dup(&ovs_ecomm
);
1615 * return the BGP link bandwidth extended community, if present;
1616 * the actual bandwidth is returned via param
1618 const uint8_t *ecommunity_linkbw_present(struct ecommunity
*ecom
, uint32_t *bw
)
1620 const uint8_t *eval
;
1626 if (!ecom
|| !ecom
->size
)
1629 for (i
= 0; i
< ecom
->size
; i
++) {
1631 uint8_t type
, sub_type
;
1634 eval
= pnt
= (ecom
->val
+ (i
* ECOMMUNITY_SIZE
));
1638 if ((type
== ECOMMUNITY_ENCODE_AS
||
1639 type
== ECOMMUNITY_ENCODE_AS_NON_TRANS
) &&
1640 sub_type
== ECOMMUNITY_LINK_BANDWIDTH
) {
1641 pnt
+= 2; /* bandwidth is encoded as AS:val */
1642 pnt
= ptr_get_be32(pnt
, &bwval
);
1643 (void)pnt
; /* consume value */
1645 *bw
= ecom
->disable_ieee_floating
1647 : ieee_float_uint32_to_uint32(
1657 struct ecommunity
*ecommunity_replace_linkbw(as_t as
, struct ecommunity
*ecom
,
1659 bool disable_ieee_floating
)
1661 struct ecommunity
*new;
1662 struct ecommunity_val lb_eval
;
1663 const uint8_t *eval
;
1667 /* Nothing to replace if link-bandwidth doesn't exist or
1668 * is non-transitive - just return existing extcommunity.
1671 if (!ecom
|| !ecom
->size
)
1674 eval
= ecommunity_linkbw_present(ecom
, &cur_bw
);
1679 if (type
& ECOMMUNITY_FLAG_NON_TRANSITIVE
)
1682 /* Transitive link-bandwidth exists, replace with the passed
1683 * (cumulative) bandwidth value. We need to create a new
1684 * extcommunity for this - refer to AS-Path replace function
1687 if (cum_bw
> 0xFFFFFFFF)
1688 cum_bw
= 0xFFFFFFFF;
1689 encode_lb_extcomm(as
> BGP_AS_MAX
? BGP_AS_TRANS
: as
, cum_bw
, false,
1690 &lb_eval
, disable_ieee_floating
);
1691 new = ecommunity_dup(ecom
);
1692 ecommunity_add_val(new, &lb_eval
, true, true);