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
17 along with GNU Zebra; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
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
)
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
*
57 community_entry_new (void)
59 return XCALLOC (MTYPE_COMMUNITY_LIST_ENTRY
, sizeof (struct community_entry
));
62 /* Free community list entry. */
64 community_entry_free (struct community_entry
*entry
)
68 case COMMUNITY_LIST_STANDARD
:
70 community_free (entry
->u
.com
);
72 case LARGE_COMMUNITY_LIST_STANDARD
:
74 lcommunity_free (&entry
->u
.lcom
);
76 case EXTCOMMUNITY_LIST_STANDARD
:
77 /* In case of standard extcommunity-list, configuration string
78 is made by ecommunity_ecom2str(). */
80 XFREE (MTYPE_ECOMMUNITY_STR
, entry
->config
);
82 ecommunity_free (&entry
->u
.ecom
);
84 case COMMUNITY_LIST_EXPANDED
:
85 case EXTCOMMUNITY_LIST_EXPANDED
:
86 case LARGE_COMMUNITY_LIST_EXPANDED
:
88 XFREE (MTYPE_COMMUNITY_LIST_CONFIG
, entry
->config
);
90 bgp_regex_free (entry
->reg
);
94 XFREE (MTYPE_COMMUNITY_LIST_ENTRY
, entry
);
97 /* Allocate a new community-list. */
98 static struct community_list
*
99 community_list_new (void)
101 return XCALLOC (MTYPE_COMMUNITY_LIST
, sizeof (struct community_list
));
104 /* Free community-list. */
106 community_list_free (struct community_list
*list
)
109 XFREE (MTYPE_COMMUNITY_LIST_NAME
, list
->name
);
110 XFREE (MTYPE_COMMUNITY_LIST
, list
);
113 static struct community_list
*
114 community_list_insert (struct community_list_handler
*ch
,
115 const char *name
, int master
)
119 struct community_list
*new;
120 struct community_list
*point
;
121 struct community_list_list
*list
;
122 struct community_list_master
*cm
;
124 /* Lookup community-list master. */
125 cm
= community_list_master_lookup (ch
, master
);
129 /* Allocate new community_list and copy given name. */
130 new = community_list_new ();
131 new->name
= XSTRDUP (MTYPE_COMMUNITY_LIST_NAME
, name
);
133 /* If name is made by all digit character. We treat it as
135 for (number
= 0, i
= 0; i
< strlen (name
); i
++)
137 if (isdigit ((int) name
[i
]))
138 number
= (number
* 10) + (name
[i
] - '0');
143 /* In case of name is all digit character */
144 if (i
== strlen (name
))
146 new->sort
= COMMUNITY_LIST_NUMBER
;
148 /* Set access_list to number list. */
151 for (point
= list
->head
; point
; point
= point
->next
)
152 if (atol (point
->name
) >= number
)
157 new->sort
= COMMUNITY_LIST_STRING
;
159 /* Set access_list to string list. */
162 /* Set point to insertion point. */
163 for (point
= list
->head
; point
; point
= point
->next
)
164 if (strcmp (point
->name
, name
) >= 0)
168 /* Link to upper list. */
171 /* In case of this is the first element of master. */
172 if (list
->head
== NULL
)
174 list
->head
= list
->tail
= new;
178 /* In case of insertion is made at the tail of access_list. */
181 new->prev
= list
->tail
;
182 list
->tail
->next
= new;
187 /* In case of insertion is made at the head of access_list. */
188 if (point
== list
->head
)
190 new->next
= list
->head
;
191 list
->head
->prev
= new;
196 /* Insertion is made at middle of the access_list. */
198 new->prev
= point
->prev
;
201 point
->prev
->next
= new;
207 struct community_list
*
208 community_list_lookup (struct community_list_handler
*ch
,
209 const char *name
, int master
)
211 struct community_list
*list
;
212 struct community_list_master
*cm
;
217 cm
= community_list_master_lookup (ch
, master
);
221 for (list
= cm
->num
.head
; list
; list
= list
->next
)
222 if (strcmp (list
->name
, name
) == 0)
224 for (list
= cm
->str
.head
; list
; list
= list
->next
)
225 if (strcmp (list
->name
, name
) == 0)
231 static struct community_list
*
232 community_list_get (struct community_list_handler
*ch
,
233 const char *name
, int master
)
235 struct community_list
*list
;
237 list
= community_list_lookup (ch
, name
, master
);
239 list
= community_list_insert (ch
, name
, master
);
244 community_list_delete (struct community_list
*list
)
246 struct community_list_list
*clist
;
247 struct community_entry
*entry
, *next
;
249 for (entry
= list
->head
; entry
; entry
= next
)
252 community_entry_free (entry
);
255 clist
= list
->parent
;
258 list
->next
->prev
= list
->prev
;
260 clist
->tail
= list
->prev
;
263 list
->prev
->next
= list
->next
;
265 clist
->head
= list
->next
;
267 community_list_free (list
);
271 community_list_empty_p (struct community_list
*list
)
273 return (list
->head
== NULL
&& list
->tail
== NULL
) ? 1 : 0;
276 /* Add community-list entry to the list. */
278 community_list_entry_add (struct community_list
*list
,
279 struct community_entry
*entry
)
282 entry
->prev
= list
->tail
;
285 list
->tail
->next
= entry
;
291 /* Delete community-list entry from the list. */
293 community_list_entry_delete (struct community_list
*list
,
294 struct community_entry
*entry
, int style
)
297 entry
->next
->prev
= entry
->prev
;
299 list
->tail
= entry
->prev
;
302 entry
->prev
->next
= entry
->next
;
304 list
->head
= entry
->next
;
306 community_entry_free (entry
);
308 if (community_list_empty_p (list
))
309 community_list_delete (list
);
312 /* Lookup community-list entry from the list. */
313 static struct community_entry
*
314 community_list_entry_lookup (struct community_list
*list
, const void *arg
,
317 struct community_entry
*entry
;
319 for (entry
= list
->head
; entry
; entry
= entry
->next
)
321 switch (entry
->style
)
323 case COMMUNITY_LIST_STANDARD
:
324 if (entry
->direct
== direct
&& community_cmp (entry
->u
.com
, arg
))
327 case EXTCOMMUNITY_LIST_STANDARD
:
328 if (entry
->direct
== direct
&& ecommunity_cmp (entry
->u
.ecom
, arg
))
331 case LARGE_COMMUNITY_LIST_STANDARD
:
332 if (entry
->direct
== direct
&& lcommunity_cmp (entry
->u
.lcom
, arg
))
335 case COMMUNITY_LIST_EXPANDED
:
336 case EXTCOMMUNITY_LIST_EXPANDED
:
337 case LARGE_COMMUNITY_LIST_EXPANDED
:
338 if (entry
->direct
== direct
&& strcmp (entry
->config
, arg
) == 0)
349 community_str_get (struct community
*com
, int i
)
358 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
359 comval
= ntohl (comval
);
363 case COMMUNITY_INTERNET
:
364 len
= strlen (" internet");
366 case COMMUNITY_NO_EXPORT
:
367 len
= strlen (" no-export");
369 case COMMUNITY_NO_ADVERTISE
:
370 len
= strlen (" no-advertise");
372 case COMMUNITY_LOCAL_AS
:
373 len
= strlen (" local-AS");
376 len
= strlen (" 65536:65535");
380 /* Allocate memory. */
381 str
= pnt
= XMALLOC (MTYPE_COMMUNITY_STR
, len
);
385 case COMMUNITY_INTERNET
:
386 strcpy (pnt
, "internet");
387 pnt
+= strlen ("internet");
389 case COMMUNITY_NO_EXPORT
:
390 strcpy (pnt
, "no-export");
391 pnt
+= strlen ("no-export");
393 case COMMUNITY_NO_ADVERTISE
:
394 strcpy (pnt
, "no-advertise");
395 pnt
+= strlen ("no-advertise");
397 case COMMUNITY_LOCAL_AS
:
398 strcpy (pnt
, "local-AS");
399 pnt
+= strlen ("local-AS");
402 as
= (comval
>> 16) & 0xFFFF;
403 val
= comval
& 0xFFFF;
404 sprintf (pnt
, "%u:%d", as
, val
);
414 /* Internal function to perform regular expression match for
415 * a single community. */
417 community_regexp_include (regex_t
* reg
, struct community
*com
, int i
)
422 /* When there is no communities attribute it is treated as empty string. */
423 if (com
== NULL
|| com
->size
== 0)
424 str
= XSTRDUP(MTYPE_COMMUNITY_STR
, "");
426 str
= community_str_get (com
, i
);
428 /* Regular expression match. */
429 rv
= regexec (reg
, str
, 0, NULL
, 0);
431 XFREE(MTYPE_COMMUNITY_STR
, str
);
440 /* Internal function to perform regular expression match for community
443 community_regexp_match (struct community
*com
, regex_t
* reg
)
447 /* When there is no communities attribute it is treated as empty
449 if (com
== NULL
|| com
->size
== 0)
452 str
= community_str (com
);
454 /* Regular expression match. */
455 if (regexec (reg
, str
, 0, NULL
, 0) == 0)
463 lcommunity_str_get (struct lcommunity
*lcom
, int i
)
465 struct lcommunity_val lcomval
;
466 u_int32_t globaladmin
;
467 u_int32_t localdata1
;
468 u_int32_t localdata2
;
474 ptr
+= (i
* LCOMMUNITY_SIZE
);
476 memcpy (&lcomval
, ptr
, LCOMMUNITY_SIZE
);
478 /* Allocate memory. 48 bytes taken off bgp_lcommunity.c */
479 str
= pnt
= XMALLOC (MTYPE_LCOMMUNITY_STR
, 48);
481 ptr
= (u_char
*)lcomval
.val
;
482 globaladmin
= (*ptr
++ << 24);
483 globaladmin
|= (*ptr
++ << 16);
484 globaladmin
|= (*ptr
++ << 8);
485 globaladmin
|= (*ptr
++);
487 localdata1
= (*ptr
++ << 24);
488 localdata1
|= (*ptr
++ << 16);
489 localdata1
|= (*ptr
++ << 8);
490 localdata1
|= (*ptr
++);
492 localdata2
= (*ptr
++ << 24);
493 localdata2
|= (*ptr
++ << 16);
494 localdata2
|= (*ptr
++ << 8);
495 localdata2
|= (*ptr
++);
497 sprintf (pnt
, "%u:%u:%u", globaladmin
, localdata1
, localdata2
);
504 /* Internal function to perform regular expression match for
505 * a single community. */
507 lcommunity_regexp_include (regex_t
* reg
, struct lcommunity
*lcom
, int i
)
511 /* When there is no communities attribute it is treated as empty string. */
512 if (lcom
== NULL
|| lcom
->size
== 0)
515 str
= lcommunity_str_get (lcom
, i
);
517 /* Regular expression match. */
518 if (regexec (reg
, str
, 0, NULL
, 0) == 0)
526 lcommunity_regexp_match (struct lcommunity
*com
, regex_t
* reg
)
530 /* When there is no communities attribute it is treated as empty
532 if (com
== NULL
|| com
->size
== 0)
535 str
= lcommunity_str (com
);
537 /* Regular expression match. */
538 if (regexec (reg
, str
, 0, NULL
, 0) == 0)
547 ecommunity_regexp_match (struct ecommunity
*ecom
, regex_t
* reg
)
551 /* When there is no communities attribute it is treated as empty
553 if (ecom
== NULL
|| ecom
->size
== 0)
556 str
= ecommunity_str (ecom
);
558 /* Regular expression match. */
559 if (regexec (reg
, str
, 0, NULL
, 0) == 0)
567 /* Delete community attribute using regular expression match. Return
568 modified communites attribute. */
569 static struct community
*
570 community_regexp_delete (struct community
*com
, regex_t
* reg
)
574 /* Maximum is "65535:65535" + '\0'. */
582 while (i
< com
->size
)
584 memcpy (&comval
, com_nthval (com
, i
), sizeof (u_int32_t
));
585 comval
= ntohl (comval
);
589 case COMMUNITY_INTERNET
:
592 case COMMUNITY_NO_EXPORT
:
595 case COMMUNITY_NO_ADVERTISE
:
596 str
= "no-advertise";
598 case COMMUNITY_LOCAL_AS
:
602 sprintf (c
, "%d:%d", (comval
>> 16) & 0xFFFF, comval
& 0xFFFF);
607 if (regexec (reg
, str
, 0, NULL
, 0) == 0)
608 community_del_val (com
, com_nthval (com
, i
));
616 /* When given community attribute matches to the community-list return
619 community_list_match (struct community
*com
, struct community_list
*list
)
621 struct community_entry
*entry
;
623 for (entry
= list
->head
; entry
; entry
= entry
->next
)
626 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
628 if (entry
->style
== COMMUNITY_LIST_STANDARD
)
630 if (community_include (entry
->u
.com
, COMMUNITY_INTERNET
))
631 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
633 if (community_match (com
, entry
->u
.com
))
634 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
636 else if (entry
->style
== COMMUNITY_LIST_EXPANDED
)
638 if (community_regexp_match (com
, entry
->reg
))
639 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
646 lcommunity_list_match (struct lcommunity
*lcom
, struct community_list
*list
)
648 struct community_entry
*entry
;
650 for (entry
= list
->head
; entry
; entry
= entry
->next
)
653 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
655 if (entry
->style
== LARGE_COMMUNITY_LIST_STANDARD
)
657 if (lcommunity_match (lcom
, entry
->u
.lcom
))
658 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
660 else if (entry
->style
== LARGE_COMMUNITY_LIST_EXPANDED
)
662 if (lcommunity_regexp_match (lcom
, entry
->reg
))
663 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
670 ecommunity_list_match (struct ecommunity
*ecom
, struct community_list
*list
)
672 struct community_entry
*entry
;
674 for (entry
= list
->head
; entry
; entry
= entry
->next
)
677 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
679 if (entry
->style
== EXTCOMMUNITY_LIST_STANDARD
)
681 if (ecommunity_match (ecom
, entry
->u
.ecom
))
682 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
684 else if (entry
->style
== EXTCOMMUNITY_LIST_EXPANDED
)
686 if (ecommunity_regexp_match (ecom
, entry
->reg
))
687 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
693 /* Perform exact matching. In case of expanded community-list, do
694 same thing as community_list_match(). */
696 community_list_exact_match (struct community
*com
,
697 struct community_list
*list
)
699 struct community_entry
*entry
;
701 for (entry
= list
->head
; entry
; entry
= entry
->next
)
704 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
706 if (entry
->style
== COMMUNITY_LIST_STANDARD
)
708 if (community_include (entry
->u
.com
, COMMUNITY_INTERNET
))
709 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
711 if (community_cmp (com
, entry
->u
.com
))
712 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
714 else if (entry
->style
== COMMUNITY_LIST_EXPANDED
)
716 if (community_regexp_match (com
, entry
->reg
))
717 return entry
->direct
== COMMUNITY_PERMIT
? 1 : 0;
723 /* Delete all permitted communities in the list from com. */
725 community_list_match_delete (struct community
*com
,
726 struct community_list
*list
)
728 struct community_entry
*entry
;
730 u_int32_t com_index_to_delete
[com
->size
];
731 int delete_index
= 0;
734 /* Loop over each community value and evaluate each against the
735 * community-list. If we need to delete a community value add its index to
736 * com_index_to_delete.
738 for (i
= 0; i
< com
->size
; i
++)
740 val
= community_val_get (com
, i
);
742 for (entry
= list
->head
; entry
; entry
= entry
->next
)
746 if (entry
->direct
== COMMUNITY_PERMIT
)
748 com_index_to_delete
[delete_index
] = i
;
754 else if ((entry
->style
== COMMUNITY_LIST_STANDARD
)
755 && (community_include (entry
->u
.com
, COMMUNITY_INTERNET
)
756 || community_include (entry
->u
.com
, val
) ))
758 if (entry
->direct
== COMMUNITY_PERMIT
)
760 com_index_to_delete
[delete_index
] = i
;
766 else if ((entry
->style
== COMMUNITY_LIST_EXPANDED
)
767 && community_regexp_include (entry
->reg
, com
, i
))
769 if (entry
->direct
== COMMUNITY_PERMIT
)
771 com_index_to_delete
[delete_index
] = i
;
779 /* Delete all of the communities we flagged for deletion */
780 for (i
= delete_index
-1; i
>= 0; i
--)
782 val
= community_val_get (com
, com_index_to_delete
[i
]);
783 community_del_val (com
, &val
);
789 /* To avoid duplicated entry in the community-list, this function
790 compares specified entry to existing entry. */
792 community_list_dup_check (struct community_list
*list
,
793 struct community_entry
*new)
795 struct community_entry
*entry
;
797 for (entry
= list
->head
; entry
; entry
= entry
->next
)
799 if (entry
->style
!= new->style
)
802 if (entry
->direct
!= new->direct
)
805 if (entry
->any
!= new->any
)
811 switch (entry
->style
)
813 case COMMUNITY_LIST_STANDARD
:
814 if (community_cmp (entry
->u
.com
, new->u
.com
))
817 case LARGE_COMMUNITY_LIST_STANDARD
:
818 if (lcommunity_cmp (entry
->u
.lcom
, new->u
.lcom
))
821 case EXTCOMMUNITY_LIST_STANDARD
:
822 if (ecommunity_cmp (entry
->u
.ecom
, new->u
.ecom
))
825 case COMMUNITY_LIST_EXPANDED
:
826 case EXTCOMMUNITY_LIST_EXPANDED
:
827 case LARGE_COMMUNITY_LIST_EXPANDED
:
828 if (strcmp (entry
->config
, new->config
) == 0)
838 /* Set community-list. */
840 community_list_set (struct community_list_handler
*ch
,
841 const char *name
, const char *str
, int direct
, int style
)
843 struct community_entry
*entry
= NULL
;
844 struct community_list
*list
;
845 struct community
*com
= NULL
;
846 regex_t
*regex
= NULL
;
848 /* Get community list. */
849 list
= community_list_get (ch
, name
, COMMUNITY_LIST_MASTER
);
851 /* When community-list already has entry, new entry should have same
852 style. If you want to have mixed style community-list, you can
853 comment out this check. */
854 if (!community_list_empty_p (list
))
856 struct community_entry
*first
;
860 if (style
!= first
->style
)
862 return (first
->style
== COMMUNITY_LIST_STANDARD
863 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
864 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT
);
870 if (style
== COMMUNITY_LIST_STANDARD
)
871 com
= community_str2com (str
);
873 regex
= bgp_regcomp (str
);
875 if (! com
&& ! regex
)
876 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
879 entry
= community_entry_new ();
880 entry
->direct
= direct
;
881 entry
->style
= style
;
882 entry
->any
= (str
? 0 : 1);
885 entry
->config
= (regex
? XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG
, str
) : NULL
);
887 /* Do not put duplicated community entry. */
888 if (community_list_dup_check (list
, entry
))
889 community_entry_free (entry
);
892 community_list_entry_add (list
, entry
);
893 route_map_notify_dependencies(name
, RMAP_EVENT_CLIST_ADDED
);
899 /* Unset community-list */
901 community_list_unset (struct community_list_handler
*ch
,
902 const char *name
, const char *str
,
903 int direct
, int style
, int delete_all
)
905 struct community_entry
*entry
= NULL
;
906 struct community_list
*list
;
907 struct community
*com
= NULL
;
909 /* Lookup community list. */
910 list
= community_list_lookup (ch
, name
, COMMUNITY_LIST_MASTER
);
912 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
914 /* Delete all of entry belongs to this community-list. */
917 community_list_delete (list
);
918 route_map_notify_dependencies(name
, RMAP_EVENT_CLIST_DELETED
);
922 if (style
== COMMUNITY_LIST_STANDARD
)
925 com
= community_str2com (str
);
930 entry
= community_list_entry_lookup (list
, com
, direct
);
931 community_free (com
);
934 entry
= community_list_entry_lookup (list
, str
, direct
);
937 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
939 community_list_entry_delete (list
, entry
, style
);
940 route_map_notify_dependencies(name
, RMAP_EVENT_CLIST_DELETED
);
945 /* Delete all permitted large communities in the list from com. */
947 lcommunity_list_match_delete (struct lcommunity
*lcom
,
948 struct community_list
*list
)
950 struct community_entry
*entry
;
951 u_int32_t com_index_to_delete
[lcom
->size
];
953 int delete_index
= 0;
956 /* Loop over each lcommunity value and evaluate each against the
957 * community-list. If we need to delete a community value add its index to
958 * com_index_to_delete.
961 for (i
= 0; i
< lcom
->size
; i
++)
963 ptr
+= (i
* LCOMMUNITY_SIZE
);
964 for (entry
= list
->head
; entry
; entry
= entry
->next
)
968 if (entry
->direct
== COMMUNITY_PERMIT
)
970 com_index_to_delete
[delete_index
] = i
;
976 else if ((entry
->style
== LARGE_COMMUNITY_LIST_STANDARD
)
977 && lcommunity_include (entry
->u
.lcom
, ptr
) )
979 if (entry
->direct
== COMMUNITY_PERMIT
)
981 com_index_to_delete
[delete_index
] = i
;
987 else if ((entry
->style
== LARGE_COMMUNITY_LIST_STANDARD
)
988 && lcommunity_regexp_include (entry
->reg
, lcom
, i
))
990 if (entry
->direct
== COMMUNITY_PERMIT
)
992 com_index_to_delete
[delete_index
] = i
;
1000 /* Delete all of the communities we flagged for deletion */
1002 for (i
= delete_index
-1; i
>= 0; i
--)
1004 ptr
+= (com_index_to_delete
[i
] * LCOMMUNITY_SIZE
);
1005 lcommunity_del_val (lcom
, ptr
);
1011 /* Set lcommunity-list. */
1013 lcommunity_list_set (struct community_list_handler
*ch
,
1014 const char *name
, const char *str
, int direct
, int style
)
1016 struct community_entry
*entry
= NULL
;
1017 struct community_list
*list
;
1018 struct lcommunity
*lcom
= NULL
;
1019 regex_t
*regex
= NULL
;
1021 /* Get community list. */
1022 list
= community_list_get (ch
, name
, LARGE_COMMUNITY_LIST_MASTER
);
1024 /* When community-list already has entry, new entry should have same
1025 style. If you want to have mixed style community-list, you can
1026 comment out this check. */
1027 if (!community_list_empty_p (list
))
1029 struct community_entry
*first
;
1033 if (style
!= first
->style
)
1035 return (first
->style
== COMMUNITY_LIST_STANDARD
1036 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
1037 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT
);
1043 if (style
== LARGE_COMMUNITY_LIST_STANDARD
)
1044 lcom
= lcommunity_str2com (str
);
1046 regex
= bgp_regcomp (str
);
1048 if (! lcom
&& ! regex
)
1049 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
1052 entry
= community_entry_new ();
1053 entry
->direct
= direct
;
1054 entry
->style
= style
;
1055 entry
->any
= (str
? 0 : 1);
1056 entry
->u
.lcom
= lcom
;
1059 entry
->config
= lcommunity_lcom2str (lcom
, LCOMMUNITY_FORMAT_COMMUNITY_LIST
);
1061 entry
->config
= XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG
, str
);
1063 entry
->config
= NULL
;
1065 /* Do not put duplicated community entry. */
1066 if (community_list_dup_check (list
, entry
))
1067 community_entry_free (entry
);
1069 community_list_entry_add (list
, entry
);
1074 /* Unset community-list. When str is NULL, delete all of
1075 community-list entry belongs to the specified name. */
1077 lcommunity_list_unset (struct community_list_handler
*ch
,
1078 const char *name
, const char *str
,
1079 int direct
, int style
)
1081 struct community_entry
*entry
= NULL
;
1082 struct community_list
*list
;
1083 struct lcommunity
*lcom
= NULL
;
1084 regex_t
*regex
= NULL
;
1086 /* Lookup community list. */
1087 list
= community_list_lookup (ch
, name
, LARGE_COMMUNITY_LIST_MASTER
);
1089 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1091 /* Delete all of entry belongs to this community-list. */
1094 community_list_delete (list
);
1098 if (style
== LARGE_COMMUNITY_LIST_STANDARD
)
1099 lcom
= lcommunity_str2com (str
);
1101 regex
= bgp_regcomp (str
);
1103 if (! lcom
&& ! regex
)
1104 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
1107 entry
= community_list_entry_lookup (list
, lcom
, direct
);
1109 entry
= community_list_entry_lookup (list
, str
, direct
);
1112 lcommunity_free (&lcom
);
1114 bgp_regex_free (regex
);
1117 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1119 community_list_entry_delete (list
, entry
, style
);
1124 /* Set extcommunity-list. */
1126 extcommunity_list_set (struct community_list_handler
*ch
,
1127 const char *name
, const char *str
,
1128 int direct
, int style
)
1130 struct community_entry
*entry
= NULL
;
1131 struct community_list
*list
;
1132 struct ecommunity
*ecom
= NULL
;
1133 regex_t
*regex
= NULL
;
1137 /* Get community list. */
1138 list
= community_list_get (ch
, name
, EXTCOMMUNITY_LIST_MASTER
);
1140 /* When community-list already has entry, new entry should have same
1141 style. If you want to have mixed style community-list, you can
1142 comment out this check. */
1143 if (!community_list_empty_p (list
))
1145 struct community_entry
*first
;
1149 if (style
!= first
->style
)
1151 return (first
->style
== EXTCOMMUNITY_LIST_STANDARD
1152 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
1153 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT
);
1159 if (style
== EXTCOMMUNITY_LIST_STANDARD
)
1160 ecom
= ecommunity_str2com (str
, 0, 1);
1162 regex
= bgp_regcomp (str
);
1164 if (! ecom
&& ! regex
)
1165 return COMMUNITY_LIST_ERR_MALFORMED_VAL
;
1169 ecom
->str
= ecommunity_ecom2str (ecom
, ECOMMUNITY_FORMAT_DISPLAY
);
1171 entry
= community_entry_new ();
1172 entry
->direct
= direct
;
1173 entry
->style
= style
;
1174 entry
->any
= (str
? 0 : 1);
1176 entry
->config
= ecommunity_ecom2str (ecom
, ECOMMUNITY_FORMAT_COMMUNITY_LIST
);
1178 entry
->config
= XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG
, str
);
1180 entry
->config
= NULL
;
1181 entry
->u
.ecom
= ecom
;
1184 /* Do not put duplicated community entry. */
1185 if (community_list_dup_check (list
, entry
))
1186 community_entry_free (entry
);
1189 community_list_entry_add (list
, entry
);
1190 route_map_notify_dependencies(name
, RMAP_EVENT_ECLIST_ADDED
);
1196 /* Unset extcommunity-list. When str is NULL, delete all of
1197 extcommunity-list entry belongs to the specified name. */
1199 extcommunity_list_unset (struct community_list_handler
*ch
,
1200 const char *name
, const char *str
,
1201 int direct
, int style
, int delete_all
)
1203 struct community_entry
*entry
= NULL
;
1204 struct community_list
*list
;
1205 struct ecommunity
*ecom
= NULL
;
1207 /* Lookup extcommunity list. */
1208 list
= community_list_lookup (ch
, name
, EXTCOMMUNITY_LIST_MASTER
);
1210 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1212 /* Delete all of entry belongs to this extcommunity-list. */
1215 community_list_delete (list
);
1216 route_map_notify_dependencies(name
, RMAP_EVENT_ECLIST_DELETED
);
1220 if (style
== EXTCOMMUNITY_LIST_STANDARD
)
1223 ecom
= ecommunity_str2com (str
, 0, 1);
1228 entry
= community_list_entry_lookup (list
, ecom
, direct
);
1229 ecommunity_free (&ecom
);
1232 entry
= community_list_entry_lookup (list
, str
, direct
);
1235 return COMMUNITY_LIST_ERR_CANT_FIND_LIST
;
1237 community_list_entry_delete (list
, entry
, style
);
1238 route_map_notify_dependencies(name
, RMAP_EVENT_ECLIST_DELETED
);
1243 /* Initializa community-list. Return community-list handler. */
1244 struct community_list_handler
*
1245 community_list_init (void)
1247 struct community_list_handler
*ch
;
1248 ch
= XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER
,
1249 sizeof (struct community_list_handler
));
1253 /* Terminate community-list. */
1255 community_list_terminate (struct community_list_handler
*ch
)
1257 struct community_list_master
*cm
;
1258 struct community_list
*list
;
1260 cm
= &ch
->community_list
;
1261 while ((list
= cm
->num
.head
) != NULL
)
1262 community_list_delete (list
);
1263 while ((list
= cm
->str
.head
) != NULL
)
1264 community_list_delete (list
);
1266 cm
= &ch
->lcommunity_list
;
1267 while ((list
= cm
->num
.head
) != NULL
)
1268 community_list_delete (list
);
1269 while ((list
= cm
->str
.head
) != NULL
)
1270 community_list_delete (list
);
1272 cm
= &ch
->extcommunity_list
;
1273 while ((list
= cm
->num
.head
) != NULL
)
1274 community_list_delete (list
);
1275 while ((list
= cm
->str
.head
) != NULL
)
1276 community_list_delete (list
);
1278 XFREE (MTYPE_COMMUNITY_LIST_HANDLER
, ch
);