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));
805 == ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT
) {
809 memcpy(&mac
, pnt
, ETH_ALEN
);
812 "ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x",
813 (uint8_t)mac
.octet
[0],
814 (uint8_t)mac
.octet
[1],
815 (uint8_t)mac
.octet
[2],
816 (uint8_t)mac
.octet
[3],
817 (uint8_t)mac
.octet
[4],
818 (uint8_t)mac
.octet
[5]);
827 len
= sprintf(str_buf
+ str_pnt
, "UNK:%d, %d",
837 int ecommunity_match(const struct ecommunity
*ecom1
,
838 const struct ecommunity
*ecom2
)
843 if (ecom1
== NULL
&& ecom2
== NULL
)
846 if (ecom1
== NULL
|| ecom2
== NULL
)
849 if (ecom1
->size
< ecom2
->size
)
852 /* Every community on com2 needs to be on com1 for this to match */
853 while (i
< ecom1
->size
&& j
< ecom2
->size
) {
854 if (memcmp(ecom1
->val
+ i
* ECOMMUNITY_SIZE
,
855 ecom2
->val
+ j
* ECOMMUNITY_SIZE
, ECOMMUNITY_SIZE
)
861 if (j
== ecom2
->size
)
867 /* return first occurence of type */
868 extern struct ecommunity_val
*ecommunity_lookup(const struct ecommunity
*ecom
,
869 uint8_t type
, uint8_t subtype
)
874 /* If the value already exists in the structure return 0. */
876 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
880 if (p
[0] == type
&& p
[1] == subtype
)
881 return (struct ecommunity_val
*)p
;
886 /* remove ext. community matching type and subtype
887 * return 1 on success ( removed ), 0 otherwise (not present)
889 extern int ecommunity_strip(struct ecommunity
*ecom
, uint8_t type
,
894 /* When this is fist value, just add it. */
895 if (ecom
== NULL
|| ecom
->val
== NULL
) {
899 /* If the value already exists in the structure return 0. */
901 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
902 if (p
[0] == type
&& p
[1] == subtype
) {
909 /* Strip The selected value */
911 /* size is reduced. no memmove to do */
912 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ECOMMUNITY_SIZE
);
914 memcpy(p
, ecom
->val
, c
* ECOMMUNITY_SIZE
);
915 if ((ecom
->size
- c
) != 0)
916 memcpy(p
+ (c
)*ECOMMUNITY_SIZE
,
917 ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
918 (ecom
->size
- c
) * ECOMMUNITY_SIZE
);
919 /* shift last ecommunities */
920 XFREE(MTYPE_ECOMMUNITY
, ecom
->val
);
926 * Remove specified extended community value from extended community.
927 * Returns 1 if value was present (and hence, removed), 0 otherwise.
929 int ecommunity_del_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
934 /* Make sure specified value exists. */
935 if (ecom
== NULL
|| ecom
->val
== NULL
)
938 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
939 if (!memcmp(p
, eval
->val
, ECOMMUNITY_SIZE
)) {
947 /* Delete the selected value */
949 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ECOMMUNITY_SIZE
);
951 memcpy(p
, ecom
->val
, c
* ECOMMUNITY_SIZE
);
952 if ((ecom
->size
- c
) != 0)
953 memcpy(p
+ (c
)*ECOMMUNITY_SIZE
,
954 ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
955 (ecom
->size
- c
) * ECOMMUNITY_SIZE
);
956 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
961 int ecommunity_fill_pbr_action(struct ecommunity_val
*ecom_eval
,
962 struct bgp_pbr_entry_action
*api
)
964 if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_RATE
) {
965 api
->action
= ACTION_TRAFFICRATE
;
966 api
->u
.r
.rate_info
[3] = ecom_eval
->val
[4];
967 api
->u
.r
.rate_info
[2] = ecom_eval
->val
[5];
968 api
->u
.r
.rate_info
[1] = ecom_eval
->val
[6];
969 api
->u
.r
.rate_info
[0] = ecom_eval
->val
[7];
970 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_ACTION
) {
971 api
->action
= ACTION_TRAFFIC_ACTION
;
972 /* else distribute code is set by default */
973 if (ecom_eval
->val
[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
))
974 api
->u
.za
.filter
|= TRAFFIC_ACTION_TERMINATE
;
976 api
->u
.za
.filter
|= TRAFFIC_ACTION_DISTRIBUTE
;
977 if (ecom_eval
->val
[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
978 api
->u
.za
.filter
|= TRAFFIC_ACTION_SAMPLE
;
980 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_MARKING
) {
981 api
->action
= ACTION_MARKING
;
982 api
->u
.marking_dscp
= ecom_eval
->val
[7];
983 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_VRF
) {
984 /* must use external function */
986 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_IP_NH
) {
987 /* see draft-ietf-idr-flowspec-redirect-ip-02
988 * Q1: how come a ext. community can host ipv6 address
989 * Q2 : from cisco documentation:
990 * Announces the reachability of one or more flowspec NLRI.
991 * When a BGP speaker receives an UPDATE message with the
992 * redirect-to-IP extended community, it is expected to
993 * create a traffic filtering rule for every flow-spec
994 * NLRI in the message that has this path as its best
995 * path. The filter entry matches the IP packets
996 * described in the NLRI field and redirects them or
997 * copies them towards the IPv4 or IPv6 address specified
998 * in the 'Network Address of Next- Hop'
999 * field of the associated MP_REACH_NLRI.
1001 struct ecommunity_ip
*ip_ecom
= (struct ecommunity_ip
*)
1004 api
->u
.zr
.redirect_ip_v4
= ip_ecom
->ip
;