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
);
70 static void ecommunity_hash_free(struct ecommunity
*ecom
)
72 ecommunity_free(&ecom
);
76 /* Add a new Extended Communities value to Extended Communities
77 Attribute structure. When the value is already exists in the
78 structure, we don't add the value. Newly added value is sorted by
79 numerical order. When the value is added to the structure return 1
81 int ecommunity_add_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
87 /* When this is fist value, just add it. */
88 if (ecom
->val
== NULL
) {
90 ecom
->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom_length(ecom
));
91 memcpy(ecom
->val
, eval
->val
, ECOMMUNITY_SIZE
);
95 /* If the value already exists in the structure return 0. */
97 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
98 ret
= memcmp(p
, eval
->val
, ECOMMUNITY_SIZE
);
105 /* Add the value to the structure with numerical sorting. */
108 XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->val
, ecom_length(ecom
));
110 memmove(ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
111 ecom
->val
+ c
* ECOMMUNITY_SIZE
,
112 (ecom
->size
- 1 - c
) * ECOMMUNITY_SIZE
);
113 memcpy(ecom
->val
+ c
* ECOMMUNITY_SIZE
, eval
->val
, ECOMMUNITY_SIZE
);
118 /* This function takes pointer to Extended Communites strucutre then
119 create a new Extended Communities structure by uniq and sort each
120 Extended Communities value. */
121 struct ecommunity
*ecommunity_uniq_sort(struct ecommunity
*ecom
)
124 struct ecommunity
*new;
125 struct ecommunity_val
*eval
;
130 new = ecommunity_new();
132 for (i
= 0; i
< ecom
->size
; i
++) {
133 eval
= (struct ecommunity_val
*)(ecom
->val
134 + (i
* ECOMMUNITY_SIZE
));
135 ecommunity_add_val(new, eval
);
140 /* Parse Extended Communites Attribute in BGP packet. */
141 struct ecommunity
*ecommunity_parse(uint8_t *pnt
, unsigned short length
)
143 struct ecommunity tmp
;
144 struct ecommunity
*new;
147 if (length
% ECOMMUNITY_SIZE
)
150 /* Prepare tmporary structure for making a new Extended Communities
152 tmp
.size
= length
/ ECOMMUNITY_SIZE
;
155 /* Create a new Extended Communities Attribute by uniq and sort each
156 Extended Communities value */
157 new = ecommunity_uniq_sort(&tmp
);
159 return ecommunity_intern(new);
162 /* Duplicate the Extended Communities Attribute structure. */
163 struct ecommunity
*ecommunity_dup(struct ecommunity
*ecom
)
165 struct ecommunity
*new;
167 new = XCALLOC(MTYPE_ECOMMUNITY
, sizeof(struct ecommunity
));
168 new->size
= ecom
->size
;
170 new->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
,
171 ecom
->size
* ECOMMUNITY_SIZE
);
172 memcpy(new->val
, ecom
->val
, ecom
->size
* ECOMMUNITY_SIZE
);
178 /* Retrun string representation of communities attribute. */
179 char *ecommunity_str(struct ecommunity
*ecom
)
183 ecommunity_ecom2str(ecom
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
187 /* Merge two Extended Communities Attribute structure. */
188 struct ecommunity
*ecommunity_merge(struct ecommunity
*ecom1
,
189 struct ecommunity
*ecom2
)
193 XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom1
->val
,
194 (ecom1
->size
+ ecom2
->size
) * ECOMMUNITY_SIZE
);
197 XMALLOC(MTYPE_ECOMMUNITY_VAL
,
198 (ecom1
->size
+ ecom2
->size
) * ECOMMUNITY_SIZE
);
200 memcpy(ecom1
->val
+ (ecom1
->size
* ECOMMUNITY_SIZE
), ecom2
->val
,
201 ecom2
->size
* ECOMMUNITY_SIZE
);
202 ecom1
->size
+= ecom2
->size
;
207 /* Intern Extended Communities Attribute. */
208 struct ecommunity
*ecommunity_intern(struct ecommunity
*ecom
)
210 struct ecommunity
*find
;
212 assert(ecom
->refcnt
== 0);
214 find
= (struct ecommunity
*)hash_get(ecomhash
, ecom
, hash_alloc_intern
);
217 ecommunity_free(&ecom
);
223 ecommunity_ecom2str(find
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
228 /* Unintern Extended Communities Attribute. */
229 void ecommunity_unintern(struct ecommunity
**ecom
)
231 struct ecommunity
*ret
;
236 /* Pull off from hash. */
237 if ((*ecom
)->refcnt
== 0) {
238 /* Extended community must be in the hash. */
239 ret
= (struct ecommunity
*)hash_release(ecomhash
, *ecom
);
242 ecommunity_free(ecom
);
246 /* Utinity function to make hash key. */
247 unsigned int ecommunity_hash_make(void *arg
)
249 const struct ecommunity
*ecom
= arg
;
250 int size
= ecom
->size
* ECOMMUNITY_SIZE
;
252 return jhash(ecom
->val
, size
, 0x564321ab);
255 /* Compare two Extended Communities Attribute structure. */
256 int ecommunity_cmp(const void *arg1
, const void *arg2
)
258 const struct ecommunity
*ecom1
= arg1
;
259 const struct ecommunity
*ecom2
= arg2
;
261 if (ecom1
== NULL
&& ecom2
== NULL
)
264 if (ecom1
== NULL
|| ecom2
== NULL
)
267 return (ecom1
->size
== ecom2
->size
268 && memcmp(ecom1
->val
, ecom2
->val
, ecom1
->size
* ECOMMUNITY_SIZE
)
272 /* Initialize Extended Comminities related hash. */
273 void ecommunity_init(void)
275 ecomhash
= hash_create(ecommunity_hash_make
, ecommunity_cmp
,
276 "BGP ecommunity hash");
279 void ecommunity_finish(void)
281 hash_clean(ecomhash
, (void (*)(void *))ecommunity_hash_free
);
286 /* Extended Communities token enum. */
287 enum ecommunity_token
{
288 ecommunity_token_unknown
= 0,
290 ecommunity_token_soo
,
291 ecommunity_token_val
,
295 * Encode BGP extended community from passed values. Supports types
296 * defined in RFC 4360 and well-known sub-types.
298 static int ecommunity_encode(uint8_t type
, uint8_t sub_type
, int trans
, as_t as
,
299 struct in_addr ip
, uint32_t val
,
300 struct ecommunity_val
*eval
)
303 if (type
== ECOMMUNITY_ENCODE_AS
) {
306 } else if (type
== ECOMMUNITY_ENCODE_IP
307 || type
== ECOMMUNITY_ENCODE_AS4
) {
308 if (val
> UINT16_MAX
)
312 /* Fill in the values. */
315 eval
->val
[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE
;
316 eval
->val
[1] = sub_type
;
317 if (type
== ECOMMUNITY_ENCODE_AS
) {
318 eval
->val
[2] = (as
>> 8) & 0xff;
319 eval
->val
[3] = as
& 0xff;
320 eval
->val
[4] = (val
>> 24) & 0xff;
321 eval
->val
[5] = (val
>> 16) & 0xff;
322 eval
->val
[6] = (val
>> 8) & 0xff;
323 eval
->val
[7] = val
& 0xff;
324 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
325 memcpy(&eval
->val
[2], &ip
, sizeof(struct in_addr
));
326 eval
->val
[6] = (val
>> 8) & 0xff;
327 eval
->val
[7] = val
& 0xff;
329 eval
->val
[2] = (as
>> 24) & 0xff;
330 eval
->val
[3] = (as
>> 16) & 0xff;
331 eval
->val
[4] = (as
>> 8) & 0xff;
332 eval
->val
[5] = as
& 0xff;
333 eval
->val
[6] = (val
>> 8) & 0xff;
334 eval
->val
[7] = val
& 0xff;
340 /* Get next Extended Communities token from the string. */
341 static const char *ecommunity_gettoken(const char *str
,
342 struct ecommunity_val
*eval
,
343 enum ecommunity_token
*token
)
355 char buf
[INET_ADDRSTRLEN
+ 1];
357 /* Skip white space. */
358 while (isspace((int)*p
)) {
363 /* Check the end of the line. */
367 /* "rt" and "soo" keyword parse. */
368 if (!isdigit((int)*p
)) {
369 /* "rt" match check. */
370 if (tolower((int)*p
) == 'r') {
372 if (tolower((int)*p
) == 't') {
374 *token
= ecommunity_token_rt
;
377 if (isspace((int)*p
) || *p
== '\0') {
378 *token
= ecommunity_token_rt
;
383 /* "soo" match check. */
384 else if (tolower((int)*p
) == 's') {
386 if (tolower((int)*p
) == 'o') {
388 if (tolower((int)*p
) == 'o') {
390 *token
= ecommunity_token_soo
;
393 if (isspace((int)*p
) || *p
== '\0') {
394 *token
= ecommunity_token_soo
;
399 if (isspace((int)*p
) || *p
== '\0') {
400 *token
= ecommunity_token_soo
;
408 /* What a mess, there are several possibilities:
414 * A.B.C.D: Four Byte IP
416 * GHJK: Four-byte ASN
418 * OPQR: Four byte value
421 while (isdigit((int)*p
) || *p
== ':' || *p
== '.') {
429 if ((p
- str
) > INET_ADDRSTRLEN
)
431 memset(buf
, 0, INET_ADDRSTRLEN
+ 1);
432 memcpy(buf
, str
, p
- str
);
435 /* Parsing A.B.C.D in:
438 ret
= inet_aton(buf
, &ip
);
443 as
= strtoul(buf
, &endptr
, 10);
444 if (*endptr
!= '\0' || as
== BGP_AS4_MAX
)
447 } else if (*p
== '.') {
456 /* We're past the IP/ASN part */
465 /* Low digit part must be there. */
466 if (!digit
|| !separator
)
469 /* Encode result into extended community. */
471 ecomm_type
= ECOMMUNITY_ENCODE_IP
;
472 else if (as
> BGP_AS_MAX
)
473 ecomm_type
= ECOMMUNITY_ENCODE_AS4
;
475 ecomm_type
= ECOMMUNITY_ENCODE_AS
;
476 if (ecommunity_encode(ecomm_type
, 0, 1, as
, ip
, val
, eval
))
478 *token
= ecommunity_token_val
;
482 *token
= ecommunity_token_unknown
;
486 /* Convert string to extended community attribute.
488 When type is already known, please specify both str and type. str
489 should not include keyword such as "rt" and "soo". Type is
490 ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
491 keyword_included should be zero.
493 For example route-map's "set extcommunity" command case:
495 "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
496 type = ECOMMUNITY_ROUTE_TARGET
499 "soo 100:1" -> str = "100:1"
500 type = ECOMMUNITY_SITE_ORIGIN
503 When string includes keyword for each extended community value.
504 Please specify keyword_included as non-zero value.
506 For example standard extcommunity-list case:
508 "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
512 struct ecommunity
*ecommunity_str2com(const char *str
, int type
,
513 int keyword_included
)
515 struct ecommunity
*ecom
= NULL
;
516 enum ecommunity_token token
= ecommunity_token_unknown
;
517 struct ecommunity_val eval
;
520 while ((str
= ecommunity_gettoken(str
, &eval
, &token
))) {
522 case ecommunity_token_rt
:
523 case ecommunity_token_soo
:
524 if (!keyword_included
|| keyword
) {
526 ecommunity_free(&ecom
);
531 if (token
== ecommunity_token_rt
) {
532 type
= ECOMMUNITY_ROUTE_TARGET
;
534 if (token
== ecommunity_token_soo
) {
535 type
= ECOMMUNITY_SITE_ORIGIN
;
538 case ecommunity_token_val
:
539 if (keyword_included
) {
542 ecommunity_free(&ecom
);
548 ecom
= ecommunity_new();
550 ecommunity_add_val(ecom
, &eval
);
552 case ecommunity_token_unknown
:
555 ecommunity_free(&ecom
);
562 static int ecommunity_rt_soo_str(char *buf
, uint8_t *pnt
, int type
,
563 int sub_type
, int format
)
568 /* For parse Extended Community attribute tupple. */
569 struct ecommunity_as eas
;
570 struct ecommunity_ip eip
;
573 /* Determine prefix for string, if any. */
575 case ECOMMUNITY_FORMAT_COMMUNITY_LIST
:
576 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "rt " : "soo ");
578 case ECOMMUNITY_FORMAT_DISPLAY
:
579 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "RT:" : "SoO:");
581 case ECOMMUNITY_FORMAT_ROUTE_MAP
:
589 /* Put string into buffer. */
590 if (type
== ECOMMUNITY_ENCODE_AS4
) {
591 pnt
= ptr_get_be32(pnt
, &eas
.as
);
592 eas
.val
= (*pnt
++ << 8);
595 len
= sprintf(buf
, "%s%u:%u", prefix
, eas
.as
, eas
.val
);
596 } else if (type
== ECOMMUNITY_ENCODE_AS
) {
597 eas
.as
= (*pnt
++ << 8);
599 pnt
= ptr_get_be32(pnt
, &eas
.val
);
601 len
= sprintf(buf
, "%s%u:%u", prefix
, eas
.as
, eas
.val
);
602 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
603 memcpy(&eip
.ip
, pnt
, 4);
605 eip
.val
= (*pnt
++ << 8);
608 len
= sprintf(buf
, "%s%s:%u", prefix
, inet_ntoa(eip
.ip
),
611 (void)pnt
; /* consume value */
616 /* Convert extended community attribute to string.
618 Due to historical reason of industry standard implementation, there
619 are three types of format.
621 route-map set extcommunity format
626 "rt 100:1 rt 100:2 soo 100:3"
628 "show [ip] bgp" and extcommunity-list regular expression matching
629 "RT:100:1 RT:100:2 SoO:100:3"
631 For each formath please use below definition for format:
633 ECOMMUNITY_FORMAT_ROUTE_MAP
634 ECOMMUNITY_FORMAT_COMMUNITY_LIST
635 ECOMMUNITY_FORMAT_DISPLAY
637 Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
640 char *ecommunity_ecom2str(struct ecommunity
*ecom
, int format
, int filter
)
645 uint8_t sub_type
= 0;
646 #define ECOMMUNITY_STR_DEFAULT_LEN 64
653 if (ecom
->size
== 0) {
654 str_buf
= XMALLOC(MTYPE_ECOMMUNITY_STR
, 1);
659 /* Prepare buffer. */
660 str_buf
= XMALLOC(MTYPE_ECOMMUNITY_STR
, ECOMMUNITY_STR_DEFAULT_LEN
+ 1);
661 str_size
= ECOMMUNITY_STR_DEFAULT_LEN
+ 1;
665 for (i
= 0; i
< ecom
->size
; i
++) {
668 /* Make it sure size is enough. */
669 while (str_pnt
+ ECOMMUNITY_STR_DEFAULT_LEN
>= str_size
) {
671 str_buf
= XREALLOC(MTYPE_ECOMMUNITY_STR
, str_buf
,
675 /* Space between each value. */
677 str_buf
[str_pnt
++] = ' ';
681 pnt
= ecom
->val
+ (i
* 8);
683 /* High-order octet of type. */
686 if (type
== ECOMMUNITY_ENCODE_AS
|| type
== ECOMMUNITY_ENCODE_IP
687 || type
== ECOMMUNITY_ENCODE_AS4
) {
688 /* Low-order octet of type. */
690 if (sub_type
!= ECOMMUNITY_ROUTE_TARGET
691 && sub_type
!= ECOMMUNITY_SITE_ORIGIN
)
694 len
= ecommunity_rt_soo_str(str_buf
+ str_pnt
,
697 } else if (type
== ECOMMUNITY_ENCODE_OPAQUE
) {
698 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
700 if (*pnt
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
) {
702 memcpy(&tunneltype
, pnt
+ 5, 2);
703 tunneltype
= ntohs(tunneltype
);
704 len
= sprintf(str_buf
+ str_pnt
, "ET:%d",
706 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_DEF_GW
) {
707 len
= sprintf(str_buf
+ str_pnt
,
711 } else if (type
== ECOMMUNITY_ENCODE_EVPN
) {
712 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
714 if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC
) {
717 memcpy(&rmac
, pnt
, ETH_ALEN
);
720 "Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
721 (uint8_t)rmac
.octet
[0],
722 (uint8_t)rmac
.octet
[1],
723 (uint8_t)rmac
.octet
[2],
724 (uint8_t)rmac
.octet
[3],
725 (uint8_t)rmac
.octet
[4],
726 (uint8_t)rmac
.octet
[5]);
728 == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY
) {
730 uint8_t flags
= *++pnt
;
732 memcpy(&seqnum
, pnt
+ 2, 4);
733 seqnum
= ntohl(seqnum
);
735 & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY
)
736 len
= sprintf(str_buf
+ str_pnt
,
740 len
= sprintf(str_buf
+ str_pnt
,
744 } else if (type
== ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) {
746 if (sub_type
== ECOMMUNITY_REDIRECT_IP_NH
) {
749 "FS:redirect IP 0x%x", *(pnt
+5));
752 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
||
753 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_2
||
754 type
== ECOMMUNITY_EXTENDED_COMMUNITY_PART_3
) {
756 if (sub_type
== ECOMMUNITY_REDIRECT_VRF
) {
759 memset(buf
, 0, sizeof(buf
));
760 ecommunity_rt_soo_str(buf
, (uint8_t *)pnt
,
762 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
763 ECOMMUNITY_ROUTE_TARGET
,
764 ECOMMUNITY_FORMAT_DISPLAY
);
765 len
= snprintf(str_buf
+ str_pnt
,
767 "FS:redirect VRF %s", buf
);
768 } else if (type
!= ECOMMUNITY_ENCODE_TRANS_EXP
)
770 else if (sub_type
== ECOMMUNITY_TRAFFIC_ACTION
) {
775 1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
)
776 ptr
+= snprintf(ptr
, sizeof(action
),
777 "terminate (apply)");
779 ptr
+= snprintf(ptr
, sizeof(action
),
782 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
783 snprintf(ptr
, sizeof(action
) -
784 (size_t)(ptr
-action
),
786 len
= snprintf(str_buf
+ str_pnt
,
788 "FS:action %s", action
);
789 } else if (sub_type
== ECOMMUNITY_TRAFFIC_RATE
) {
790 union traffic_rate data
;
792 data
.rate_byte
[3] = *(pnt
+2);
793 data
.rate_byte
[2] = *(pnt
+3);
794 data
.rate_byte
[1] = *(pnt
+4);
795 data
.rate_byte
[0] = *(pnt
+5);
798 "FS:rate %f", data
.rate_float
);
799 } else if (sub_type
== ECOMMUNITY_TRAFFIC_MARKING
) {
802 "FS:marking %u", *(pnt
+5));
804 == ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT
) {
808 memcpy(&mac
, pnt
, ETH_ALEN
);
811 "ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x",
812 (uint8_t)mac
.octet
[0],
813 (uint8_t)mac
.octet
[1],
814 (uint8_t)mac
.octet
[2],
815 (uint8_t)mac
.octet
[3],
816 (uint8_t)mac
.octet
[4],
817 (uint8_t)mac
.octet
[5]);
826 len
= sprintf(str_buf
+ str_pnt
, "UNK:%d, %d",
836 int ecommunity_match(const struct ecommunity
*ecom1
,
837 const struct ecommunity
*ecom2
)
842 if (ecom1
== NULL
&& ecom2
== NULL
)
845 if (ecom1
== NULL
|| ecom2
== NULL
)
848 if (ecom1
->size
< ecom2
->size
)
851 /* Every community on com2 needs to be on com1 for this to match */
852 while (i
< ecom1
->size
&& j
< ecom2
->size
) {
853 if (memcmp(ecom1
->val
+ i
* ECOMMUNITY_SIZE
,
854 ecom2
->val
+ j
* ECOMMUNITY_SIZE
, ECOMMUNITY_SIZE
)
860 if (j
== ecom2
->size
)
866 /* return first occurence of type */
867 extern struct ecommunity_val
*ecommunity_lookup(const struct ecommunity
*ecom
,
868 uint8_t type
, uint8_t subtype
)
873 /* If the value already exists in the structure return 0. */
875 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
879 if (p
[0] == type
&& p
[1] == subtype
)
880 return (struct ecommunity_val
*)p
;
885 /* remove ext. community matching type and subtype
886 * return 1 on success ( removed ), 0 otherwise (not present)
888 extern int ecommunity_strip(struct ecommunity
*ecom
, uint8_t type
,
893 /* When this is fist value, just add it. */
894 if (ecom
== NULL
|| ecom
->val
== NULL
) {
898 /* If the value already exists in the structure return 0. */
900 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
901 if (p
[0] == type
&& p
[1] == subtype
) {
908 /* Strip The selected value */
910 /* size is reduced. no memmove to do */
911 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ECOMMUNITY_SIZE
);
913 memcpy(p
, ecom
->val
, c
* ECOMMUNITY_SIZE
);
914 if ((ecom
->size
- c
) != 0)
915 memcpy(p
+ (c
)*ECOMMUNITY_SIZE
,
916 ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
917 (ecom
->size
- c
) * ECOMMUNITY_SIZE
);
918 /* shift last ecommunities */
919 XFREE(MTYPE_ECOMMUNITY
, ecom
->val
);
925 * Remove specified extended community value from extended community.
926 * Returns 1 if value was present (and hence, removed), 0 otherwise.
928 int ecommunity_del_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
933 /* Make sure specified value exists. */
934 if (ecom
== NULL
|| ecom
->val
== NULL
)
937 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
938 if (!memcmp(p
, eval
->val
, ECOMMUNITY_SIZE
)) {
946 /* Delete the selected value */
948 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ECOMMUNITY_SIZE
);
950 memcpy(p
, ecom
->val
, c
* ECOMMUNITY_SIZE
);
951 if ((ecom
->size
- c
) != 0)
952 memcpy(p
+ (c
)*ECOMMUNITY_SIZE
,
953 ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
954 (ecom
->size
- c
) * ECOMMUNITY_SIZE
);
955 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
960 int ecommunity_fill_pbr_action(struct ecommunity_val
*ecom_eval
,
961 struct bgp_pbr_entry_action
*api
)
963 if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_RATE
) {
964 api
->action
= ACTION_TRAFFICRATE
;
965 api
->u
.r
.rate_info
[3] = ecom_eval
->val
[4];
966 api
->u
.r
.rate_info
[2] = ecom_eval
->val
[5];
967 api
->u
.r
.rate_info
[1] = ecom_eval
->val
[6];
968 api
->u
.r
.rate_info
[0] = ecom_eval
->val
[7];
969 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_ACTION
) {
970 api
->action
= ACTION_TRAFFIC_ACTION
;
971 /* else distribute code is set by default */
972 if (ecom_eval
->val
[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
))
973 api
->u
.za
.filter
|= TRAFFIC_ACTION_TERMINATE
;
975 api
->u
.za
.filter
|= TRAFFIC_ACTION_DISTRIBUTE
;
976 if (ecom_eval
->val
[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
977 api
->u
.za
.filter
|= TRAFFIC_ACTION_SAMPLE
;
979 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_MARKING
) {
980 api
->action
= ACTION_MARKING
;
981 api
->u
.marking_dscp
= ecom_eval
->val
[7];
982 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_VRF
) {
983 /* must use external function */
985 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_IP_NH
) {
986 /* see draft-ietf-idr-flowspec-redirect-ip-02
987 * Q1: how come a ext. community can host ipv6 address
988 * Q2 : from cisco documentation:
989 * Announces the reachability of one or more flowspec NLRI.
990 * When a BGP speaker receives an UPDATE message with the
991 * redirect-to-IP extended community, it is expected to
992 * create a traffic filtering rule for every flow-spec
993 * NLRI in the message that has this path as its best
994 * path. The filter entry matches the IP packets
995 * described in the NLRI field and redirects them or
996 * copies them towards the IPv4 or IPv6 address specified
997 * in the 'Network Address of Next- Hop'
998 * field of the associated MP_REACH_NLRI.
1000 struct ecommunity_ip
*ip_ecom
= (struct ecommunity_ip
*)
1003 api
->u
.zr
.redirect_ip_v4
= ip_ecom
->ip
;