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 /* Allocate ecommunities. */
56 void ecommunity_free(struct ecommunity
**ecom
)
59 XFREE(MTYPE_ECOMMUNITY_VAL
, (*ecom
)->val
);
61 XFREE(MTYPE_ECOMMUNITY_STR
, (*ecom
)->str
);
62 XFREE(MTYPE_ECOMMUNITY
, *ecom
);
66 static void ecommunity_hash_free(struct ecommunity
*ecom
)
68 ecommunity_free(&ecom
);
72 /* Add a new Extended Communities value to Extended Communities
73 Attribute structure. When the value is already exists in the
74 structure, we don't add the value. Newly added value is sorted by
75 numerical order. When the value is added to the structure return 1
77 int ecommunity_add_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
83 /* When this is fist value, just add it. */
84 if (ecom
->val
== NULL
) {
86 ecom
->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom_length(ecom
));
87 memcpy(ecom
->val
, eval
->val
, ECOMMUNITY_SIZE
);
91 /* If the value already exists in the structure return 0. */
93 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
94 ret
= memcmp(p
, eval
->val
, ECOMMUNITY_SIZE
);
101 /* Add the value to the structure with numerical sorting. */
104 XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->val
, ecom_length(ecom
));
106 memmove(ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
107 ecom
->val
+ c
* ECOMMUNITY_SIZE
,
108 (ecom
->size
- 1 - c
) * ECOMMUNITY_SIZE
);
109 memcpy(ecom
->val
+ c
* ECOMMUNITY_SIZE
, eval
->val
, ECOMMUNITY_SIZE
);
114 /* This function takes pointer to Extended Communites strucutre then
115 create a new Extended Communities structure by uniq and sort each
116 Extended Communities value. */
117 struct ecommunity
*ecommunity_uniq_sort(struct ecommunity
*ecom
)
120 struct ecommunity
*new;
121 struct ecommunity_val
*eval
;
126 new = ecommunity_new();
128 for (i
= 0; i
< ecom
->size
; i
++) {
129 eval
= (struct ecommunity_val
*)(ecom
->val
130 + (i
* ECOMMUNITY_SIZE
));
131 ecommunity_add_val(new, eval
);
136 /* Parse Extended Communites Attribute in BGP packet. */
137 struct ecommunity
*ecommunity_parse(uint8_t *pnt
, unsigned short length
)
139 struct ecommunity tmp
;
140 struct ecommunity
*new;
143 if (length
% ECOMMUNITY_SIZE
)
146 /* Prepare tmporary structure for making a new Extended Communities
148 tmp
.size
= length
/ ECOMMUNITY_SIZE
;
151 /* Create a new Extended Communities Attribute by uniq and sort each
152 Extended Communities value */
153 new = ecommunity_uniq_sort(&tmp
);
155 return ecommunity_intern(new);
158 /* Duplicate the Extended Communities Attribute structure. */
159 struct ecommunity
*ecommunity_dup(struct ecommunity
*ecom
)
161 struct ecommunity
*new;
163 new = XCALLOC(MTYPE_ECOMMUNITY
, sizeof(struct ecommunity
));
164 new->size
= ecom
->size
;
166 new->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
,
167 ecom
->size
* ECOMMUNITY_SIZE
);
168 memcpy(new->val
, ecom
->val
, ecom
->size
* ECOMMUNITY_SIZE
);
174 /* Retrun string representation of communities attribute. */
175 char *ecommunity_str(struct ecommunity
*ecom
)
179 ecommunity_ecom2str(ecom
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
183 /* Merge two Extended Communities Attribute structure. */
184 struct ecommunity
*ecommunity_merge(struct ecommunity
*ecom1
,
185 struct ecommunity
*ecom2
)
189 XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom1
->val
,
190 (ecom1
->size
+ ecom2
->size
) * ECOMMUNITY_SIZE
);
193 XMALLOC(MTYPE_ECOMMUNITY_VAL
,
194 (ecom1
->size
+ ecom2
->size
) * ECOMMUNITY_SIZE
);
196 memcpy(ecom1
->val
+ (ecom1
->size
* ECOMMUNITY_SIZE
), ecom2
->val
,
197 ecom2
->size
* ECOMMUNITY_SIZE
);
198 ecom1
->size
+= ecom2
->size
;
203 /* Intern Extended Communities Attribute. */
204 struct ecommunity
*ecommunity_intern(struct ecommunity
*ecom
)
206 struct ecommunity
*find
;
208 assert(ecom
->refcnt
== 0);
210 find
= (struct ecommunity
*)hash_get(ecomhash
, ecom
, hash_alloc_intern
);
213 ecommunity_free(&ecom
);
219 ecommunity_ecom2str(find
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
224 /* Unintern Extended Communities Attribute. */
225 void ecommunity_unintern(struct ecommunity
**ecom
)
227 struct ecommunity
*ret
;
232 /* Pull off from hash. */
233 if ((*ecom
)->refcnt
== 0) {
234 /* Extended community must be in the hash. */
235 ret
= (struct ecommunity
*)hash_release(ecomhash
, *ecom
);
238 ecommunity_free(ecom
);
242 /* Utinity function to make hash key. */
243 unsigned int ecommunity_hash_make(void *arg
)
245 const struct ecommunity
*ecom
= arg
;
246 int size
= ecom
->size
* ECOMMUNITY_SIZE
;
248 return jhash(ecom
->val
, size
, 0x564321ab);
251 /* Compare two Extended Communities Attribute structure. */
252 int ecommunity_cmp(const void *arg1
, const void *arg2
)
254 const struct ecommunity
*ecom1
= arg1
;
255 const struct ecommunity
*ecom2
= arg2
;
257 if (ecom1
== NULL
&& ecom2
== NULL
)
260 if (ecom1
== NULL
|| ecom2
== NULL
)
263 return (ecom1
->size
== ecom2
->size
264 && memcmp(ecom1
->val
, ecom2
->val
, ecom1
->size
* ECOMMUNITY_SIZE
)
268 /* Initialize Extended Comminities related hash. */
269 void ecommunity_init(void)
271 ecomhash
= hash_create(ecommunity_hash_make
, ecommunity_cmp
,
272 "BGP ecommunity hash");
275 void ecommunity_finish(void)
277 hash_clean(ecomhash
, (void (*)(void *))ecommunity_hash_free
);
282 /* Extended Communities token enum. */
283 enum ecommunity_token
{
284 ecommunity_token_unknown
= 0,
286 ecommunity_token_soo
,
287 ecommunity_token_val
,
291 * Encode BGP extended community from passed values. Supports types
292 * defined in RFC 4360 and well-known sub-types.
294 static int ecommunity_encode(uint8_t type
, uint8_t sub_type
, int trans
, as_t as
,
295 struct in_addr ip
, uint32_t val
,
296 struct ecommunity_val
*eval
)
299 if (type
== ECOMMUNITY_ENCODE_AS
) {
302 } else if (type
== ECOMMUNITY_ENCODE_IP
303 || type
== ECOMMUNITY_ENCODE_AS4
) {
304 if (val
> UINT16_MAX
)
308 /* Fill in the values. */
311 eval
->val
[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE
;
312 eval
->val
[1] = sub_type
;
313 if (type
== ECOMMUNITY_ENCODE_AS
) {
314 eval
->val
[2] = (as
>> 8) & 0xff;
315 eval
->val
[3] = as
& 0xff;
316 eval
->val
[4] = (val
>> 24) & 0xff;
317 eval
->val
[5] = (val
>> 16) & 0xff;
318 eval
->val
[6] = (val
>> 8) & 0xff;
319 eval
->val
[7] = val
& 0xff;
320 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
321 memcpy(&eval
->val
[2], &ip
, sizeof(struct in_addr
));
322 eval
->val
[6] = (val
>> 8) & 0xff;
323 eval
->val
[7] = val
& 0xff;
325 eval
->val
[2] = (as
>> 24) & 0xff;
326 eval
->val
[3] = (as
>> 16) & 0xff;
327 eval
->val
[4] = (as
>> 8) & 0xff;
328 eval
->val
[5] = as
& 0xff;
329 eval
->val
[6] = (val
>> 8) & 0xff;
330 eval
->val
[7] = val
& 0xff;
336 /* Get next Extended Communities token from the string. */
337 static const char *ecommunity_gettoken(const char *str
,
338 struct ecommunity_val
*eval
,
339 enum ecommunity_token
*token
)
351 char buf
[INET_ADDRSTRLEN
+ 1];
353 /* Skip white space. */
354 while (isspace((int)*p
)) {
359 /* Check the end of the line. */
363 /* "rt" and "soo" keyword parse. */
364 if (!isdigit((int)*p
)) {
365 /* "rt" match check. */
366 if (tolower((int)*p
) == 'r') {
368 if (tolower((int)*p
) == 't') {
370 *token
= ecommunity_token_rt
;
373 if (isspace((int)*p
) || *p
== '\0') {
374 *token
= ecommunity_token_rt
;
379 /* "soo" match check. */
380 else if (tolower((int)*p
) == 's') {
382 if (tolower((int)*p
) == 'o') {
384 if (tolower((int)*p
) == 'o') {
386 *token
= ecommunity_token_soo
;
389 if (isspace((int)*p
) || *p
== '\0') {
390 *token
= ecommunity_token_soo
;
395 if (isspace((int)*p
) || *p
== '\0') {
396 *token
= ecommunity_token_soo
;
404 /* What a mess, there are several possibilities:
410 * A.B.C.D: Four Byte IP
412 * GHJK: Four-byte ASN
414 * OPQR: Four byte value
417 while (isdigit((int)*p
) || *p
== ':' || *p
== '.') {
425 if ((p
- str
) > INET_ADDRSTRLEN
)
427 memset(buf
, 0, INET_ADDRSTRLEN
+ 1);
428 memcpy(buf
, str
, p
- str
);
431 /* Parsing A.B.C.D in:
434 ret
= inet_aton(buf
, &ip
);
439 as
= strtoul(buf
, &endptr
, 10);
440 if (*endptr
!= '\0' || as
== BGP_AS4_MAX
)
443 } else if (*p
== '.') {
452 /* We're past the IP/ASN part */
461 /* Low digit part must be there. */
462 if (!digit
|| !separator
)
465 /* Encode result into extended community. */
467 ecomm_type
= ECOMMUNITY_ENCODE_IP
;
468 else if (as
> BGP_AS_MAX
)
469 ecomm_type
= ECOMMUNITY_ENCODE_AS4
;
471 ecomm_type
= ECOMMUNITY_ENCODE_AS
;
472 if (ecommunity_encode(ecomm_type
, 0, 1, as
, ip
, val
, eval
))
474 *token
= ecommunity_token_val
;
478 *token
= ecommunity_token_unknown
;
482 /* Convert string to extended community attribute.
484 When type is already known, please specify both str and type. str
485 should not include keyword such as "rt" and "soo". Type is
486 ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
487 keyword_included should be zero.
489 For example route-map's "set extcommunity" command case:
491 "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
492 type = ECOMMUNITY_ROUTE_TARGET
495 "soo 100:1" -> str = "100:1"
496 type = ECOMMUNITY_SITE_ORIGIN
499 When string includes keyword for each extended community value.
500 Please specify keyword_included as non-zero value.
502 For example standard extcommunity-list case:
504 "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
508 struct ecommunity
*ecommunity_str2com(const char *str
, int type
,
509 int keyword_included
)
511 struct ecommunity
*ecom
= NULL
;
512 enum ecommunity_token token
= ecommunity_token_unknown
;
513 struct ecommunity_val eval
;
516 while ((str
= ecommunity_gettoken(str
, &eval
, &token
))) {
518 case ecommunity_token_rt
:
519 case ecommunity_token_soo
:
520 if (!keyword_included
|| keyword
) {
522 ecommunity_free(&ecom
);
527 if (token
== ecommunity_token_rt
) {
528 type
= ECOMMUNITY_ROUTE_TARGET
;
530 if (token
== ecommunity_token_soo
) {
531 type
= ECOMMUNITY_SITE_ORIGIN
;
534 case ecommunity_token_val
:
535 if (keyword_included
) {
538 ecommunity_free(&ecom
);
544 ecom
= ecommunity_new();
546 ecommunity_add_val(ecom
, &eval
);
548 case ecommunity_token_unknown
:
551 ecommunity_free(&ecom
);
558 static int ecommunity_rt_soo_str(char *buf
, uint8_t *pnt
, int type
,
559 int sub_type
, int format
)
564 /* For parse Extended Community attribute tupple. */
565 struct ecommunity_as eas
;
566 struct ecommunity_ip eip
;
569 /* Determine prefix for string, if any. */
571 case ECOMMUNITY_FORMAT_COMMUNITY_LIST
:
572 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "rt " : "soo ");
574 case ECOMMUNITY_FORMAT_DISPLAY
:
575 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "RT:" : "SoO:");
577 case ECOMMUNITY_FORMAT_ROUTE_MAP
:
585 /* Put string into buffer. */
586 if (type
== ECOMMUNITY_ENCODE_AS4
) {
587 pnt
= ptr_get_be32(pnt
, &eas
.as
);
588 eas
.val
= (*pnt
++ << 8);
591 len
= sprintf(buf
, "%s%u:%u", prefix
, eas
.as
, eas
.val
);
592 } else if (type
== ECOMMUNITY_ENCODE_AS
) {
593 eas
.as
= (*pnt
++ << 8);
595 pnt
= ptr_get_be32(pnt
, &eas
.val
);
597 len
= sprintf(buf
, "%s%u:%u", prefix
, eas
.as
, eas
.val
);
598 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
599 memcpy(&eip
.ip
, pnt
, 4);
601 eip
.val
= (*pnt
++ << 8);
604 len
= sprintf(buf
, "%s%s:%u", prefix
, inet_ntoa(eip
.ip
),
607 (void)pnt
; /* consume value */
612 /* Convert extended community attribute to string.
614 Due to historical reason of industry standard implementation, there
615 are three types of format.
617 route-map set extcommunity format
622 "rt 100:1 rt 100:2 soo 100:3"
624 "show [ip] bgp" and extcommunity-list regular expression matching
625 "RT:100:1 RT:100:2 SoO:100:3"
627 For each formath please use below definition for format:
629 ECOMMUNITY_FORMAT_ROUTE_MAP
630 ECOMMUNITY_FORMAT_COMMUNITY_LIST
631 ECOMMUNITY_FORMAT_DISPLAY
633 Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
636 char *ecommunity_ecom2str(struct ecommunity
*ecom
, int format
, int filter
)
642 #define ECOMMUNITY_STR_DEFAULT_LEN 27
649 if (ecom
->size
== 0) {
650 str_buf
= XMALLOC(MTYPE_ECOMMUNITY_STR
, 1);
655 /* Prepare buffer. */
656 str_buf
= XMALLOC(MTYPE_ECOMMUNITY_STR
, ECOMMUNITY_STR_DEFAULT_LEN
+ 1);
657 str_size
= ECOMMUNITY_STR_DEFAULT_LEN
+ 1;
661 for (i
= 0; i
< ecom
->size
; i
++) {
664 /* Make it sure size is enough. */
665 while (str_pnt
+ ECOMMUNITY_STR_DEFAULT_LEN
>= str_size
) {
667 str_buf
= XREALLOC(MTYPE_ECOMMUNITY_STR
, str_buf
,
671 /* Space between each value. */
673 str_buf
[str_pnt
++] = ' ';
677 pnt
= ecom
->val
+ (i
* 8);
679 /* High-order octet of type. */
682 if (type
== ECOMMUNITY_ENCODE_AS
|| type
== ECOMMUNITY_ENCODE_IP
683 || type
== ECOMMUNITY_ENCODE_AS4
) {
684 /* Low-order octet of type. */
686 if (sub_type
!= ECOMMUNITY_ROUTE_TARGET
687 && sub_type
!= ECOMMUNITY_SITE_ORIGIN
)
690 len
= ecommunity_rt_soo_str(str_buf
+ str_pnt
,
693 } else if (type
== ECOMMUNITY_ENCODE_OPAQUE
) {
694 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
696 if (*pnt
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
) {
698 memcpy(&tunneltype
, pnt
+ 5, 2);
699 tunneltype
= ntohs(tunneltype
);
700 len
= sprintf(str_buf
+ str_pnt
, "ET:%d",
702 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_DEF_GW
) {
703 len
= sprintf(str_buf
+ str_pnt
,
707 } else if (type
== ECOMMUNITY_ENCODE_EVPN
) {
708 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
710 if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC
) {
713 memcpy(&rmac
, pnt
, ETH_ALEN
);
716 "Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
717 (uint8_t)rmac
.octet
[0],
718 (uint8_t)rmac
.octet
[1],
719 (uint8_t)rmac
.octet
[2],
720 (uint8_t)rmac
.octet
[3],
721 (uint8_t)rmac
.octet
[4],
722 (uint8_t)rmac
.octet
[5]);
724 == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY
) {
726 uint8_t flags
= *++pnt
;
728 memcpy(&seqnum
, pnt
+ 2, 4);
729 seqnum
= ntohl(seqnum
);
731 & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY
)
732 len
= sprintf(str_buf
+ str_pnt
,
736 len
= sprintf(str_buf
+ str_pnt
,
740 } else if (type
== ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) {
742 if (sub_type
== ECOMMUNITY_REDIRECT_IP_NH
) {
745 "FS:redirect IP 0x%x", *(pnt
+5));
748 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
) {
751 if (sub_type
== ECOMMUNITY_TRAFFIC_ACTION
) {
756 1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
)
757 ptr
+= snprintf(ptr
, sizeof(action
),
758 "terminate (apply)");
760 ptr
+= snprintf(ptr
, sizeof(action
),
763 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
764 snprintf(ptr
, sizeof(action
) -
765 (size_t)(ptr
-action
),
767 len
= snprintf(str_buf
+ str_pnt
,
769 "FS:action %s", action
);
770 } else if (sub_type
== ECOMMUNITY_TRAFFIC_RATE
) {
771 union traffic_rate data
;
773 data
.rate_byte
[3] = *(pnt
+2);
774 data
.rate_byte
[2] = *(pnt
+3);
775 data
.rate_byte
[1] = *(pnt
+4);
776 data
.rate_byte
[0] = *(pnt
+5);
779 "FS:rate %f", data
.rate_float
);
780 } else if (sub_type
== ECOMMUNITY_REDIRECT_VRF
) {
783 memset(buf
, 0, sizeof(buf
));
784 ecommunity_rt_soo_str(buf
, (uint8_t *)pnt
,
786 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
787 ECOMMUNITY_ROUTE_TARGET
,
788 ECOMMUNITY_FORMAT_DISPLAY
);
792 "FS:redirect VRF %s", buf
);
793 } else if (sub_type
== ECOMMUNITY_TRAFFIC_MARKING
) {
796 "FS:marking %u", *(pnt
+5));
803 len
= sprintf(str_buf
+ str_pnt
, "?");
812 int ecommunity_match(const struct ecommunity
*ecom1
,
813 const struct ecommunity
*ecom2
)
818 if (ecom1
== NULL
&& ecom2
== NULL
)
821 if (ecom1
== NULL
|| ecom2
== NULL
)
824 if (ecom1
->size
< ecom2
->size
)
827 /* Every community on com2 needs to be on com1 for this to match */
828 while (i
< ecom1
->size
&& j
< ecom2
->size
) {
829 if (memcmp(ecom1
->val
+ i
* ECOMMUNITY_SIZE
,
830 ecom2
->val
+ j
* ECOMMUNITY_SIZE
, ECOMMUNITY_SIZE
)
836 if (j
== ecom2
->size
)
842 /* return first occurence of type */
843 extern struct ecommunity_val
*ecommunity_lookup(const struct ecommunity
*ecom
,
844 uint8_t type
, uint8_t subtype
)
849 /* If the value already exists in the structure return 0. */
851 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
855 if (p
[0] == type
&& p
[1] == subtype
)
856 return (struct ecommunity_val
*)p
;
861 /* remove ext. community matching type and subtype
862 * return 1 on success ( removed ), 0 otherwise (not present)
864 extern int ecommunity_strip(struct ecommunity
*ecom
, uint8_t type
,
869 /* When this is fist value, just add it. */
870 if (ecom
== NULL
|| ecom
->val
== NULL
) {
874 /* If the value already exists in the structure return 0. */
876 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
877 if (p
[0] == type
&& p
[1] == subtype
) {
884 /* Strip The selected value */
886 /* size is reduced. no memmove to do */
887 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ECOMMUNITY_SIZE
);
889 memcpy(p
, ecom
->val
, c
* ECOMMUNITY_SIZE
);
890 if ((ecom
->size
- c
) != 0)
891 memcpy(p
+ (c
)*ECOMMUNITY_SIZE
,
892 ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
893 (ecom
->size
- c
) * ECOMMUNITY_SIZE
);
894 /* shift last ecommunities */
895 XFREE(MTYPE_ECOMMUNITY
, ecom
->val
);
901 * Remove specified extended community value from extended community.
902 * Returns 1 if value was present (and hence, removed), 0 otherwise.
904 int ecommunity_del_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
909 /* Make sure specified value exists. */
910 if (ecom
== NULL
|| ecom
->val
== NULL
)
913 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
914 if (!memcmp(p
, eval
->val
, ECOMMUNITY_SIZE
)) {
922 /* Delete the selected value */
924 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ECOMMUNITY_SIZE
);
926 memcpy(p
, ecom
->val
, c
* ECOMMUNITY_SIZE
);
927 if ((ecom
->size
- c
) != 0)
928 memcpy(p
+ (c
)*ECOMMUNITY_SIZE
,
929 ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
930 (ecom
->size
- c
) * ECOMMUNITY_SIZE
);
931 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);
936 int ecommunity_fill_pbr_action(struct ecommunity_val
*ecom_eval
,
937 struct bgp_pbr_entry_action
*api
)
939 if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_RATE
) {
940 api
->action
= ACTION_TRAFFICRATE
;
941 api
->u
.r
.rate_info
[3] = ecom_eval
->val
[4];
942 api
->u
.r
.rate_info
[2] = ecom_eval
->val
[5];
943 api
->u
.r
.rate_info
[1] = ecom_eval
->val
[6];
944 api
->u
.r
.rate_info
[0] = ecom_eval
->val
[7];
945 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_ACTION
) {
946 api
->action
= ACTION_TRAFFIC_ACTION
;
947 /* else distribute code is set by default */
948 if (ecom_eval
->val
[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
))
949 api
->u
.za
.filter
|= TRAFFIC_ACTION_TERMINATE
;
951 api
->u
.za
.filter
|= TRAFFIC_ACTION_DISTRIBUTE
;
952 if (ecom_eval
->val
[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
953 api
->u
.za
.filter
|= TRAFFIC_ACTION_SAMPLE
;
955 } else if (ecom_eval
->val
[1] == ECOMMUNITY_TRAFFIC_MARKING
) {
956 api
->action
= ACTION_MARKING
;
957 api
->u
.marking_dscp
= ecom_eval
->val
[7];
958 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_VRF
) {
959 /* must use external function */
961 } else if (ecom_eval
->val
[1] == ECOMMUNITY_REDIRECT_IP_NH
) {
962 /* see draft-ietf-idr-flowspec-redirect-ip-02
963 * Q1: how come a ext. community can host ipv6 address
964 * Q2 : from cisco documentation:
965 * Announces the reachability of one or more flowspec NLRI.
966 * When a BGP speaker receives an UPDATE message with the
967 * redirect-to-IP extended community, it is expected to
968 * create a traffic filtering rule for every flow-spec
969 * NLRI in the message that has this path as its best
970 * path. The filter entry matches the IP packets
971 * described in the NLRI field and redirects them or
972 * copies them towards the IPv4 or IPv6 address specified
973 * in the 'Network Address of Next- Hop'
974 * field of the associated MP_REACH_NLRI.
976 struct ecommunity_ip
*ip_ecom
= (struct ecommunity_ip
*)
979 api
->u
.zr
.redirect_ip_v4
= ip_ecom
->ip
;