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 "bgpd/bgpd.h"
33 #include "bgpd/bgp_ecommunity.h"
34 #include "bgpd/bgp_lcommunity.h"
35 #include "bgpd/bgp_aspath.h"
36 #include "bgpd/bgp_flowspec_private.h"
37 #include "bgpd/bgp_pbr.h"
39 /* struct used to dump the rate contained in FS set traffic-rate EC */
45 /* Hash of community attribute. */
46 static struct hash
*ecomhash
;
48 /* Allocate a new ecommunities. */
49 struct ecommunity
*ecommunity_new(void)
51 return (struct ecommunity
*)XCALLOC(MTYPE_ECOMMUNITY
,
52 sizeof(struct ecommunity
));
55 void ecommunity_strfree(char **s
)
57 XFREE(MTYPE_ECOMMUNITY_STR
, *s
);
60 /* Allocate ecommunities. */
61 void ecommunity_free(struct ecommunity
**ecom
)
64 XFREE(MTYPE_ECOMMUNITY_VAL
, (*ecom
)->val
);
66 XFREE(MTYPE_ECOMMUNITY_STR
, (*ecom
)->str
);
67 XFREE(MTYPE_ECOMMUNITY
, *ecom
);
71 static void ecommunity_hash_free(struct ecommunity
*ecom
)
73 ecommunity_free(&ecom
);
77 /* Add a new Extended Communities value to Extended Communities
78 Attribute structure. When the value is already exists in the
79 structure, we don't add the value. Newly added value is sorted by
80 numerical order. When the value is added to the structure return 1
82 int ecommunity_add_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
88 /* When this is fist value, just add it. */
89 if (ecom
->val
== NULL
) {
91 ecom
->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom_length(ecom
));
92 memcpy(ecom
->val
, eval
->val
, ECOMMUNITY_SIZE
);
96 /* If the value already exists in the structure return 0. */
98 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
99 ret
= memcmp(p
, eval
->val
, ECOMMUNITY_SIZE
);
106 /* Add the value to the structure with numerical sorting. */
109 XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->val
, ecom_length(ecom
));
111 memmove(ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
112 ecom
->val
+ c
* ECOMMUNITY_SIZE
,
113 (ecom
->size
- 1 - c
) * ECOMMUNITY_SIZE
);
114 memcpy(ecom
->val
+ c
* ECOMMUNITY_SIZE
, eval
->val
, ECOMMUNITY_SIZE
);
119 /* This function takes pointer to Extended Communites strucutre then
120 create a new Extended Communities structure by uniq and sort each
121 Extended Communities value. */
122 struct ecommunity
*ecommunity_uniq_sort(struct ecommunity
*ecom
)
125 struct ecommunity
*new;
126 struct ecommunity_val
*eval
;
131 new = ecommunity_new();
133 for (i
= 0; i
< ecom
->size
; i
++) {
134 eval
= (struct ecommunity_val
*)(ecom
->val
135 + (i
* ECOMMUNITY_SIZE
));
136 ecommunity_add_val(new, eval
);
141 /* Parse Extended Communites Attribute in BGP packet. */
142 struct ecommunity
*ecommunity_parse(uint8_t *pnt
, unsigned short length
)
144 struct ecommunity tmp
;
145 struct ecommunity
*new;
148 if (length
% ECOMMUNITY_SIZE
)
151 /* Prepare tmporary structure for making a new Extended Communities
153 tmp
.size
= length
/ ECOMMUNITY_SIZE
;
156 /* Create a new Extended Communities Attribute by uniq and sort each
157 Extended Communities value */
158 new = ecommunity_uniq_sort(&tmp
);
160 return ecommunity_intern(new);
163 /* Duplicate the Extended Communities Attribute structure. */
164 struct ecommunity
*ecommunity_dup(struct ecommunity
*ecom
)
166 struct ecommunity
*new;
168 new = XCALLOC(MTYPE_ECOMMUNITY
, sizeof(struct ecommunity
));
169 new->size
= ecom
->size
;
171 new->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
,
172 ecom
->size
* ECOMMUNITY_SIZE
);
173 memcpy(new->val
, ecom
->val
, ecom
->size
* ECOMMUNITY_SIZE
);
179 /* Retrun string representation of communities attribute. */
180 char *ecommunity_str(struct ecommunity
*ecom
)
184 ecommunity_ecom2str(ecom
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
188 /* Merge two Extended Communities Attribute structure. */
189 struct ecommunity
*ecommunity_merge(struct ecommunity
*ecom1
,
190 struct ecommunity
*ecom2
)
194 XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom1
->val
,
195 (ecom1
->size
+ ecom2
->size
) * ECOMMUNITY_SIZE
);
198 XMALLOC(MTYPE_ECOMMUNITY_VAL
,
199 (ecom1
->size
+ ecom2
->size
) * ECOMMUNITY_SIZE
);
201 memcpy(ecom1
->val
+ (ecom1
->size
* ECOMMUNITY_SIZE
), ecom2
->val
,
202 ecom2
->size
* ECOMMUNITY_SIZE
);
203 ecom1
->size
+= ecom2
->size
;
208 /* Intern Extended Communities Attribute. */
209 struct ecommunity
*ecommunity_intern(struct ecommunity
*ecom
)
211 struct ecommunity
*find
;
213 assert(ecom
->refcnt
== 0);
215 find
= (struct ecommunity
*)hash_get(ecomhash
, ecom
, hash_alloc_intern
);
218 ecommunity_free(&ecom
);
224 ecommunity_ecom2str(find
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
229 /* Unintern Extended Communities Attribute. */
230 void ecommunity_unintern(struct ecommunity
**ecom
)
232 struct ecommunity
*ret
;
237 /* Pull off from hash. */
238 if ((*ecom
)->refcnt
== 0) {
239 /* Extended community must be in the hash. */
240 ret
= (struct ecommunity
*)hash_release(ecomhash
, *ecom
);
243 ecommunity_free(ecom
);
247 /* Utinity function to make hash key. */
248 unsigned int ecommunity_hash_make(void *arg
)
250 const struct ecommunity
*ecom
= arg
;
251 int size
= ecom
->size
* ECOMMUNITY_SIZE
;
253 return jhash(ecom
->val
, size
, 0x564321ab);
256 /* Compare two Extended Communities Attribute structure. */
257 int ecommunity_cmp(const void *arg1
, const void *arg2
)
259 const struct ecommunity
*ecom1
= arg1
;
260 const struct ecommunity
*ecom2
= arg2
;
262 if (ecom1
== NULL
&& ecom2
== NULL
)
265 if (ecom1
== NULL
|| ecom2
== NULL
)
268 return (ecom1
->size
== ecom2
->size
269 && memcmp(ecom1
->val
, ecom2
->val
, ecom1
->size
* ECOMMUNITY_SIZE
)
273 /* Initialize Extended Comminities related hash. */
274 void ecommunity_init(void)
276 ecomhash
= hash_create(ecommunity_hash_make
, ecommunity_cmp
,
277 "BGP ecommunity hash");
280 void ecommunity_finish(void)
282 hash_clean(ecomhash
, (void (*)(void *))ecommunity_hash_free
);
287 /* Extended Communities token enum. */
288 enum ecommunity_token
{
289 ecommunity_token_unknown
= 0,
291 ecommunity_token_soo
,
292 ecommunity_token_val
,
296 * Encode BGP extended community from passed values. Supports types
297 * defined in RFC 4360 and well-known sub-types.
299 static int ecommunity_encode(uint8_t type
, uint8_t sub_type
, int trans
, as_t as
,
300 struct in_addr ip
, uint32_t val
,
301 struct ecommunity_val
*eval
)
304 if (type
== ECOMMUNITY_ENCODE_AS
) {
307 } else if (type
== ECOMMUNITY_ENCODE_IP
308 || type
== ECOMMUNITY_ENCODE_AS4
) {
309 if (val
> UINT16_MAX
)
313 /* Fill in the values. */
316 eval
->val
[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE
;
317 eval
->val
[1] = sub_type
;
318 if (type
== ECOMMUNITY_ENCODE_AS
) {
319 eval
->val
[2] = (as
>> 8) & 0xff;
320 eval
->val
[3] = as
& 0xff;
321 eval
->val
[4] = (val
>> 24) & 0xff;
322 eval
->val
[5] = (val
>> 16) & 0xff;
323 eval
->val
[6] = (val
>> 8) & 0xff;
324 eval
->val
[7] = val
& 0xff;
325 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
326 memcpy(&eval
->val
[2], &ip
, sizeof(struct in_addr
));
327 eval
->val
[6] = (val
>> 8) & 0xff;
328 eval
->val
[7] = val
& 0xff;
330 eval
->val
[2] = (as
>> 24) & 0xff;
331 eval
->val
[3] = (as
>> 16) & 0xff;
332 eval
->val
[4] = (as
>> 8) & 0xff;
333 eval
->val
[5] = as
& 0xff;
334 eval
->val
[6] = (val
>> 8) & 0xff;
335 eval
->val
[7] = val
& 0xff;
341 /* Get next Extended Communities token from the string. */
342 static const char *ecommunity_gettoken(const char *str
,
343 struct ecommunity_val
*eval
,
344 enum ecommunity_token
*token
)
356 char buf
[INET_ADDRSTRLEN
+ 1];
358 /* Skip white space. */
359 while (isspace((int)*p
)) {
364 /* Check the end of the line. */
368 /* "rt" and "soo" keyword parse. */
369 if (!isdigit((int)*p
)) {
370 /* "rt" match check. */
371 if (tolower((int)*p
) == 'r') {
373 if (tolower((int)*p
) == 't') {
375 *token
= ecommunity_token_rt
;
378 if (isspace((int)*p
) || *p
== '\0') {
379 *token
= ecommunity_token_rt
;
384 /* "soo" match check. */
385 else if (tolower((int)*p
) == 's') {
387 if (tolower((int)*p
) == 'o') {
389 if (tolower((int)*p
) == 'o') {
391 *token
= ecommunity_token_soo
;
394 if (isspace((int)*p
) || *p
== '\0') {
395 *token
= ecommunity_token_soo
;
400 if (isspace((int)*p
) || *p
== '\0') {
401 *token
= ecommunity_token_soo
;
409 /* What a mess, there are several possibilities:
415 * A.B.C.D: Four Byte IP
417 * GHJK: Four-byte ASN
419 * OPQR: Four byte value
422 while (isdigit((int)*p
) || *p
== ':' || *p
== '.') {
430 if ((p
- str
) > INET_ADDRSTRLEN
)
432 memset(buf
, 0, INET_ADDRSTRLEN
+ 1);
433 memcpy(buf
, str
, p
- str
);
436 /* Parsing A.B.C.D in:
439 ret
= inet_aton(buf
, &ip
);
444 as
= strtoul(buf
, &endptr
, 10);
445 if (*endptr
!= '\0' || as
== BGP_AS4_MAX
)
448 } else if (*p
== '.') {
457 /* We're past the IP/ASN part */
466 /* Low digit part must be there. */
467 if (!digit
|| !separator
)
470 /* Encode result into extended community. */
472 ecomm_type
= ECOMMUNITY_ENCODE_IP
;
473 else if (as
> BGP_AS_MAX
)
474 ecomm_type
= ECOMMUNITY_ENCODE_AS4
;
476 ecomm_type
= ECOMMUNITY_ENCODE_AS
;
477 if (ecommunity_encode(ecomm_type
, 0, 1, as
, ip
, val
, eval
))
479 *token
= ecommunity_token_val
;
483 *token
= ecommunity_token_unknown
;
487 /* Convert string to extended community attribute.
489 When type is already known, please specify both str and type. str
490 should not include keyword such as "rt" and "soo". Type is
491 ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
492 keyword_included should be zero.
494 For example route-map's "set extcommunity" command case:
496 "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
497 type = ECOMMUNITY_ROUTE_TARGET
500 "soo 100:1" -> str = "100:1"
501 type = ECOMMUNITY_SITE_ORIGIN
504 When string includes keyword for each extended community value.
505 Please specify keyword_included as non-zero value.
507 For example standard extcommunity-list case:
509 "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
513 struct ecommunity
*ecommunity_str2com(const char *str
, int type
,
514 int keyword_included
)
516 struct ecommunity
*ecom
= NULL
;
517 enum ecommunity_token token
= ecommunity_token_unknown
;
518 struct ecommunity_val eval
;
521 while ((str
= ecommunity_gettoken(str
, &eval
, &token
))) {
523 case ecommunity_token_rt
:
524 case ecommunity_token_soo
:
525 if (!keyword_included
|| keyword
) {
527 ecommunity_free(&ecom
);
532 if (token
== ecommunity_token_rt
) {
533 type
= ECOMMUNITY_ROUTE_TARGET
;
535 if (token
== ecommunity_token_soo
) {
536 type
= ECOMMUNITY_SITE_ORIGIN
;
539 case ecommunity_token_val
:
540 if (keyword_included
) {
543 ecommunity_free(&ecom
);
549 ecom
= ecommunity_new();
551 ecommunity_add_val(ecom
, &eval
);
553 case ecommunity_token_unknown
:
556 ecommunity_free(&ecom
);
563 static int ecommunity_rt_soo_str(char *buf
, uint8_t *pnt
, int type
,
564 int sub_type
, int format
)
569 /* For parse Extended Community attribute tupple. */
570 struct ecommunity_as eas
;
571 struct ecommunity_ip eip
;
574 /* Determine prefix for string, if any. */
576 case ECOMMUNITY_FORMAT_COMMUNITY_LIST
:
577 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "rt " : "soo ");
579 case ECOMMUNITY_FORMAT_DISPLAY
:
580 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "RT:" : "SoO:");
582 case ECOMMUNITY_FORMAT_ROUTE_MAP
:
590 /* Put string into buffer. */
591 if (type
== ECOMMUNITY_ENCODE_AS4
) {
592 pnt
= ptr_get_be32(pnt
, &eas
.as
);
593 eas
.val
= (*pnt
++ << 8);
596 len
= sprintf(buf
, "%s%u:%u", prefix
, eas
.as
, eas
.val
);
597 } else if (type
== ECOMMUNITY_ENCODE_AS
) {
598 eas
.as
= (*pnt
++ << 8);
600 pnt
= ptr_get_be32(pnt
, &eas
.val
);
602 len
= sprintf(buf
, "%s%u:%u", prefix
, eas
.as
, eas
.val
);
603 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
604 memcpy(&eip
.ip
, pnt
, 4);
606 eip
.val
= (*pnt
++ << 8);
609 len
= sprintf(buf
, "%s%s:%u", prefix
, inet_ntoa(eip
.ip
),
612 (void)pnt
; /* consume value */
617 /* Convert extended community attribute to string.
619 Due to historical reason of industry standard implementation, there
620 are three types of format.
622 route-map set extcommunity format
627 "rt 100:1 rt 100:2 soo 100:3"
629 "show [ip] bgp" and extcommunity-list regular expression matching
630 "RT:100:1 RT:100:2 SoO:100:3"
632 For each formath please use below definition for format:
634 ECOMMUNITY_FORMAT_ROUTE_MAP
635 ECOMMUNITY_FORMAT_COMMUNITY_LIST
636 ECOMMUNITY_FORMAT_DISPLAY
638 Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
641 char *ecommunity_ecom2str(struct ecommunity
*ecom
, int format
, int filter
)
646 uint8_t sub_type
= 0;
647 #define ECOMMUNITY_STR_DEFAULT_LEN 64
654 if (ecom
->size
== 0) {
655 str_buf
= XMALLOC(MTYPE_ECOMMUNITY_STR
, 1);
660 /* Prepare buffer. */
661 str_buf
= XMALLOC(MTYPE_ECOMMUNITY_STR
, ECOMMUNITY_STR_DEFAULT_LEN
+ 1);
662 str_size
= ECOMMUNITY_STR_DEFAULT_LEN
+ 1;
666 for (i
= 0; i
< ecom
->size
; i
++) {
669 /* Make it sure size is enough. */
670 while (str_pnt
+ ECOMMUNITY_STR_DEFAULT_LEN
>= str_size
) {
672 str_buf
= XREALLOC(MTYPE_ECOMMUNITY_STR
, str_buf
,
676 /* Space between each value. */
678 str_buf
[str_pnt
++] = ' ';
682 pnt
= ecom
->val
+ (i
* 8);
684 /* High-order octet of type. */
687 if (type
== ECOMMUNITY_ENCODE_AS
|| type
== ECOMMUNITY_ENCODE_IP
688 || type
== ECOMMUNITY_ENCODE_AS4
) {
689 /* Low-order octet of type. */
691 if (sub_type
!= ECOMMUNITY_ROUTE_TARGET
692 && sub_type
!= ECOMMUNITY_SITE_ORIGIN
)
695 len
= ecommunity_rt_soo_str(str_buf
+ str_pnt
,
698 } else if (type
== ECOMMUNITY_ENCODE_OPAQUE
) {
699 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
701 if (*pnt
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
) {
703 memcpy(&tunneltype
, pnt
+ 5, 2);
704 tunneltype
= ntohs(tunneltype
);
705 len
= sprintf(str_buf
+ str_pnt
, "ET:%d",
707 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_DEF_GW
) {
708 len
= sprintf(str_buf
+ str_pnt
,
712 } else if (type
== ECOMMUNITY_ENCODE_EVPN
) {
713 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
715 if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC
) {
718 memcpy(&rmac
, pnt
, ETH_ALEN
);
721 "Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
722 (uint8_t)rmac
.octet
[0],
723 (uint8_t)rmac
.octet
[1],
724 (uint8_t)rmac
.octet
[2],
725 (uint8_t)rmac
.octet
[3],
726 (uint8_t)rmac
.octet
[4],
727 (uint8_t)rmac
.octet
[5]);
729 == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY
) {
731 uint8_t flags
= *++pnt
;
733 memcpy(&seqnum
, pnt
+ 2, 4);
734 seqnum
= ntohl(seqnum
);
736 & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY
)
737 len
= sprintf(str_buf
+ str_pnt
,
741 len
= sprintf(str_buf
+ str_pnt
,
745 } else if (type
== ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) {
747 if (sub_type
== ECOMMUNITY_REDIRECT_IP_NH
) {
750 "FS:redirect IP 0x%x", *(pnt
+5));
753 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
||
754 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
755 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
) {
757 if (sub_type
== ECOMMUNITY_REDIRECT_VRF
) {
760 memset(buf
, 0, sizeof(buf
));
761 ecommunity_rt_soo_str(buf
, (uint8_t *)pnt
,
763 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
764 ECOMMUNITY_ROUTE_TARGET
,
765 ECOMMUNITY_FORMAT_DISPLAY
);
766 len
= snprintf(str_buf
+ str_pnt
,
768 "FS:redirect VRF %s", buf
);
769 } else if (type
!= ECOMMUNITY_ENCODE_TRANS_EXP
)
771 else if (sub_type
== ECOMMUNITY_TRAFFIC_ACTION
) {
776 1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
)
777 ptr
+= snprintf(ptr
, sizeof(action
),
778 "terminate (apply)");
780 ptr
+= snprintf(ptr
, sizeof(action
),
783 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
784 snprintf(ptr
, sizeof(action
) -
785 (size_t)(ptr
-action
),
787 len
= snprintf(str_buf
+ str_pnt
,
789 "FS:action %s", action
);
790 } else if (sub_type
== ECOMMUNITY_TRAFFIC_RATE
) {
791 union traffic_rate data
;
793 data
.rate_byte
[3] = *(pnt
+2);
794 data
.rate_byte
[2] = *(pnt
+3);
795 data
.rate_byte
[1] = *(pnt
+4);
796 data
.rate_byte
[0] = *(pnt
+5);
799 "FS:rate %f", data
.rate_float
);
800 } else if (sub_type
== ECOMMUNITY_TRAFFIC_MARKING
) {
803 "FS:marking %u", *(pnt
+5));
812 len
= sprintf(str_buf
+ str_pnt
, "UNK:%d, %d",
822 int ecommunity_match(const struct ecommunity
*ecom1
,
823 const struct ecommunity
*ecom2
)
828 if (ecom1
== NULL
&& ecom2
== NULL
)
831 if (ecom1
== NULL
|| ecom2
== NULL
)
834 if (ecom1
->size
< ecom2
->size
)
837 /* Every community on com2 needs to be on com1 for this to match */
838 while (i
< ecom1
->size
&& j
< ecom2
->size
) {
839 if (memcmp(ecom1
->val
+ i
* ECOMMUNITY_SIZE
,
840 ecom2
->val
+ j
* ECOMMUNITY_SIZE
, ECOMMUNITY_SIZE
)
846 if (j
== ecom2
->size
)
852 /* return first occurence of type */
853 extern struct ecommunity_val
*ecommunity_lookup(const struct ecommunity
*ecom
,
854 uint8_t type
, uint8_t subtype
)
859 /* If the value already exists in the structure return 0. */
861 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
865 if (p
[0] == type
&& p
[1] == subtype
)
866 return (struct ecommunity_val
*)p
;
871 /* remove ext. community matching type and subtype
872 * return 1 on success ( removed ), 0 otherwise (not present)
874 extern int ecommunity_strip(struct ecommunity
*ecom
, uint8_t type
,
879 /* When this is fist value, just add it. */
880 if (ecom
== NULL
|| ecom
->val
== NULL
) {
884 /* If the value already exists in the structure return 0. */
886 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
887 if (p
[0] == type
&& p
[1] == subtype
) {
894 /* Strip The selected value */
896 /* size is reduced. no memmove to do */
897 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ECOMMUNITY_SIZE
);
899 memcpy(p
, ecom
->val
, c
* ECOMMUNITY_SIZE
);
900 if ((ecom
->size
- c
) != 0)
901 memcpy(p
+ (c
)*ECOMMUNITY_SIZE
,
902 ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
903 (ecom
->size
- c
) * ECOMMUNITY_SIZE
);
904 /* shift last ecommunities */
905 XFREE(MTYPE_ECOMMUNITY
, ecom
->val
);
911 * Remove specified extended community value from extended community.
912 * Returns 1 if value was present (and hence, removed), 0 otherwise.
914 int ecommunity_del_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
919 /* Make sure specified value exists. */
920 if (ecom
== NULL
|| ecom
->val
== NULL
)
923 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
924 if (!memcmp(p
, eval
->val
, ECOMMUNITY_SIZE
)) {
932 /* Delete the selected value */
934 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ECOMMUNITY_SIZE
);
936 memcpy(p
, ecom
->val
, c
* ECOMMUNITY_SIZE
);
937 if ((ecom
->size
- c
) != 0)
938 memcpy(p
+ (c
)*ECOMMUNITY_SIZE
,
939 ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
940 (ecom
->size
- c
) * ECOMMUNITY_SIZE
);
941 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
946 int ecommunity_fill_pbr_action(struct ecommunity_val
*ecom_eval
,
947 struct bgp_pbr_entry_action
*api
)
949 if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_RATE
) {
950 api
->action
= ACTION_TRAFFICRATE
;
951 api
->u
.r
.rate_info
[3] = ecom_eval
->val
[4];
952 api
->u
.r
.rate_info
[2] = ecom_eval
->val
[5];
953 api
->u
.r
.rate_info
[1] = ecom_eval
->val
[6];
954 api
->u
.r
.rate_info
[0] = ecom_eval
->val
[7];
955 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_ACTION
) {
956 api
->action
= ACTION_TRAFFIC_ACTION
;
957 /* else distribute code is set by default */
958 if (ecom_eval
->val
[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
))
959 api
->u
.za
.filter
|= TRAFFIC_ACTION_TERMINATE
;
961 api
->u
.za
.filter
|= TRAFFIC_ACTION_DISTRIBUTE
;
962 if (ecom_eval
->val
[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
963 api
->u
.za
.filter
|= TRAFFIC_ACTION_SAMPLE
;
965 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_MARKING
) {
966 api
->action
= ACTION_MARKING
;
967 api
->u
.marking_dscp
= ecom_eval
->val
[7];
968 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_VRF
) {
969 /* must use external function */
971 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_IP_NH
) {
972 /* see draft-ietf-idr-flowspec-redirect-ip-02
973 * Q1: how come a ext. community can host ipv6 address
974 * Q2 : from cisco documentation:
975 * Announces the reachability of one or more flowspec NLRI.
976 * When a BGP speaker receives an UPDATE message with the
977 * redirect-to-IP extended community, it is expected to
978 * create a traffic filtering rule for every flow-spec
979 * NLRI in the message that has this path as its best
980 * path. The filter entry matches the IP packets
981 * described in the NLRI field and redirects them or
982 * copies them towards the IPv4 or IPv6 address specified
983 * in the 'Network Address of Next- Hop'
984 * field of the associated MP_REACH_NLRI.
986 struct ecommunity_ip
*ip_ecom
= (struct ecommunity_ip
*)
989 api
->u
.zr
.redirect_ip_v4
= ip_ecom
->ip
;