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"
38 /* struct used to dump the rate contained in FS set traffic-rate EC */
44 /* Hash of community attribute. */
45 static struct hash
*ecomhash
;
47 /* Allocate a new ecommunities. */
48 struct ecommunity
*ecommunity_new(void)
50 return (struct ecommunity
*)XCALLOC(MTYPE_ECOMMUNITY
,
51 sizeof(struct ecommunity
));
54 /* Allocate ecommunities. */
55 void ecommunity_free(struct ecommunity
**ecom
)
58 XFREE(MTYPE_ECOMMUNITY_VAL
, (*ecom
)->val
);
60 XFREE(MTYPE_ECOMMUNITY_STR
, (*ecom
)->str
);
61 XFREE(MTYPE_ECOMMUNITY
, *ecom
);
65 static void ecommunity_hash_free(struct ecommunity
*ecom
)
67 ecommunity_free(&ecom
);
71 /* Add a new Extended Communities value to Extended Communities
72 Attribute structure. When the value is already exists in the
73 structure, we don't add the value. Newly added value is sorted by
74 numerical order. When the value is added to the structure return 1
76 int ecommunity_add_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
82 /* When this is fist value, just add it. */
83 if (ecom
->val
== NULL
) {
85 ecom
->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom_length(ecom
));
86 memcpy(ecom
->val
, eval
->val
, ECOMMUNITY_SIZE
);
90 /* If the value already exists in the structure return 0. */
92 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
93 ret
= memcmp(p
, eval
->val
, ECOMMUNITY_SIZE
);
100 /* Add the value to the structure with numerical sorting. */
103 XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->val
, ecom_length(ecom
));
105 memmove(ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
106 ecom
->val
+ c
* ECOMMUNITY_SIZE
,
107 (ecom
->size
- 1 - c
) * ECOMMUNITY_SIZE
);
108 memcpy(ecom
->val
+ c
* ECOMMUNITY_SIZE
, eval
->val
, ECOMMUNITY_SIZE
);
113 /* This function takes pointer to Extended Communites strucutre then
114 create a new Extended Communities structure by uniq and sort each
115 Extended Communities value. */
116 struct ecommunity
*ecommunity_uniq_sort(struct ecommunity
*ecom
)
119 struct ecommunity
*new;
120 struct ecommunity_val
*eval
;
125 new = ecommunity_new();
127 for (i
= 0; i
< ecom
->size
; i
++) {
128 eval
= (struct ecommunity_val
*)(ecom
->val
129 + (i
* ECOMMUNITY_SIZE
));
130 ecommunity_add_val(new, eval
);
135 /* Parse Extended Communites Attribute in BGP packet. */
136 struct ecommunity
*ecommunity_parse(uint8_t *pnt
, unsigned short length
)
138 struct ecommunity tmp
;
139 struct ecommunity
*new;
142 if (length
% ECOMMUNITY_SIZE
)
145 /* Prepare tmporary structure for making a new Extended Communities
147 tmp
.size
= length
/ ECOMMUNITY_SIZE
;
150 /* Create a new Extended Communities Attribute by uniq and sort each
151 Extended Communities value */
152 new = ecommunity_uniq_sort(&tmp
);
154 return ecommunity_intern(new);
157 /* Duplicate the Extended Communities Attribute structure. */
158 struct ecommunity
*ecommunity_dup(struct ecommunity
*ecom
)
160 struct ecommunity
*new;
162 new = XCALLOC(MTYPE_ECOMMUNITY
, sizeof(struct ecommunity
));
163 new->size
= ecom
->size
;
165 new->val
= XMALLOC(MTYPE_ECOMMUNITY_VAL
,
166 ecom
->size
* ECOMMUNITY_SIZE
);
167 memcpy(new->val
, ecom
->val
, ecom
->size
* ECOMMUNITY_SIZE
);
173 /* Retrun string representation of communities attribute. */
174 char *ecommunity_str(struct ecommunity
*ecom
)
178 ecommunity_ecom2str(ecom
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
182 /* Merge two Extended Communities Attribute structure. */
183 struct ecommunity
*ecommunity_merge(struct ecommunity
*ecom1
,
184 struct ecommunity
*ecom2
)
188 XREALLOC(MTYPE_ECOMMUNITY_VAL
, ecom1
->val
,
189 (ecom1
->size
+ ecom2
->size
) * ECOMMUNITY_SIZE
);
192 XMALLOC(MTYPE_ECOMMUNITY_VAL
,
193 (ecom1
->size
+ ecom2
->size
) * ECOMMUNITY_SIZE
);
195 memcpy(ecom1
->val
+ (ecom1
->size
* ECOMMUNITY_SIZE
), ecom2
->val
,
196 ecom2
->size
* ECOMMUNITY_SIZE
);
197 ecom1
->size
+= ecom2
->size
;
202 /* Intern Extended Communities Attribute. */
203 struct ecommunity
*ecommunity_intern(struct ecommunity
*ecom
)
205 struct ecommunity
*find
;
207 assert(ecom
->refcnt
== 0);
209 find
= (struct ecommunity
*)hash_get(ecomhash
, ecom
, hash_alloc_intern
);
212 ecommunity_free(&ecom
);
218 ecommunity_ecom2str(find
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
223 /* Unintern Extended Communities Attribute. */
224 void ecommunity_unintern(struct ecommunity
**ecom
)
226 struct ecommunity
*ret
;
231 /* Pull off from hash. */
232 if ((*ecom
)->refcnt
== 0) {
233 /* Extended community must be in the hash. */
234 ret
= (struct ecommunity
*)hash_release(ecomhash
, *ecom
);
237 ecommunity_free(ecom
);
241 /* Utinity function to make hash key. */
242 unsigned int ecommunity_hash_make(void *arg
)
244 const struct ecommunity
*ecom
= arg
;
245 int size
= ecom
->size
* ECOMMUNITY_SIZE
;
247 return jhash(ecom
->val
, size
, 0x564321ab);
250 /* Compare two Extended Communities Attribute structure. */
251 int ecommunity_cmp(const void *arg1
, const void *arg2
)
253 const struct ecommunity
*ecom1
= arg1
;
254 const struct ecommunity
*ecom2
= arg2
;
256 if (ecom1
== NULL
&& ecom2
== NULL
)
259 if (ecom1
== NULL
|| ecom2
== NULL
)
262 return (ecom1
->size
== ecom2
->size
263 && memcmp(ecom1
->val
, ecom2
->val
, ecom1
->size
* ECOMMUNITY_SIZE
)
267 /* Initialize Extended Comminities related hash. */
268 void ecommunity_init(void)
270 ecomhash
= hash_create(ecommunity_hash_make
, ecommunity_cmp
,
271 "BGP ecommunity hash");
274 void ecommunity_finish(void)
276 hash_clean(ecomhash
, (void (*)(void *))ecommunity_hash_free
);
281 /* Extended Communities token enum. */
282 enum ecommunity_token
{
283 ecommunity_token_unknown
= 0,
285 ecommunity_token_soo
,
286 ecommunity_token_val
,
290 * Encode BGP extended community from passed values. Supports types
291 * defined in RFC 4360 and well-known sub-types.
293 static int ecommunity_encode(uint8_t type
, uint8_t sub_type
, int trans
, as_t as
,
294 struct in_addr ip
, uint32_t val
,
295 struct ecommunity_val
*eval
)
298 if (type
== ECOMMUNITY_ENCODE_AS
) {
301 } else if (type
== ECOMMUNITY_ENCODE_IP
302 || type
== ECOMMUNITY_ENCODE_AS4
) {
303 if (val
> UINT16_MAX
)
307 /* Fill in the values. */
310 eval
->val
[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE
;
311 eval
->val
[1] = sub_type
;
312 if (type
== ECOMMUNITY_ENCODE_AS
) {
313 eval
->val
[2] = (as
>> 8) & 0xff;
314 eval
->val
[3] = as
& 0xff;
315 eval
->val
[4] = (val
>> 24) & 0xff;
316 eval
->val
[5] = (val
>> 16) & 0xff;
317 eval
->val
[6] = (val
>> 8) & 0xff;
318 eval
->val
[7] = val
& 0xff;
319 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
320 memcpy(&eval
->val
[2], &ip
, sizeof(struct in_addr
));
321 eval
->val
[6] = (val
>> 8) & 0xff;
322 eval
->val
[7] = val
& 0xff;
324 eval
->val
[2] = (as
>> 24) & 0xff;
325 eval
->val
[3] = (as
>> 16) & 0xff;
326 eval
->val
[4] = (as
>> 8) & 0xff;
327 eval
->val
[5] = as
& 0xff;
328 eval
->val
[6] = (val
>> 8) & 0xff;
329 eval
->val
[7] = val
& 0xff;
335 /* Get next Extended Communities token from the string. */
336 static const char *ecommunity_gettoken(const char *str
,
337 struct ecommunity_val
*eval
,
338 enum ecommunity_token
*token
)
350 char buf
[INET_ADDRSTRLEN
+ 1];
352 /* Skip white space. */
353 while (isspace((int)*p
)) {
358 /* Check the end of the line. */
362 /* "rt" and "soo" keyword parse. */
363 if (!isdigit((int)*p
)) {
364 /* "rt" match check. */
365 if (tolower((int)*p
) == 'r') {
367 if (tolower((int)*p
) == 't') {
369 *token
= ecommunity_token_rt
;
372 if (isspace((int)*p
) || *p
== '\0') {
373 *token
= ecommunity_token_rt
;
378 /* "soo" match check. */
379 else if (tolower((int)*p
) == 's') {
381 if (tolower((int)*p
) == 'o') {
383 if (tolower((int)*p
) == 'o') {
385 *token
= ecommunity_token_soo
;
388 if (isspace((int)*p
) || *p
== '\0') {
389 *token
= ecommunity_token_soo
;
394 if (isspace((int)*p
) || *p
== '\0') {
395 *token
= ecommunity_token_soo
;
403 /* What a mess, there are several possibilities:
409 * A.B.C.D: Four Byte IP
411 * GHJK: Four-byte ASN
413 * OPQR: Four byte value
416 while (isdigit((int)*p
) || *p
== ':' || *p
== '.') {
424 if ((p
- str
) > INET_ADDRSTRLEN
)
426 memset(buf
, 0, INET_ADDRSTRLEN
+ 1);
427 memcpy(buf
, str
, p
- str
);
430 /* Parsing A.B.C.D in:
433 ret
= inet_aton(buf
, &ip
);
438 as
= strtoul(buf
, &endptr
, 10);
439 if (*endptr
!= '\0' || as
== BGP_AS4_MAX
)
442 } else if (*p
== '.') {
451 /* We're past the IP/ASN part */
460 /* Low digit part must be there. */
461 if (!digit
|| !separator
)
464 /* Encode result into extended community. */
466 ecomm_type
= ECOMMUNITY_ENCODE_IP
;
467 else if (as
> BGP_AS_MAX
)
468 ecomm_type
= ECOMMUNITY_ENCODE_AS4
;
470 ecomm_type
= ECOMMUNITY_ENCODE_AS
;
471 if (ecommunity_encode(ecomm_type
, 0, 1, as
, ip
, val
, eval
))
473 *token
= ecommunity_token_val
;
477 *token
= ecommunity_token_unknown
;
481 /* Convert string to extended community attribute.
483 When type is already known, please specify both str and type. str
484 should not include keyword such as "rt" and "soo". Type is
485 ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
486 keyword_included should be zero.
488 For example route-map's "set extcommunity" command case:
490 "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
491 type = ECOMMUNITY_ROUTE_TARGET
494 "soo 100:1" -> str = "100:1"
495 type = ECOMMUNITY_SITE_ORIGIN
498 When string includes keyword for each extended community value.
499 Please specify keyword_included as non-zero value.
501 For example standard extcommunity-list case:
503 "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
507 struct ecommunity
*ecommunity_str2com(const char *str
, int type
,
508 int keyword_included
)
510 struct ecommunity
*ecom
= NULL
;
511 enum ecommunity_token token
= ecommunity_token_unknown
;
512 struct ecommunity_val eval
;
515 while ((str
= ecommunity_gettoken(str
, &eval
, &token
))) {
517 case ecommunity_token_rt
:
518 case ecommunity_token_soo
:
519 if (!keyword_included
|| keyword
) {
521 ecommunity_free(&ecom
);
526 if (token
== ecommunity_token_rt
) {
527 type
= ECOMMUNITY_ROUTE_TARGET
;
529 if (token
== ecommunity_token_soo
) {
530 type
= ECOMMUNITY_SITE_ORIGIN
;
533 case ecommunity_token_val
:
534 if (keyword_included
) {
537 ecommunity_free(&ecom
);
543 ecom
= ecommunity_new();
545 ecommunity_add_val(ecom
, &eval
);
547 case ecommunity_token_unknown
:
550 ecommunity_free(&ecom
);
557 static int ecommunity_rt_soo_str(char *buf
, uint8_t *pnt
, int type
,
558 int sub_type
, int format
)
563 /* For parse Extended Community attribute tupple. */
564 struct ecommunity_as eas
;
565 struct ecommunity_ip eip
;
568 /* Determine prefix for string, if any. */
570 case ECOMMUNITY_FORMAT_COMMUNITY_LIST
:
571 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "rt " : "soo ");
573 case ECOMMUNITY_FORMAT_DISPLAY
:
574 prefix
= (sub_type
== ECOMMUNITY_ROUTE_TARGET
? "RT:" : "SoO:");
576 case ECOMMUNITY_FORMAT_ROUTE_MAP
:
584 /* Put string into buffer. */
585 if (type
== ECOMMUNITY_ENCODE_AS4
) {
586 pnt
= ptr_get_be32(pnt
, &eas
.as
);
587 eas
.val
= (*pnt
++ << 8);
590 len
= sprintf(buf
, "%s%u:%u", prefix
, eas
.as
, eas
.val
);
591 } else if (type
== ECOMMUNITY_ENCODE_AS
) {
592 eas
.as
= (*pnt
++ << 8);
594 pnt
= ptr_get_be32(pnt
, &eas
.val
);
596 len
= sprintf(buf
, "%s%u:%u", prefix
, eas
.as
, eas
.val
);
597 } else if (type
== ECOMMUNITY_ENCODE_IP
) {
598 memcpy(&eip
.ip
, pnt
, 4);
600 eip
.val
= (*pnt
++ << 8);
603 len
= sprintf(buf
, "%s%s:%u", prefix
, inet_ntoa(eip
.ip
),
606 (void)pnt
; /* consume value */
611 /* Convert extended community attribute to string.
613 Due to historical reason of industry standard implementation, there
614 are three types of format.
616 route-map set extcommunity format
621 "rt 100:1 rt 100:2 soo 100:3"
623 "show [ip] bgp" and extcommunity-list regular expression matching
624 "RT:100:1 RT:100:2 SoO:100:3"
626 For each formath please use below definition for format:
628 ECOMMUNITY_FORMAT_ROUTE_MAP
629 ECOMMUNITY_FORMAT_COMMUNITY_LIST
630 ECOMMUNITY_FORMAT_DISPLAY
632 Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
635 char *ecommunity_ecom2str(struct ecommunity
*ecom
, int format
, int filter
)
641 #define ECOMMUNITY_STR_DEFAULT_LEN 27
648 if (ecom
->size
== 0) {
649 str_buf
= XMALLOC(MTYPE_ECOMMUNITY_STR
, 1);
654 /* Prepare buffer. */
655 str_buf
= XMALLOC(MTYPE_ECOMMUNITY_STR
, ECOMMUNITY_STR_DEFAULT_LEN
+ 1);
656 str_size
= ECOMMUNITY_STR_DEFAULT_LEN
+ 1;
660 for (i
= 0; i
< ecom
->size
; i
++) {
663 /* Make it sure size is enough. */
664 while (str_pnt
+ ECOMMUNITY_STR_DEFAULT_LEN
>= str_size
) {
666 str_buf
= XREALLOC(MTYPE_ECOMMUNITY_STR
, str_buf
,
670 /* Space between each value. */
672 str_buf
[str_pnt
++] = ' ';
676 pnt
= ecom
->val
+ (i
* 8);
678 /* High-order octet of type. */
681 if (type
== ECOMMUNITY_ENCODE_AS
|| type
== ECOMMUNITY_ENCODE_IP
682 || type
== ECOMMUNITY_ENCODE_AS4
) {
683 /* Low-order octet of type. */
685 if (sub_type
!= ECOMMUNITY_ROUTE_TARGET
686 && sub_type
!= ECOMMUNITY_SITE_ORIGIN
)
689 len
= ecommunity_rt_soo_str(str_buf
+ str_pnt
,
692 } else if (type
== ECOMMUNITY_ENCODE_OPAQUE
) {
693 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
695 if (*pnt
== ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
) {
697 memcpy(&tunneltype
, pnt
+ 5, 2);
698 tunneltype
= ntohs(tunneltype
);
699 len
= sprintf(str_buf
+ str_pnt
, "ET:%d",
701 } else if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_DEF_GW
) {
702 len
= sprintf(str_buf
+ str_pnt
,
706 } else if (type
== ECOMMUNITY_ENCODE_EVPN
) {
707 if (filter
== ECOMMUNITY_ROUTE_TARGET
)
709 if (*pnt
== ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC
) {
712 memcpy(&rmac
, pnt
, ETH_ALEN
);
715 "Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
716 (uint8_t)rmac
.octet
[0],
717 (uint8_t)rmac
.octet
[1],
718 (uint8_t)rmac
.octet
[2],
719 (uint8_t)rmac
.octet
[3],
720 (uint8_t)rmac
.octet
[4],
721 (uint8_t)rmac
.octet
[5]);
723 == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY
) {
725 uint8_t flags
= *++pnt
;
727 memcpy(&seqnum
, pnt
+ 2, 4);
728 seqnum
= ntohl(seqnum
);
730 & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY
)
731 len
= sprintf(str_buf
+ str_pnt
,
735 len
= sprintf(str_buf
+ str_pnt
,
739 } else if (type
== ECOMMUNITY_ENCODE_REDIRECT_IP_NH
) {
741 if (sub_type
== ECOMMUNITY_REDIRECT_IP_NH
) {
744 "FS:redirect IP 0x%x", *(pnt
+5));
747 } else if (type
== ECOMMUNITY_ENCODE_TRANS_EXP
) {
750 if (sub_type
== ECOMMUNITY_TRAFFIC_ACTION
) {
755 1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL
)
756 ptr
+= snprintf(ptr
, sizeof(action
),
757 "terminate (apply)");
759 ptr
+= snprintf(ptr
, sizeof(action
),
762 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE
)
763 snprintf(ptr
, sizeof(action
) -
764 (size_t)(ptr
-action
),
766 len
= snprintf(str_buf
+ str_pnt
,
768 "FS:action %s", action
);
769 } else if (sub_type
== ECOMMUNITY_TRAFFIC_RATE
) {
770 union traffic_rate data
;
772 data
.rate_byte
[3] = *(pnt
+2);
773 data
.rate_byte
[2] = *(pnt
+3);
774 data
.rate_byte
[1] = *(pnt
+4);
775 data
.rate_byte
[0] = *(pnt
+5);
778 "FS:rate %f", data
.rate_float
);
779 } else if (sub_type
== ECOMMUNITY_REDIRECT_VRF
) {
782 memset(buf
, 0, sizeof(buf
));
783 ecommunity_rt_soo_str(buf
, (uint8_t *)pnt
,
785 ~ECOMMUNITY_ENCODE_TRANS_EXP
,
786 ECOMMUNITY_ROUTE_TARGET
,
787 ECOMMUNITY_FORMAT_DISPLAY
);
791 "FS:redirect VRF %s", buf
);
792 } else if (sub_type
== ECOMMUNITY_TRAFFIC_MARKING
) {
795 "FS:marking %u", *(pnt
+5));
802 len
= sprintf(str_buf
+ str_pnt
, "?");
811 int ecommunity_match(const struct ecommunity
*ecom1
,
812 const struct ecommunity
*ecom2
)
817 if (ecom1
== NULL
&& ecom2
== NULL
)
820 if (ecom1
== NULL
|| ecom2
== NULL
)
823 if (ecom1
->size
< ecom2
->size
)
826 /* Every community on com2 needs to be on com1 for this to match */
827 while (i
< ecom1
->size
&& j
< ecom2
->size
) {
828 if (memcmp(ecom1
->val
+ i
* ECOMMUNITY_SIZE
,
829 ecom2
->val
+ j
* ECOMMUNITY_SIZE
, ECOMMUNITY_SIZE
)
835 if (j
== ecom2
->size
)
841 /* return first occurence of type */
842 extern struct ecommunity_val
*ecommunity_lookup(const struct ecommunity
*ecom
,
843 uint8_t type
, uint8_t subtype
)
848 /* If the value already exists in the structure return 0. */
850 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
854 if (p
[0] == type
&& p
[1] == subtype
)
855 return (struct ecommunity_val
*)p
;
860 /* remove ext. community matching type and subtype
861 * return 1 on success ( removed ), 0 otherwise (not present)
863 extern int ecommunity_strip(struct ecommunity
*ecom
, uint8_t type
,
868 /* When this is fist value, just add it. */
869 if (ecom
== NULL
|| ecom
->val
== NULL
) {
873 /* If the value already exists in the structure return 0. */
875 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
876 if (p
[0] == type
&& p
[1] == subtype
) {
883 /* Strip The selected value */
885 /* size is reduced. no memmove to do */
886 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ECOMMUNITY_SIZE
);
888 memcpy(p
, ecom
->val
, c
* ECOMMUNITY_SIZE
);
889 if ((ecom
->size
- c
) != 0)
890 memcpy(p
+ (c
)*ECOMMUNITY_SIZE
,
891 ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
892 (ecom
->size
- c
) * ECOMMUNITY_SIZE
);
893 /* shift last ecommunities */
894 XFREE(MTYPE_ECOMMUNITY
, ecom
->val
);
900 * Remove specified extended community value from extended community.
901 * Returns 1 if value was present (and hence, removed), 0 otherwise.
903 int ecommunity_del_val(struct ecommunity
*ecom
, struct ecommunity_val
*eval
)
908 /* Make sure specified value exists. */
909 if (ecom
== NULL
|| ecom
->val
== NULL
)
912 for (p
= ecom
->val
; c
< ecom
->size
; p
+= ECOMMUNITY_SIZE
, c
++) {
913 if (!memcmp(p
, eval
->val
, ECOMMUNITY_SIZE
)) {
921 /* Delete the selected value */
923 p
= XMALLOC(MTYPE_ECOMMUNITY_VAL
, ecom
->size
* ECOMMUNITY_SIZE
);
925 memcpy(p
, ecom
->val
, c
* ECOMMUNITY_SIZE
);
926 if ((ecom
->size
- c
) != 0)
927 memcpy(p
+ (c
)*ECOMMUNITY_SIZE
,
928 ecom
->val
+ (c
+ 1) * ECOMMUNITY_SIZE
,
929 (ecom
->size
- c
) * ECOMMUNITY_SIZE
);
930 XFREE(MTYPE_ECOMMUNITY_VAL
, ecom
->val
);