1 /* BGP community-list and extcommunity-list.
2 * Copyright (C) 1999 Kunihiro Ishiguro
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
30 #include "bgpd/bgpd.h"
31 #include "bgpd/bgp_community.h"
32 #include "bgpd/bgp_ecommunity.h"
33 #include "bgpd/bgp_lcommunity.h"
34 #include "bgpd/bgp_aspath.h"
35 #include "bgpd/bgp_regex.h"
36 #include "bgpd/bgp_clist.h"
38 /* Lookup master structure for community-list or
40 struct community_list_master
*
41 community_list_master_lookup(struct community_list_handler
*ch
, int master
)
45 case COMMUNITY_LIST_MASTER
:
46 return &ch
->community_list
;
47 case EXTCOMMUNITY_LIST_MASTER
:
48 return &ch
->extcommunity_list
;
49 case LARGE_COMMUNITY_LIST_MASTER
:
50 return &ch
->lcommunity_list
;
55 /* Allocate a new community list entry. */
56 static struct community_entry
*community_entry_new(void)
58 return XCALLOC(MTYPE_COMMUNITY_LIST_ENTRY
,
59 sizeof(struct community_entry
));
62 /* Free community list entry. */
63 static void community_entry_free(struct community_entry
*entry
)
65 switch (entry
->style
) {
66 case COMMUNITY_LIST_STANDARD
:
68 community_free(entry
->u
.com
);
70 case LARGE_COMMUNITY_LIST_STANDARD
:
72 lcommunity_free(&entry
->u
.lcom
);
74 case EXTCOMMUNITY_LIST_STANDARD
:
75 /* In case of standard extcommunity-list, configuration string
76 is made by ecommunity_ecom2str(). */
78 XFREE(MTYPE_ECOMMUNITY_STR
, entry
->config
);
80 ecommunity_free(&entry
->u
.ecom
);
82 case COMMUNITY_LIST_EXPANDED
:
83 case EXTCOMMUNITY_LIST_EXPANDED
:
84 case LARGE_COMMUNITY_LIST_EXPANDED
:
86 XFREE(MTYPE_COMMUNITY_LIST_CONFIG
, entry
->config
);
88 bgp_regex_free(entry
->reg
);
92 XFREE(MTYPE_COMMUNITY_LIST_ENTRY
, entry
);
95 /* Allocate a new community-list. */
96 static struct community_list
*community_list_new(void)
98 return XCALLOC(MTYPE_COMMUNITY_LIST
, sizeof(struct community_list
));
101 /* Free community-list. */
102 static void community_list_free(struct community_list
*list
)
105 XFREE(MTYPE_COMMUNITY_LIST_NAME
, list
->name
);
106 XFREE(MTYPE_COMMUNITY_LIST
, list
);
109 static struct community_list
*
110 community_list_insert(struct community_list_handler
*ch
, const char *name
,
115 struct community_list
*new;
116 struct community_list
*point
;
117 struct community_list_list
*list
;
118 struct community_list_master
*cm
;
120 /* Lookup community-list master. */
121 cm
= community_list_master_lookup(ch
, master
);
125 /* Allocate new community_list and copy given name. */
126 new = community_list_new();
127 new->name
= XSTRDUP(MTYPE_COMMUNITY_LIST_NAME
, name
);
129 /* If name is made by all digit character. We treat it as
131 for (number
= 0, i
= 0; i
< strlen(name
); i
++) {
132 if (isdigit((int)name
[i
]))
133 number
= (number
* 10) + (name
[i
] - '0');
138 /* In case of name is all digit character */
139 if (i
== strlen(name
)) {
140 new->sort
= COMMUNITY_LIST_NUMBER
;
142 /* Set access_list to number list. */
145 for (point
= list
->head
; point
; point
= point
->next
)
146 if (atol(point
->name
) >= number
)
149 new->sort
= COMMUNITY_LIST_STRING
;
151 /* Set access_list to string list. */
154 /* Set point to insertion point. */
155 for (point
= list
->head
; point
; point
= point
->next
)
156 if (strcmp(point
->name
, name
) >= 0)
160 /* Link to upper list. */
163 /* In case of this is the first element of master. */
164 if (list
->head
== NULL
) {
165 list
->head
= list
->tail
= new;
169 /* In case of insertion is made at the tail of access_list. */
171 new->prev
= list
->tail
;
172 list
->tail
->next
= new;
177 /* In case of insertion is made at the head of access_list. */
178 if (point
== list
->head
) {
179 new->next
= list
->head
;
180 list
->head
->prev
= new;
185 /* Insertion is made at middle of the access_list. */
187 new->prev
= point
->prev
;
190 point
->prev
->next
= new;
196 struct community_list
*community_list_lookup(struct community_list_handler
*ch
,
197 const char *name
, int master
)
199 struct community_list
*list
;
200 struct community_list_master
*cm
;
205 cm
= community_list_master_lookup(ch
, master
);
209 for (list
= cm
->num
.head
; list
; list
= list
->next
)
210 if (strcmp(list
->name
, name
) == 0)
212 for (list
= cm
->str
.head
; list
; list
= list
->next
)
213 if (strcmp(list
->name
, name
) == 0)
219 static struct community_list
*
220 community_list_get(struct community_list_handler
*ch
, const char *name
,
223 struct community_list
*list
;
225 list
= community_list_lookup(ch
, name
, master
);
227 list
= community_list_insert(ch
, name
, master
);
231 static void community_list_delete(struct community_list
*list
)
233 struct community_list_list
*clist
;
234 struct community_entry
*entry
, *next
;
236 for (entry
= list
->head
; entry
; entry
= next
) {
238 community_entry_free(entry
);
241 clist
= list
->parent
;
244 list
->next
->prev
= list
->prev
;
246 clist
->tail
= list
->prev
;
249 list
->prev
->next
= list
->next
;
251 clist
->head
= list
->next
;
253 community_list_free(list
);
256 static int community_list_empty_p(struct community_list
*list
)
258 return (list
->head
== NULL
&& list
->tail
== NULL
) ? 1 : 0;
261 /* Add community-list entry to the list. */
262 static void community_list_entry_add(struct community_list
*list
,
263 struct community_entry
*entry
)
266 entry
->prev
= list
->tail
;
269 list
->tail
->next
= entry
;
275 /* Delete community-list entry from the list. */
276 static void community_list_entry_delete(struct community_list
*list
,
277 struct community_entry
*entry
,
281 entry
->next
->prev
= entry
->prev
;
283 list
->tail
= entry
->prev
;
286 entry
->prev
->next
= entry
->next
;
288 list
->head
= entry
->next
;
290 community_entry_free(entry
);
292 if (community_list_empty_p(list
))
293 community_list_delete(list
);
296 /* Lookup community-list entry from the list. */
297 static struct community_entry
*
298 community_list_entry_lookup(struct community_list
*list
, const void *arg
,
301 struct community_entry
*entry
;
303 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
304 switch (entry
->style
) {
305 case COMMUNITY_LIST_STANDARD
:
306 if (entry
->direct
== direct
307 && community_cmp(entry
->u
.com
, arg
))
310 case EXTCOMMUNITY_LIST_STANDARD
:
311 if (entry
->direct
== direct
312 && ecommunity_cmp(entry
->u
.ecom
, arg
))
315 case LARGE_COMMUNITY_LIST_STANDARD
:
316 if (entry
->direct
== direct
317 && lcommunity_cmp(entry
->u
.lcom
, arg
))
320 case COMMUNITY_LIST_EXPANDED
:
321 case EXTCOMMUNITY_LIST_EXPANDED
:
322 case LARGE_COMMUNITY_LIST_EXPANDED
:
323 if (entry
->direct
== direct
324 && strcmp(entry
->config
, arg
) == 0)
334 static char *community_str_get(struct community
*com
, int i
)
343 memcpy(&comval
, com_nthval(com
, i
), sizeof(uint32_t));
344 comval
= ntohl(comval
);
347 case COMMUNITY_INTERNET
:
348 len
= strlen(" internet");
350 case COMMUNITY_NO_EXPORT
:
351 len
= strlen(" no-export");
353 case COMMUNITY_NO_ADVERTISE
:
354 len
= strlen(" no-advertise");
356 case COMMUNITY_LOCAL_AS
:
357 len
= strlen(" local-AS");
359 case COMMUNITY_GSHUT
:
360 len
= strlen(" graceful-shutdown");
363 len
= strlen(" 65536:65535");
367 /* Allocate memory. */
368 str
= pnt
= XMALLOC(MTYPE_COMMUNITY_STR
, len
);
371 case COMMUNITY_INTERNET
:
372 strcpy(pnt
, "internet");
373 pnt
+= strlen("internet");
375 case COMMUNITY_NO_EXPORT
:
376 strcpy(pnt
, "no-export");
377 pnt
+= strlen("no-export");
379 case COMMUNITY_NO_ADVERTISE
:
380 strcpy(pnt
, "no-advertise");
381 pnt
+= strlen("no-advertise");
383 case COMMUNITY_LOCAL_AS
:
384 strcpy(pnt
, "local-AS");
385 pnt
+= strlen("local-AS");
387 case COMMUNITY_GSHUT
:
388 strcpy(pnt
, "graceful-shutdown");
389 pnt
+= strlen("graceful-shutdown");
392 as
= (comval
>> 16) & 0xFFFF;
393 val
= comval
& 0xFFFF;
394 sprintf(pnt
, "%u:%d", as
, val
);
404 /* Internal function to perform regular expression match for
405 * a single community. */
406 static int community_regexp_include(regex_t
*reg
, struct community
*com
, int i
)
411 /* When there is no communities attribute it is treated as empty string.
413 if (com
== NULL
|| com
->size
== 0)
414 str
= XSTRDUP(MTYPE_COMMUNITY_STR
, "");
416 str
= community_str_get(com
, i
);
418 /* Regular expression match. */
419 rv
= regexec(reg
, str
, 0, NULL
, 0);
421 XFREE(MTYPE_COMMUNITY_STR
, str
);
430 /* Internal function to perform regular expression match for community
432 static int community_regexp_match(struct community
*com
, regex_t
*reg
)
436 /* When there is no communities attribute it is treated as empty
438 if (com
== NULL
|| com
->size
== 0)
441 str
= community_str(com
, false);
443 /* Regular expression match. */
444 if (regexec(reg
, str
, 0, NULL
, 0) == 0)
451 static char *lcommunity_str_get(struct lcommunity
*lcom
, int i
)
453 struct lcommunity_val lcomval
;
454 uint32_t globaladmin
;
461 ptr
= lcom
->val
+ (i
* LCOMMUNITY_SIZE
);
463 memcpy(&lcomval
, ptr
, LCOMMUNITY_SIZE
);
465 /* Allocate memory. 48 bytes taken off bgp_lcommunity.c */
466 str
= pnt
= XMALLOC(MTYPE_LCOMMUNITY_STR
, 48);
468 ptr
= (uint8_t *)lcomval
.val
;
469 ptr
= ptr_get_be32(ptr
, &globaladmin
);
470 ptr
= ptr_get_be32(ptr
, &localdata1
);
471 ptr
= ptr_get_be32(ptr
, &localdata2
);
472 (void)ptr
; /* consume value */
474 sprintf(pnt
, "%u:%u:%u", globaladmin
, localdata1
, localdata2
);
481 /* Internal function to perform regular expression match for
482 * a single community. */
483 static int lcommunity_regexp_include(regex_t
*reg
, struct lcommunity
*lcom
,
488 /* When there is no communities attribute it is treated as empty string.
490 if (lcom
== NULL
|| lcom
->size
== 0)
491 str
= XSTRDUP(MTYPE_LCOMMUNITY_STR
, "");
493 str
= lcommunity_str_get(lcom
, i
);
495 /* Regular expression match. */
496 if (regexec(reg
, str
, 0, NULL
, 0) == 0) {
497 XFREE(MTYPE_LCOMMUNITY_STR
, str
);
501 XFREE(MTYPE_LCOMMUNITY_STR
, str
);
506 static int lcommunity_regexp_match(struct lcommunity
*com
, regex_t
*reg
)
510 /* When there is no communities attribute it is treated as empty
512 if (com
== NULL
|| com
->size
== 0)
515 str
= lcommunity_str(com
);
517 /* Regular expression match. */
518 if (regexec(reg
, str
, 0, NULL
, 0) == 0)
526 static int ecommunity_regexp_match(struct ecommunity
*ecom
, regex_t
*reg
)
530 /* When there is no communities attribute it is treated as empty
532 if (ecom
== NULL
|| ecom
->size
== 0)
535 str
= ecommunity_str(ecom
);
537 /* Regular expression match. */
538 if (regexec(reg
, str
, 0, NULL
, 0) == 0)
546 /* Delete community attribute using regular expression match. Return
547 modified communites attribute. */
548 static struct community
*
549 community_regexp_delete (struct community
*com
, regex_t
* reg
)
553 /* Maximum is "65535:65535" + '\0'. */
561 while (i
< com
->size
)
563 memcpy (&comval
, com_nthval (com
, i
), sizeof (uint32_t));
564 comval
= ntohl (comval
);
568 case COMMUNITY_INTERNET
:
571 case COMMUNITY_NO_EXPORT
:
574 case COMMUNITY_NO_ADVERTISE
:
575 str
= "no-advertise";
577 case COMMUNITY_LOCAL_AS
:
581 sprintf (c
, "%d:%d", (comval
>> 16) & 0xFFFF, comval
& 0xFFFF);
586 if (regexec (reg
, str
, 0, NULL
, 0) == 0)
587 community_del_val (com
, com_nthval (com
, i
));
595 /* When given community attribute matches to the community-list return
597 int community_list_match(struct community
*com
, struct community_list
*list
)
599 struct community_entry
*entry
;
601 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
603 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
605 if (entry
->style
== COMMUNITY_LIST_STANDARD
) {
606 if (community_include(entry
->u
.com
, COMMUNITY_INTERNET
))
607 return entry
->direct
== COMMUNITY_PERMIT
? 1
610 if (community_match(com
, entry
->u
.com
))
611 return entry
->direct
== COMMUNITY_PERMIT
? 1
613 } else if (entry
->style
== COMMUNITY_LIST_EXPANDED
) {
614 if (community_regexp_match(com
, entry
->reg
))
615 return entry
->direct
== COMMUNITY_PERMIT
? 1
622 int lcommunity_list_match(struct lcommunity
*lcom
, struct community_list
*list
)
624 struct community_entry
*entry
;
626 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
628 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
630 if (entry
->style
== LARGE_COMMUNITY_LIST_STANDARD
) {
631 if (lcommunity_match(lcom
, entry
->u
.lcom
))
632 return entry
->direct
== COMMUNITY_PERMIT
? 1
634 } else if (entry
->style
== LARGE_COMMUNITY_LIST_EXPANDED
) {
635 if (lcommunity_regexp_match(lcom
, entry
->reg
))
636 return entry
->direct
== COMMUNITY_PERMIT
? 1
643 int ecommunity_list_match(struct ecommunity
*ecom
, struct community_list
*list
)
645 struct community_entry
*entry
;
647 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
649 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
651 if (entry
->style
== EXTCOMMUNITY_LIST_STANDARD
) {
652 if (ecommunity_match(ecom
, entry
->u
.ecom
))
653 return entry
->direct
== COMMUNITY_PERMIT
? 1
655 } else if (entry
->style
== EXTCOMMUNITY_LIST_EXPANDED
) {
656 if (ecommunity_regexp_match(ecom
, entry
->reg
))
657 return entry
->direct
== COMMUNITY_PERMIT
? 1
664 /* Perform exact matching. In case of expanded community-list, do
665 same thing as community_list_match(). */
666 int community_list_exact_match(struct community
*com
,
667 struct community_list
*list
)
669 struct community_entry
*entry
;
671 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
673 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
675 if (entry
->style
== COMMUNITY_LIST_STANDARD
) {
676 if (community_include(entry
->u
.com
, COMMUNITY_INTERNET
))
677 return entry
->direct
== COMMUNITY_PERMIT
? 1
680 if (community_cmp(com
, entry
->u
.com
))
681 return entry
->direct
== COMMUNITY_PERMIT
? 1
683 } else if (entry
->style
== COMMUNITY_LIST_EXPANDED
) {
684 if (community_regexp_match(com
, entry
->reg
))
685 return entry
->direct
== COMMUNITY_PERMIT
? 1
692 /* Delete all permitted communities in the list from com. */
693 struct community
*community_list_match_delete(struct community
*com
,
694 struct community_list
*list
)
696 struct community_entry
*entry
;
698 uint32_t com_index_to_delete
[com
->size
];
699 int delete_index
= 0;
702 /* Loop over each community value and evaluate each against the
703 * community-list. If we need to delete a community value add its index
704 * to com_index_to_delete.
706 for (i
= 0; i
< com
->size
; i
++) {
707 val
= community_val_get(com
, i
);
709 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
711 if (entry
->direct
== COMMUNITY_PERMIT
) {
712 com_index_to_delete
[delete_index
] = i
;
718 else if ((entry
->style
== COMMUNITY_LIST_STANDARD
)
719 && (community_include(entry
->u
.com
,
721 || community_include(entry
->u
.com
, val
))) {
722 if (entry
->direct
== COMMUNITY_PERMIT
) {
723 com_index_to_delete
[delete_index
] = i
;
729 else if ((entry
->style
== COMMUNITY_LIST_EXPANDED
)
730 && community_regexp_include(entry
->reg
, com
,
732 if (entry
->direct
== COMMUNITY_PERMIT
) {
733 com_index_to_delete
[delete_index
] = i
;
741 /* Delete all of the communities we flagged for deletion */
742 for (i
= delete_index
- 1; i
>= 0; i
--) {
743 val
= community_val_get(com
, com_index_to_delete
[i
]);
744 community_del_val(com
, &val
);
750 /* To avoid duplicated entry in the community-list, this function
751 compares specified entry to existing entry. */
752 static int community_list_dup_check(struct community_list
*list
,
753 struct community_entry
*new)
755 struct community_entry
*entry
;
757 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
758 if (entry
->style
!= new->style
)
761 if (entry
->direct
!= new->direct
)
764 if (entry
->any
!= new->any
)
770 switch (entry
->style
) {
771 case COMMUNITY_LIST_STANDARD
:
772 if (community_cmp(entry
->u
.com
, new->u
.com
))
775 case LARGE_COMMUNITY_LIST_STANDARD
:
776 if (lcommunity_cmp(entry
->u
.lcom
, new->u
.lcom
))
779 case EXTCOMMUNITY_LIST_STANDARD
:
780 if (ecommunity_cmp(entry
->u
.ecom
, new->u
.ecom
))
783 case COMMUNITY_LIST_EXPANDED
:
784 case EXTCOMMUNITY_LIST_EXPANDED
:
785 case LARGE_COMMUNITY_LIST_EXPANDED
:
786 if (strcmp(entry
->config
, new->config
) == 0)
796 /* Set community-list. */
797 int community_list_set(struct community_list_handler
*ch
, const char *name
,
798 const char *str
, int direct
, int style
)
800 struct community_entry
*entry
= NULL
;
801 struct community_list
*list
;
802 struct community
*com
= NULL
;
803 regex_t
*regex
= NULL
;
805 /* Get community list. */
806 list
= community_list_get(ch
, name
, COMMUNITY_LIST_MASTER
);
808 /* When community-list already has entry, new entry should have same
809 style. If you want to have mixed style community-list, you can
810 comment out this check. */
811 if (!community_list_empty_p(list
)) {
812 struct community_entry
*first
;
816 if (style
!= first
->style
) {
817 return (first
->style
== COMMUNITY_LIST_STANDARD
818 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
819 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT
);
824 if (style
== COMMUNITY_LIST_STANDARD
)
825 com
= community_str2com(str
);
827 regex
= bgp_regcomp(str
);
830 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
833 entry
= community_entry_new();
834 entry
->direct
= direct
;
835 entry
->style
= style
;
836 entry
->any
= (str
? 0 : 1);
840 (regex
? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG
, str
) : NULL
);
842 /* Do not put duplicated community entry. */
843 if (community_list_dup_check(list
, entry
))
844 community_entry_free(entry
);
846 community_list_entry_add(list
, entry
);
847 route_map_notify_dependencies(name
, RMAP_EVENT_CLIST_ADDED
);
853 /* Unset community-list */
854 int community_list_unset(struct community_list_handler
*ch
, const char *name
,
855 const char *str
, int direct
, int style
)
857 struct community_entry
*entry
= NULL
;
858 struct community_list
*list
;
859 struct community
*com
= NULL
;
861 /* Lookup community list. */
862 list
= community_list_lookup(ch
, name
, COMMUNITY_LIST_MASTER
);
864 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
866 /* Delete all of entry belongs to this community-list. */
868 community_list_delete(list
);
869 route_map_notify_dependencies(name
, RMAP_EVENT_CLIST_DELETED
);
873 if (style
== COMMUNITY_LIST_STANDARD
)
874 com
= community_str2com(str
);
877 entry
= community_list_entry_lookup(list
, com
, direct
);
880 entry
= community_list_entry_lookup(list
, str
, direct
);
883 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
885 community_list_entry_delete(list
, entry
, style
);
886 route_map_notify_dependencies(name
, RMAP_EVENT_CLIST_DELETED
);
891 /* Delete all permitted large communities in the list from com. */
892 struct lcommunity
*lcommunity_list_match_delete(struct lcommunity
*lcom
,
893 struct community_list
*list
)
895 struct community_entry
*entry
;
896 uint32_t com_index_to_delete
[lcom
->size
];
898 int delete_index
= 0;
901 /* Loop over each lcommunity value and evaluate each against the
902 * community-list. If we need to delete a community value add its index
903 * to com_index_to_delete.
905 for (i
= 0; i
< lcom
->size
; i
++) {
906 ptr
= lcom
->val
+ (i
* LCOMMUNITY_SIZE
);
907 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
909 if (entry
->direct
== COMMUNITY_PERMIT
) {
910 com_index_to_delete
[delete_index
] = i
;
916 else if ((entry
->style
== LARGE_COMMUNITY_LIST_STANDARD
)
917 && lcommunity_include(entry
->u
.lcom
, ptr
)) {
918 if (entry
->direct
== COMMUNITY_PERMIT
) {
919 com_index_to_delete
[delete_index
] = i
;
925 else if ((entry
->style
== LARGE_COMMUNITY_LIST_EXPANDED
)
926 && lcommunity_regexp_include(entry
->reg
, lcom
,
928 if (entry
->direct
== COMMUNITY_PERMIT
) {
929 com_index_to_delete
[delete_index
] = i
;
937 /* Delete all of the communities we flagged for deletion */
938 for (i
= delete_index
- 1; i
>= 0; i
--) {
939 ptr
= lcom
->val
+ (com_index_to_delete
[i
] * LCOMMUNITY_SIZE
);
940 lcommunity_del_val(lcom
, ptr
);
946 /* Set lcommunity-list. */
947 int lcommunity_list_set(struct community_list_handler
*ch
, const char *name
,
948 const char *str
, int direct
, int style
)
950 struct community_entry
*entry
= NULL
;
951 struct community_list
*list
;
952 struct lcommunity
*lcom
= NULL
;
953 regex_t
*regex
= NULL
;
955 /* Get community list. */
956 list
= community_list_get(ch
, name
, LARGE_COMMUNITY_LIST_MASTER
);
958 /* When community-list already has entry, new entry should have same
959 style. If you want to have mixed style community-list, you can
960 comment out this check. */
961 if (!community_list_empty_p(list
)) {
962 struct community_entry
*first
;
966 if (style
!= first
->style
) {
967 return (first
->style
== COMMUNITY_LIST_STANDARD
968 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
969 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT
);
974 if (style
== LARGE_COMMUNITY_LIST_STANDARD
)
975 lcom
= lcommunity_str2com(str
);
977 regex
= bgp_regcomp(str
);
980 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
983 entry
= community_entry_new();
984 entry
->direct
= direct
;
985 entry
->style
= style
;
986 entry
->any
= (str
? 0 : 1);
987 entry
->u
.lcom
= lcom
;
990 entry
->config
= lcommunity_lcom2str(
991 lcom
, LCOMMUNITY_FORMAT_COMMUNITY_LIST
);
993 entry
->config
= XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG
, str
);
995 entry
->config
= NULL
;
997 /* Do not put duplicated community entry. */
998 if (community_list_dup_check(list
, entry
))
999 community_entry_free(entry
);
1001 community_list_entry_add(list
, entry
);
1006 /* Unset community-list. When str is NULL, delete all of
1007 community-list entry belongs to the specified name. */
1008 int lcommunity_list_unset(struct community_list_handler
*ch
, const char *name
,
1009 const char *str
, int direct
, int style
)
1011 struct community_entry
*entry
= NULL
;
1012 struct community_list
*list
;
1013 struct lcommunity
*lcom
= NULL
;
1014 regex_t
*regex
= NULL
;
1016 /* Lookup community list. */
1017 list
= community_list_lookup(ch
, name
, LARGE_COMMUNITY_LIST_MASTER
);
1019 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1021 /* Delete all of entry belongs to this community-list. */
1023 community_list_delete(list
);
1027 if (style
== LARGE_COMMUNITY_LIST_STANDARD
)
1028 lcom
= lcommunity_str2com(str
);
1030 regex
= bgp_regcomp(str
);
1032 if (!lcom
&& !regex
)
1033 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
1036 entry
= community_list_entry_lookup(list
, lcom
, direct
);
1038 entry
= community_list_entry_lookup(list
, str
, direct
);
1041 lcommunity_free(&lcom
);
1043 bgp_regex_free(regex
);
1046 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1048 community_list_entry_delete(list
, entry
, style
);
1053 /* Set extcommunity-list. */
1054 int extcommunity_list_set(struct community_list_handler
*ch
, const char *name
,
1055 const char *str
, int direct
, int style
)
1057 struct community_entry
*entry
= NULL
;
1058 struct community_list
*list
;
1059 struct ecommunity
*ecom
= NULL
;
1060 regex_t
*regex
= NULL
;
1064 /* Get community list. */
1065 list
= community_list_get(ch
, name
, EXTCOMMUNITY_LIST_MASTER
);
1067 /* When community-list already has entry, new entry should have same
1068 style. If you want to have mixed style community-list, you can
1069 comment out this check. */
1070 if (!community_list_empty_p(list
)) {
1071 struct community_entry
*first
;
1075 if (style
!= first
->style
) {
1076 return (first
->style
== EXTCOMMUNITY_LIST_STANDARD
1077 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
1078 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT
);
1082 if (style
== EXTCOMMUNITY_LIST_STANDARD
)
1083 ecom
= ecommunity_str2com(str
, 0, 1);
1085 regex
= bgp_regcomp(str
);
1087 if (!ecom
&& !regex
)
1088 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
1092 ecommunity_ecom2str(ecom
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
1094 entry
= community_entry_new();
1095 entry
->direct
= direct
;
1096 entry
->style
= style
;
1097 entry
->any
= (str
? 0 : 1);
1099 entry
->config
= ecommunity_ecom2str(
1100 ecom
, ECOMMUNITY_FORMAT_COMMUNITY_LIST
, 0);
1102 entry
->config
= XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG
, str
);
1104 entry
->u
.ecom
= ecom
;
1107 /* Do not put duplicated community entry. */
1108 if (community_list_dup_check(list
, entry
))
1109 community_entry_free(entry
);
1111 community_list_entry_add(list
, entry
);
1112 route_map_notify_dependencies(name
, RMAP_EVENT_ECLIST_ADDED
);
1118 /* Unset extcommunity-list.
1120 * When str is NULL, delete all extcommunity-list entries belonging to the
1123 int extcommunity_list_unset(struct community_list_handler
*ch
, const char *name
,
1124 const char *str
, int direct
, int style
)
1126 struct community_entry
*entry
= NULL
;
1127 struct community_list
*list
;
1128 struct ecommunity
*ecom
= NULL
;
1130 /* Lookup extcommunity list. */
1131 list
= community_list_lookup(ch
, name
, EXTCOMMUNITY_LIST_MASTER
);
1133 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1135 /* Delete all of entry belongs to this extcommunity-list. */
1137 community_list_delete(list
);
1138 route_map_notify_dependencies(name
, RMAP_EVENT_ECLIST_DELETED
);
1142 if (style
== EXTCOMMUNITY_LIST_STANDARD
)
1143 ecom
= ecommunity_str2com(str
, 0, 1);
1146 entry
= community_list_entry_lookup(list
, ecom
, direct
);
1147 ecommunity_free(&ecom
);
1149 entry
= community_list_entry_lookup(list
, str
, direct
);
1152 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1154 community_list_entry_delete(list
, entry
, style
);
1155 route_map_notify_dependencies(name
, RMAP_EVENT_ECLIST_DELETED
);
1160 /* Initializa community-list. Return community-list handler. */
1161 struct community_list_handler
*community_list_init(void)
1163 struct community_list_handler
*ch
;
1164 ch
= XCALLOC(MTYPE_COMMUNITY_LIST_HANDLER
,
1165 sizeof(struct community_list_handler
));
1169 /* Terminate community-list. */
1170 void community_list_terminate(struct community_list_handler
*ch
)
1172 struct community_list_master
*cm
;
1173 struct community_list
*list
;
1175 cm
= &ch
->community_list
;
1176 while ((list
= cm
->num
.head
) != NULL
)
1177 community_list_delete(list
);
1178 while ((list
= cm
->str
.head
) != NULL
)
1179 community_list_delete(list
);
1181 cm
= &ch
->lcommunity_list
;
1182 while ((list
= cm
->num
.head
) != NULL
)
1183 community_list_delete(list
);
1184 while ((list
= cm
->str
.head
) != NULL
)
1185 community_list_delete(list
);
1187 cm
= &ch
->extcommunity_list
;
1188 while ((list
= cm
->num
.head
) != NULL
)
1189 community_list_delete(list
);
1190 while ((list
= cm
->str
.head
) != NULL
)
1191 community_list_delete(list
);
1193 XFREE(MTYPE_COMMUNITY_LIST_HANDLER
, ch
);