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
29 #include "bgpd/bgpd.h"
30 #include "bgpd/bgp_community.h"
31 #include "bgpd/bgp_ecommunity.h"
32 #include "bgpd/bgp_lcommunity.h"
33 #include "bgpd/bgp_aspath.h"
34 #include "bgpd/bgp_regex.h"
35 #include "bgpd/bgp_clist.h"
37 /* Lookup master structure for community-list or
39 struct community_list_master
*
40 community_list_master_lookup(struct community_list_handler
*ch
, int master
)
44 case COMMUNITY_LIST_MASTER
:
45 return &ch
->community_list
;
46 case EXTCOMMUNITY_LIST_MASTER
:
47 return &ch
->extcommunity_list
;
48 case LARGE_COMMUNITY_LIST_MASTER
:
49 return &ch
->lcommunity_list
;
54 /* Allocate a new community list entry. */
55 static struct community_entry
*community_entry_new(void)
57 return XCALLOC(MTYPE_COMMUNITY_LIST_ENTRY
,
58 sizeof(struct community_entry
));
61 /* Free community list entry. */
62 static void community_entry_free(struct community_entry
*entry
)
64 switch (entry
->style
) {
65 case COMMUNITY_LIST_STANDARD
:
67 community_free(entry
->u
.com
);
69 case LARGE_COMMUNITY_LIST_STANDARD
:
71 lcommunity_free(&entry
->u
.lcom
);
73 case EXTCOMMUNITY_LIST_STANDARD
:
74 /* In case of standard extcommunity-list, configuration string
75 is made by ecommunity_ecom2str(). */
77 XFREE(MTYPE_ECOMMUNITY_STR
, entry
->config
);
79 ecommunity_free(&entry
->u
.ecom
);
81 case COMMUNITY_LIST_EXPANDED
:
82 case EXTCOMMUNITY_LIST_EXPANDED
:
83 case LARGE_COMMUNITY_LIST_EXPANDED
:
85 XFREE(MTYPE_COMMUNITY_LIST_CONFIG
, entry
->config
);
87 bgp_regex_free(entry
->reg
);
91 XFREE(MTYPE_COMMUNITY_LIST_ENTRY
, entry
);
94 /* Allocate a new community-list. */
95 static struct community_list
*community_list_new(void)
97 return XCALLOC(MTYPE_COMMUNITY_LIST
, sizeof(struct community_list
));
100 /* Free community-list. */
101 static void community_list_free(struct community_list
*list
)
104 XFREE(MTYPE_COMMUNITY_LIST_NAME
, list
->name
);
105 XFREE(MTYPE_COMMUNITY_LIST
, list
);
108 static struct community_list
*
109 community_list_insert(struct community_list_handler
*ch
, const char *name
,
114 struct community_list
*new;
115 struct community_list
*point
;
116 struct community_list_list
*list
;
117 struct community_list_master
*cm
;
119 /* Lookup community-list master. */
120 cm
= community_list_master_lookup(ch
, master
);
124 /* Allocate new community_list and copy given name. */
125 new = community_list_new();
126 new->name
= XSTRDUP(MTYPE_COMMUNITY_LIST_NAME
, name
);
128 /* If name is made by all digit character. We treat it as
130 for (number
= 0, i
= 0; i
< strlen(name
); i
++) {
131 if (isdigit((int)name
[i
]))
132 number
= (number
* 10) + (name
[i
] - '0');
137 /* In case of name is all digit character */
138 if (i
== strlen(name
)) {
139 new->sort
= COMMUNITY_LIST_NUMBER
;
141 /* Set access_list to number list. */
144 for (point
= list
->head
; point
; point
= point
->next
)
145 if (atol(point
->name
) >= number
)
148 new->sort
= COMMUNITY_LIST_STRING
;
150 /* Set access_list to string list. */
153 /* Set point to insertion point. */
154 for (point
= list
->head
; point
; point
= point
->next
)
155 if (strcmp(point
->name
, name
) >= 0)
159 /* Link to upper list. */
162 /* In case of this is the first element of master. */
163 if (list
->head
== NULL
) {
164 list
->head
= list
->tail
= new;
168 /* In case of insertion is made at the tail of access_list. */
170 new->prev
= list
->tail
;
171 list
->tail
->next
= new;
176 /* In case of insertion is made at the head of access_list. */
177 if (point
== list
->head
) {
178 new->next
= list
->head
;
179 list
->head
->prev
= new;
184 /* Insertion is made at middle of the access_list. */
186 new->prev
= point
->prev
;
189 point
->prev
->next
= new;
195 struct community_list
*community_list_lookup(struct community_list_handler
*ch
,
196 const char *name
, int master
)
198 struct community_list
*list
;
199 struct community_list_master
*cm
;
204 cm
= community_list_master_lookup(ch
, master
);
208 for (list
= cm
->num
.head
; list
; list
= list
->next
)
209 if (strcmp(list
->name
, name
) == 0)
211 for (list
= cm
->str
.head
; list
; list
= list
->next
)
212 if (strcmp(list
->name
, name
) == 0)
218 static struct community_list
*
219 community_list_get(struct community_list_handler
*ch
, const char *name
,
222 struct community_list
*list
;
224 list
= community_list_lookup(ch
, name
, master
);
226 list
= community_list_insert(ch
, name
, master
);
230 static void community_list_delete(struct community_list
*list
)
232 struct community_list_list
*clist
;
233 struct community_entry
*entry
, *next
;
235 for (entry
= list
->head
; entry
; entry
= next
) {
237 community_entry_free(entry
);
240 clist
= list
->parent
;
243 list
->next
->prev
= list
->prev
;
245 clist
->tail
= list
->prev
;
248 list
->prev
->next
= list
->next
;
250 clist
->head
= list
->next
;
252 community_list_free(list
);
255 static int community_list_empty_p(struct community_list
*list
)
257 return (list
->head
== NULL
&& list
->tail
== NULL
) ? 1 : 0;
260 /* Add community-list entry to the list. */
261 static void community_list_entry_add(struct community_list
*list
,
262 struct community_entry
*entry
)
265 entry
->prev
= list
->tail
;
268 list
->tail
->next
= entry
;
274 /* Delete community-list entry from the list. */
275 static void community_list_entry_delete(struct community_list
*list
,
276 struct community_entry
*entry
,
280 entry
->next
->prev
= entry
->prev
;
282 list
->tail
= entry
->prev
;
285 entry
->prev
->next
= entry
->next
;
287 list
->head
= entry
->next
;
289 community_entry_free(entry
);
291 if (community_list_empty_p(list
))
292 community_list_delete(list
);
295 /* Lookup community-list entry from the list. */
296 static struct community_entry
*
297 community_list_entry_lookup(struct community_list
*list
, const void *arg
,
300 struct community_entry
*entry
;
302 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
303 switch (entry
->style
) {
304 case COMMUNITY_LIST_STANDARD
:
305 if (entry
->direct
== direct
306 && community_cmp(entry
->u
.com
, arg
))
309 case EXTCOMMUNITY_LIST_STANDARD
:
310 if (entry
->direct
== direct
311 && ecommunity_cmp(entry
->u
.ecom
, arg
))
314 case LARGE_COMMUNITY_LIST_STANDARD
:
315 if (entry
->direct
== direct
316 && lcommunity_cmp(entry
->u
.lcom
, arg
))
319 case COMMUNITY_LIST_EXPANDED
:
320 case EXTCOMMUNITY_LIST_EXPANDED
:
321 case LARGE_COMMUNITY_LIST_EXPANDED
:
322 if (entry
->direct
== direct
323 && strcmp(entry
->config
, arg
) == 0)
333 static char *community_str_get(struct community
*com
, int i
)
342 memcpy(&comval
, com_nthval(com
, i
), sizeof(u_int32_t
));
343 comval
= ntohl(comval
);
346 case COMMUNITY_INTERNET
:
347 len
= strlen(" internet");
349 case COMMUNITY_NO_EXPORT
:
350 len
= strlen(" no-export");
352 case COMMUNITY_NO_ADVERTISE
:
353 len
= strlen(" no-advertise");
355 case COMMUNITY_LOCAL_AS
:
356 len
= strlen(" local-AS");
359 len
= strlen(" 65536:65535");
363 /* Allocate memory. */
364 str
= pnt
= XMALLOC(MTYPE_COMMUNITY_STR
, len
);
367 case COMMUNITY_INTERNET
:
368 strcpy(pnt
, "internet");
369 pnt
+= strlen("internet");
371 case COMMUNITY_NO_EXPORT
:
372 strcpy(pnt
, "no-export");
373 pnt
+= strlen("no-export");
375 case COMMUNITY_NO_ADVERTISE
:
376 strcpy(pnt
, "no-advertise");
377 pnt
+= strlen("no-advertise");
379 case COMMUNITY_LOCAL_AS
:
380 strcpy(pnt
, "local-AS");
381 pnt
+= strlen("local-AS");
384 as
= (comval
>> 16) & 0xFFFF;
385 val
= comval
& 0xFFFF;
386 sprintf(pnt
, "%u:%d", as
, val
);
396 /* Internal function to perform regular expression match for
397 * a single community. */
398 static int community_regexp_include(regex_t
*reg
, struct community
*com
, int i
)
403 /* When there is no communities attribute it is treated as empty string.
405 if (com
== NULL
|| com
->size
== 0)
406 str
= XSTRDUP(MTYPE_COMMUNITY_STR
, "");
408 str
= community_str_get(com
, i
);
410 /* Regular expression match. */
411 rv
= regexec(reg
, str
, 0, NULL
, 0);
413 XFREE(MTYPE_COMMUNITY_STR
, str
);
422 /* Internal function to perform regular expression match for community
424 static int community_regexp_match(struct community
*com
, regex_t
*reg
)
428 /* When there is no communities attribute it is treated as empty
430 if (com
== NULL
|| com
->size
== 0)
433 str
= community_str(com
);
435 /* Regular expression match. */
436 if (regexec(reg
, str
, 0, NULL
, 0) == 0)
443 static char *lcommunity_str_get(struct lcommunity
*lcom
, int i
)
445 struct lcommunity_val lcomval
;
446 u_int32_t globaladmin
;
447 u_int32_t localdata1
;
448 u_int32_t localdata2
;
453 ptr
= lcom
->val
+ (i
* LCOMMUNITY_SIZE
);
455 memcpy(&lcomval
, ptr
, LCOMMUNITY_SIZE
);
457 /* Allocate memory. 48 bytes taken off bgp_lcommunity.c */
458 str
= pnt
= XMALLOC(MTYPE_LCOMMUNITY_STR
, 48);
460 ptr
= (u_char
*)lcomval
.val
;
461 globaladmin
= (*ptr
++ << 24);
462 globaladmin
|= (*ptr
++ << 16);
463 globaladmin
|= (*ptr
++ << 8);
464 globaladmin
|= (*ptr
++);
466 localdata1
= (*ptr
++ << 24);
467 localdata1
|= (*ptr
++ << 16);
468 localdata1
|= (*ptr
++ << 8);
469 localdata1
|= (*ptr
++);
471 localdata2
= (*ptr
++ << 24);
472 localdata2
|= (*ptr
++ << 16);
473 localdata2
|= (*ptr
++ << 8);
474 localdata2
|= (*ptr
++);
476 sprintf(pnt
, "%u:%u:%u", globaladmin
, localdata1
, localdata2
);
483 /* Internal function to perform regular expression match for
484 * a single community. */
485 static int lcommunity_regexp_include(regex_t
*reg
, struct lcommunity
*lcom
,
490 /* When there is no communities attribute it is treated as empty string.
492 if (lcom
== NULL
|| lcom
->size
== 0)
493 str
= XSTRDUP(MTYPE_LCOMMUNITY_STR
, "");
495 str
= lcommunity_str_get(lcom
, i
);
497 /* Regular expression match. */
498 if (regexec(reg
, str
, 0, NULL
, 0) == 0) {
499 XFREE(MTYPE_LCOMMUNITY_STR
, str
);
503 XFREE(MTYPE_LCOMMUNITY_STR
, str
);
508 static int lcommunity_regexp_match(struct lcommunity
*com
, regex_t
*reg
)
512 /* When there is no communities attribute it is treated as empty
514 if (com
== NULL
|| com
->size
== 0)
517 str
= lcommunity_str(com
);
519 /* Regular expression match. */
520 if (regexec(reg
, str
, 0, NULL
, 0) == 0)
528 static int ecommunity_regexp_match(struct ecommunity
*ecom
, regex_t
*reg
)
532 /* When there is no communities attribute it is treated as empty
534 if (ecom
== NULL
|| ecom
->size
== 0)
537 str
= ecommunity_str(ecom
);
539 /* Regular expression match. */
540 if (regexec(reg
, str
, 0, NULL
, 0) == 0)
548 /* Delete community attribute using regular expression match. Return
549 modified communites attribute. */
550 static struct community
*
551 community_regexp_delete (struct community
*com
, regex_t
* reg
)
555 /* Maximum is "65535:65535" + '\0'. */
563 while (i
< com
->size
)
565 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
566 comval
= ntohl (comval
);
570 case COMMUNITY_INTERNET
:
573 case COMMUNITY_NO_EXPORT
:
576 case COMMUNITY_NO_ADVERTISE
:
577 str
= "no-advertise";
579 case COMMUNITY_LOCAL_AS
:
583 sprintf (c
, "%d:%d", (comval
>> 16) & 0xFFFF, comval
& 0xFFFF);
588 if (regexec (reg
, str
, 0, NULL
, 0) == 0)
589 community_del_val (com
, com_nthval (com
, i
));
597 /* When given community attribute matches to the community-list return
599 int community_list_match(struct community
*com
, struct community_list
*list
)
601 struct community_entry
*entry
;
603 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
605 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
607 if (entry
->style
== COMMUNITY_LIST_STANDARD
) {
608 if (community_include(entry
->u
.com
, COMMUNITY_INTERNET
))
609 return entry
->direct
== COMMUNITY_PERMIT
? 1
612 if (community_match(com
, entry
->u
.com
))
613 return entry
->direct
== COMMUNITY_PERMIT
? 1
615 } else if (entry
->style
== COMMUNITY_LIST_EXPANDED
) {
616 if (community_regexp_match(com
, entry
->reg
))
617 return entry
->direct
== COMMUNITY_PERMIT
? 1
624 int lcommunity_list_match(struct lcommunity
*lcom
, struct community_list
*list
)
626 struct community_entry
*entry
;
628 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
630 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
632 if (entry
->style
== LARGE_COMMUNITY_LIST_STANDARD
) {
633 if (lcommunity_match(lcom
, entry
->u
.lcom
))
634 return entry
->direct
== COMMUNITY_PERMIT
? 1
636 } else if (entry
->style
== LARGE_COMMUNITY_LIST_EXPANDED
) {
637 if (lcommunity_regexp_match(lcom
, entry
->reg
))
638 return entry
->direct
== COMMUNITY_PERMIT
? 1
645 int ecommunity_list_match(struct ecommunity
*ecom
, struct community_list
*list
)
647 struct community_entry
*entry
;
649 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
651 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
653 if (entry
->style
== EXTCOMMUNITY_LIST_STANDARD
) {
654 if (ecommunity_match(ecom
, entry
->u
.ecom
))
655 return entry
->direct
== COMMUNITY_PERMIT
? 1
657 } else if (entry
->style
== EXTCOMMUNITY_LIST_EXPANDED
) {
658 if (ecommunity_regexp_match(ecom
, entry
->reg
))
659 return entry
->direct
== COMMUNITY_PERMIT
? 1
666 /* Perform exact matching. In case of expanded community-list, do
667 same thing as community_list_match(). */
668 int community_list_exact_match(struct community
*com
,
669 struct community_list
*list
)
671 struct community_entry
*entry
;
673 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
675 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
677 if (entry
->style
== COMMUNITY_LIST_STANDARD
) {
678 if (community_include(entry
->u
.com
, COMMUNITY_INTERNET
))
679 return entry
->direct
== COMMUNITY_PERMIT
? 1
682 if (community_cmp(com
, entry
->u
.com
))
683 return entry
->direct
== COMMUNITY_PERMIT
? 1
685 } else if (entry
->style
== COMMUNITY_LIST_EXPANDED
) {
686 if (community_regexp_match(com
, entry
->reg
))
687 return entry
->direct
== COMMUNITY_PERMIT
? 1
694 /* Delete all permitted communities in the list from com. */
695 struct community
*community_list_match_delete(struct community
*com
,
696 struct community_list
*list
)
698 struct community_entry
*entry
;
700 u_int32_t com_index_to_delete
[com
->size
];
701 int delete_index
= 0;
704 /* Loop over each community value and evaluate each against the
705 * community-list. If we need to delete a community value add its index
706 * to com_index_to_delete.
708 for (i
= 0; i
< com
->size
; i
++) {
709 val
= community_val_get(com
, i
);
711 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
713 if (entry
->direct
== COMMUNITY_PERMIT
) {
714 com_index_to_delete
[delete_index
] = i
;
720 else if ((entry
->style
== COMMUNITY_LIST_STANDARD
)
721 && (community_include(entry
->u
.com
,
723 || community_include(entry
->u
.com
, val
))) {
724 if (entry
->direct
== COMMUNITY_PERMIT
) {
725 com_index_to_delete
[delete_index
] = i
;
731 else if ((entry
->style
== COMMUNITY_LIST_EXPANDED
)
732 && community_regexp_include(entry
->reg
, com
,
734 if (entry
->direct
== COMMUNITY_PERMIT
) {
735 com_index_to_delete
[delete_index
] = i
;
743 /* Delete all of the communities we flagged for deletion */
744 for (i
= delete_index
- 1; i
>= 0; i
--) {
745 val
= community_val_get(com
, com_index_to_delete
[i
]);
746 community_del_val(com
, &val
);
752 /* To avoid duplicated entry in the community-list, this function
753 compares specified entry to existing entry. */
754 static int community_list_dup_check(struct community_list
*list
,
755 struct community_entry
*new)
757 struct community_entry
*entry
;
759 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
760 if (entry
->style
!= new->style
)
763 if (entry
->direct
!= new->direct
)
766 if (entry
->any
!= new->any
)
772 switch (entry
->style
) {
773 case COMMUNITY_LIST_STANDARD
:
774 if (community_cmp(entry
->u
.com
, new->u
.com
))
777 case LARGE_COMMUNITY_LIST_STANDARD
:
778 if (lcommunity_cmp(entry
->u
.lcom
, new->u
.lcom
))
781 case EXTCOMMUNITY_LIST_STANDARD
:
782 if (ecommunity_cmp(entry
->u
.ecom
, new->u
.ecom
))
785 case COMMUNITY_LIST_EXPANDED
:
786 case EXTCOMMUNITY_LIST_EXPANDED
:
787 case LARGE_COMMUNITY_LIST_EXPANDED
:
788 if (strcmp(entry
->config
, new->config
) == 0)
798 /* Set community-list. */
799 int community_list_set(struct community_list_handler
*ch
, const char *name
,
800 const char *str
, int direct
, int style
)
802 struct community_entry
*entry
= NULL
;
803 struct community_list
*list
;
804 struct community
*com
= NULL
;
805 regex_t
*regex
= NULL
;
807 /* Get community list. */
808 list
= community_list_get(ch
, name
, COMMUNITY_LIST_MASTER
);
810 /* When community-list already has entry, new entry should have same
811 style. If you want to have mixed style community-list, you can
812 comment out this check. */
813 if (!community_list_empty_p(list
)) {
814 struct community_entry
*first
;
818 if (style
!= first
->style
) {
819 return (first
->style
== COMMUNITY_LIST_STANDARD
820 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
821 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT
);
826 if (style
== COMMUNITY_LIST_STANDARD
)
827 com
= community_str2com(str
);
829 regex
= bgp_regcomp(str
);
832 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
835 entry
= community_entry_new();
836 entry
->direct
= direct
;
837 entry
->style
= style
;
838 entry
->any
= (str
? 0 : 1);
842 (regex
? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG
, str
) : NULL
);
844 /* Do not put duplicated community entry. */
845 if (community_list_dup_check(list
, entry
))
846 community_entry_free(entry
);
848 community_list_entry_add(list
, entry
);
849 route_map_notify_dependencies(name
, RMAP_EVENT_CLIST_ADDED
);
855 /* Unset community-list */
856 int community_list_unset(struct community_list_handler
*ch
, const char *name
,
857 const char *str
, int direct
, int style
, int delete_all
)
859 struct community_entry
*entry
= NULL
;
860 struct community_list
*list
;
861 struct community
*com
= NULL
;
863 /* Lookup community list. */
864 list
= community_list_lookup(ch
, name
, COMMUNITY_LIST_MASTER
);
866 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
868 /* Delete all of entry belongs to this community-list. */
870 community_list_delete(list
);
871 route_map_notify_dependencies(name
, RMAP_EVENT_CLIST_DELETED
);
875 if (style
== COMMUNITY_LIST_STANDARD
) {
877 com
= community_str2com(str
);
881 entry
= community_list_entry_lookup(list
, com
, direct
);
884 entry
= community_list_entry_lookup(list
, str
, direct
);
887 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
889 community_list_entry_delete(list
, entry
, style
);
890 route_map_notify_dependencies(name
, RMAP_EVENT_CLIST_DELETED
);
895 /* Delete all permitted large communities in the list from com. */
896 struct lcommunity
*lcommunity_list_match_delete(struct lcommunity
*lcom
,
897 struct community_list
*list
)
899 struct community_entry
*entry
;
900 u_int32_t com_index_to_delete
[lcom
->size
];
902 int delete_index
= 0;
905 /* Loop over each lcommunity value and evaluate each against the
906 * community-list. If we need to delete a community value add its index
907 * to com_index_to_delete.
909 for (i
= 0; i
< lcom
->size
; i
++) {
910 ptr
= lcom
->val
+ (i
* LCOMMUNITY_SIZE
);
911 for (entry
= list
->head
; entry
; entry
= entry
->next
) {
913 if (entry
->direct
== COMMUNITY_PERMIT
) {
914 com_index_to_delete
[delete_index
] = i
;
920 else if ((entry
->style
== LARGE_COMMUNITY_LIST_STANDARD
)
921 && lcommunity_include(entry
->u
.lcom
, ptr
)) {
922 if (entry
->direct
== COMMUNITY_PERMIT
) {
923 com_index_to_delete
[delete_index
] = i
;
929 else if ((entry
->style
== LARGE_COMMUNITY_LIST_EXPANDED
)
930 && lcommunity_regexp_include(entry
->reg
, lcom
,
932 if (entry
->direct
== COMMUNITY_PERMIT
) {
933 com_index_to_delete
[delete_index
] = i
;
941 /* Delete all of the communities we flagged for deletion */
942 for (i
= delete_index
- 1; i
>= 0; i
--) {
943 ptr
= lcom
->val
+ (com_index_to_delete
[i
] * LCOMMUNITY_SIZE
);
944 lcommunity_del_val(lcom
, ptr
);
950 /* Set lcommunity-list. */
951 int lcommunity_list_set(struct community_list_handler
*ch
, const char *name
,
952 const char *str
, int direct
, int style
)
954 struct community_entry
*entry
= NULL
;
955 struct community_list
*list
;
956 struct lcommunity
*lcom
= NULL
;
957 regex_t
*regex
= NULL
;
959 /* Get community list. */
960 list
= community_list_get(ch
, name
, LARGE_COMMUNITY_LIST_MASTER
);
962 /* When community-list already has entry, new entry should have same
963 style. If you want to have mixed style community-list, you can
964 comment out this check. */
965 if (!community_list_empty_p(list
)) {
966 struct community_entry
*first
;
970 if (style
!= first
->style
) {
971 return (first
->style
== COMMUNITY_LIST_STANDARD
972 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
973 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT
);
978 if (style
== LARGE_COMMUNITY_LIST_STANDARD
)
979 lcom
= lcommunity_str2com(str
);
981 regex
= bgp_regcomp(str
);
984 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
987 entry
= community_entry_new();
988 entry
->direct
= direct
;
989 entry
->style
= style
;
990 entry
->any
= (str
? 0 : 1);
991 entry
->u
.lcom
= lcom
;
994 entry
->config
= lcommunity_lcom2str(
995 lcom
, LCOMMUNITY_FORMAT_COMMUNITY_LIST
);
997 entry
->config
= XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG
, str
);
999 entry
->config
= NULL
;
1001 /* Do not put duplicated community entry. */
1002 if (community_list_dup_check(list
, entry
))
1003 community_entry_free(entry
);
1005 community_list_entry_add(list
, entry
);
1010 /* Unset community-list. When str is NULL, delete all of
1011 community-list entry belongs to the specified name. */
1012 int lcommunity_list_unset(struct community_list_handler
*ch
, const char *name
,
1013 const char *str
, int direct
, int style
)
1015 struct community_entry
*entry
= NULL
;
1016 struct community_list
*list
;
1017 struct lcommunity
*lcom
= NULL
;
1018 regex_t
*regex
= NULL
;
1020 /* Lookup community list. */
1021 list
= community_list_lookup(ch
, name
, LARGE_COMMUNITY_LIST_MASTER
);
1023 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1025 /* Delete all of entry belongs to this community-list. */
1027 community_list_delete(list
);
1031 if (style
== LARGE_COMMUNITY_LIST_STANDARD
)
1032 lcom
= lcommunity_str2com(str
);
1034 regex
= bgp_regcomp(str
);
1036 if (!lcom
&& !regex
)
1037 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
1040 entry
= community_list_entry_lookup(list
, lcom
, direct
);
1042 entry
= community_list_entry_lookup(list
, str
, direct
);
1045 lcommunity_free(&lcom
);
1047 bgp_regex_free(regex
);
1050 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1052 community_list_entry_delete(list
, entry
, style
);
1057 /* Set extcommunity-list. */
1058 int extcommunity_list_set(struct community_list_handler
*ch
, const char *name
,
1059 const char *str
, int direct
, int style
)
1061 struct community_entry
*entry
= NULL
;
1062 struct community_list
*list
;
1063 struct ecommunity
*ecom
= NULL
;
1064 regex_t
*regex
= NULL
;
1068 /* Get community list. */
1069 list
= community_list_get(ch
, name
, EXTCOMMUNITY_LIST_MASTER
);
1071 /* When community-list already has entry, new entry should have same
1072 style. If you want to have mixed style community-list, you can
1073 comment out this check. */
1074 if (!community_list_empty_p(list
)) {
1075 struct community_entry
*first
;
1079 if (style
!= first
->style
) {
1080 return (first
->style
== EXTCOMMUNITY_LIST_STANDARD
1081 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
1082 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT
);
1086 if (style
== EXTCOMMUNITY_LIST_STANDARD
)
1087 ecom
= ecommunity_str2com(str
, 0, 1);
1089 regex
= bgp_regcomp(str
);
1091 if (!ecom
&& !regex
)
1092 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
1096 ecommunity_ecom2str(ecom
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
1098 entry
= community_entry_new();
1099 entry
->direct
= direct
;
1100 entry
->style
= style
;
1101 entry
->any
= (str
? 0 : 1);
1103 entry
->config
= ecommunity_ecom2str(
1104 ecom
, ECOMMUNITY_FORMAT_COMMUNITY_LIST
, 0);
1106 entry
->config
= XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG
, str
);
1108 entry
->u
.ecom
= ecom
;
1111 /* Do not put duplicated community entry. */
1112 if (community_list_dup_check(list
, entry
))
1113 community_entry_free(entry
);
1115 community_list_entry_add(list
, entry
);
1116 route_map_notify_dependencies(name
, RMAP_EVENT_ECLIST_ADDED
);
1122 /* Unset extcommunity-list. When str is NULL, delete all of
1123 extcommunity-list entry belongs to the specified name. */
1124 int extcommunity_list_unset(struct community_list_handler
*ch
, const char *name
,
1125 const char *str
, int direct
, int style
,
1128 struct community_entry
*entry
= NULL
;
1129 struct community_list
*list
;
1130 struct ecommunity
*ecom
= NULL
;
1132 /* Lookup extcommunity list. */
1133 list
= community_list_lookup(ch
, name
, EXTCOMMUNITY_LIST_MASTER
);
1135 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1137 /* Delete all of entry belongs to this extcommunity-list. */
1139 community_list_delete(list
);
1140 route_map_notify_dependencies(name
, RMAP_EVENT_ECLIST_DELETED
);
1144 if (style
== EXTCOMMUNITY_LIST_STANDARD
) {
1146 ecom
= ecommunity_str2com(str
, 0, 1);
1150 entry
= community_list_entry_lookup(list
, ecom
, direct
);
1151 ecommunity_free(&ecom
);
1153 entry
= community_list_entry_lookup(list
, str
, direct
);
1156 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1158 community_list_entry_delete(list
, entry
, style
);
1159 route_map_notify_dependencies(name
, RMAP_EVENT_ECLIST_DELETED
);
1164 /* Initializa community-list. Return community-list handler. */
1165 struct community_list_handler
*community_list_init(void)
1167 struct community_list_handler
*ch
;
1168 ch
= XCALLOC(MTYPE_COMMUNITY_LIST_HANDLER
,
1169 sizeof(struct community_list_handler
));
1173 /* Terminate community-list. */
1174 void community_list_terminate(struct community_list_handler
*ch
)
1176 struct community_list_master
*cm
;
1177 struct community_list
*list
;
1179 cm
= &ch
->community_list
;
1180 while ((list
= cm
->num
.head
) != NULL
)
1181 community_list_delete(list
);
1182 while ((list
= cm
->str
.head
) != NULL
)
1183 community_list_delete(list
);
1185 cm
= &ch
->lcommunity_list
;
1186 while ((list
= cm
->num
.head
) != NULL
)
1187 community_list_delete(list
);
1188 while ((list
= cm
->str
.head
) != NULL
)
1189 community_list_delete(list
);
1191 cm
= &ch
->extcommunity_list
;
1192 while ((list
= cm
->num
.head
) != NULL
)
1193 community_list_delete(list
);
1194 while ((list
= cm
->str
.head
) != NULL
)
1195 community_list_delete(list
);
1197 XFREE(MTYPE_COMMUNITY_LIST_HANDLER
, ch
);