blob: 0b6a2e8cce81c4227ea00df3898973d3abacd05c [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP community-list and extcommunity-list.
2 Copyright (C) 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "command.h"
24#include "prefix.h"
25#include "memory.h"
26
27#include "bgpd/bgpd.h"
28#include "bgpd/bgp_community.h"
29#include "bgpd/bgp_ecommunity.h"
30#include "bgpd/bgp_aspath.h"
31#include "bgpd/bgp_regex.h"
32#include "bgpd/bgp_clist.h"
33
34/* Lookup master structure for community-list or
35 extcommunity-list. */
36struct community_list_master *
37community_list_master_lookup (struct community_list_handler *ch, int style)
38{
39 if (ch)
40 switch (style)
41 {
42 case COMMUNITY_LIST_STANDARD:
43 case COMMUNITY_LIST_EXPANDED:
44 case COMMUNITY_LIST_AUTO:
45 return &ch->community_list;
46 break;
47 case EXTCOMMUNITY_LIST_STANDARD:
48 case EXTCOMMUNITY_LIST_EXPANDED:
49 case EXTCOMMUNITY_LIST_AUTO:
50 return &ch->extcommunity_list;
51 }
52 return NULL;
53}
54
55/* Allocate a new community list entry. */
56struct community_entry *
57community_entry_new ()
58{
59 struct community_entry *new;
60
61 new = XMALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry));
62 memset (new, 0, sizeof (struct community_entry));
63 return new;
64}
65
66/* Free community list entry. */
67void
68community_entry_free (struct community_entry *entry)
69{
70 switch (entry->style)
71 {
72 case COMMUNITY_LIST_STANDARD:
73 if (entry->u.com)
74 community_free (entry->u.com);
75 break;
76 case EXTCOMMUNITY_LIST_STANDARD:
77 /* In case of standard extcommunity-list, configuration string
78 is made by ecommunity_ecom2str(). */
79 if (entry->config)
80 XFREE (MTYPE_ECOMMUNITY_STR, entry->config);
81 if (entry->u.ecom)
82 ecommunity_free (entry->u.ecom);
83 break;
84 case COMMUNITY_LIST_EXPANDED:
85 case EXTCOMMUNITY_LIST_EXPANDED:
86 if (entry->config)
87 XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
88 if (entry->reg)
89 bgp_regex_free (entry->reg);
90 default:
91 break;
92 }
93 XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry);
94}
95
96/* Allocate a new community-list. */
97struct community_list *
98community_list_new ()
99{
100 struct community_list *new;
101
102 new = XMALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list));
103 memset (new, 0, sizeof (struct community_list));
104 return new;
105}
106
107/* Free community-list. */
108void
109community_list_free (struct community_list *list)
110{
111 if (list->name)
112 XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name);
113 XFREE (MTYPE_COMMUNITY_LIST, list);
114}
115
116struct community_list *
117community_list_insert (struct community_list_handler *ch,
118 char *name, int style)
119{
120 int i;
121 long number;
122 struct community_list *new;
123 struct community_list *point;
124 struct community_list_list *list;
125 struct community_list_master *cm;
126
127 /* Lookup community-list master. */
128 cm = community_list_master_lookup (ch, style);
129 if (! cm)
130 return NULL;
131
132 /* Allocate new community_list and copy given name. */
133 new = community_list_new ();
134 new->name = XSTRDUP (MTYPE_COMMUNITY_LIST_NAME, name);
135
136 /* If name is made by all digit character. We treat it as
137 number. */
138 for (number = 0, i = 0; i < strlen (name); i++)
139 {
140 if (isdigit ((int) name[i]))
141 number = (number * 10) + (name[i] - '0');
142 else
143 break;
144 }
145
146 /* In case of name is all digit character */
147 if (i == strlen (name))
148 {
149 new->sort = COMMUNITY_LIST_NUMBER;
150
151 /* Set access_list to number list. */
152 list = &cm->num;
153
154 for (point = list->head; point; point = point->next)
155 if (atol (point->name) >= number)
156 break;
157 }
158 else
159 {
160 new->sort = COMMUNITY_LIST_STRING;
161
162 /* Set access_list to string list. */
163 list = &cm->str;
164
165 /* Set point to insertion point. */
166 for (point = list->head; point; point = point->next)
167 if (strcmp (point->name, name) >= 0)
168 break;
169 }
170
171 /* Link to upper list. */
172 new->parent = list;
173
174 /* In case of this is the first element of master. */
175 if (list->head == NULL)
176 {
177 list->head = list->tail = new;
178 return new;
179 }
180
181 /* In case of insertion is made at the tail of access_list. */
182 if (point == NULL)
183 {
184 new->prev = list->tail;
185 list->tail->next = new;
186 list->tail = new;
187 return new;
188 }
189
190 /* In case of insertion is made at the head of access_list. */
191 if (point == list->head)
192 {
193 new->next = list->head;
194 list->head->prev = new;
195 list->head = new;
196 return new;
197 }
198
199 /* Insertion is made at middle of the access_list. */
200 new->next = point;
201 new->prev = point->prev;
202
203 if (point->prev)
204 point->prev->next = new;
205 point->prev = new;
206
207 return new;
208}
209
210struct community_list *
211community_list_lookup (struct community_list_handler *ch,
212 char *name, int style)
213{
214 struct community_list *list;
215 struct community_list_master *cm;
216
217 if (! name)
218 return NULL;
219
220 cm = community_list_master_lookup (ch, style);
221 if (! cm)
222 return NULL;
223
224 for (list = cm->num.head; list; list = list->next)
225 if (strcmp (list->name, name) == 0)
226 return list;
227 for (list = cm->str.head; list; list = list->next)
228 if (strcmp (list->name, name) == 0)
229 return list;
230
231 return NULL;
232}
233
234struct community_list *
235community_list_get (struct community_list_handler *ch, char *name, int style)
236{
237 struct community_list *list;
238
239 list = community_list_lookup (ch, name, style);
240 if (! list)
241 list = community_list_insert (ch, name, style);
242 return list;
243}
244
245void
246community_list_delete (struct community_list *list)
247{
248 struct community_list_list *clist;
249 struct community_entry *entry, *next;
250
251 for (entry = list->head; entry; entry = next)
252 {
253 next = entry->next;
254 community_entry_free (entry);
255 }
256
257 clist = list->parent;
258
259 if (list->next)
260 list->next->prev = list->prev;
261 else
262 clist->tail = list->prev;
263
264 if (list->prev)
265 list->prev->next = list->next;
266 else
267 clist->head = list->next;
268
269 community_list_free (list);
270}
271
272int
273community_list_empty_p (struct community_list *list)
274{
275 return (list->head == NULL && list->tail == NULL) ? 1 : 0;
276}
277
278/* Add community-list entry to the list. */
279static void
280community_list_entry_add (struct community_list *list,
281 struct community_entry *entry)
282{
283 entry->next = NULL;
284 entry->prev = list->tail;
285
286 if (list->tail)
287 list->tail->next = entry;
288 else
289 list->head = entry;
290 list->tail = entry;
291}
292
293/* Delete community-list entry from the list. */
294static void
295community_list_entry_delete (struct community_list *list,
296 struct community_entry *entry, int style)
297{
298 if (entry->next)
299 entry->next->prev = entry->prev;
300 else
301 list->tail = entry->prev;
302
303 if (entry->prev)
304 entry->prev->next = entry->next;
305 else
306 list->head = entry->next;
307
308 community_entry_free (entry);
309
310 if (community_list_empty_p (list))
311 community_list_delete (list);
312}
313
314/* Lookup community-list entry from the list. */
315static struct community_entry *
316community_list_entry_lookup (struct community_list *list, void *arg,
317 int direct)
318{
319 struct community_entry *entry;
320
321 for (entry = list->head; entry; entry = entry->next)
322 {
323 switch (entry->style)
324 {
325 case COMMUNITY_LIST_STANDARD:
326 if (community_cmp (entry->u.com, arg))
327 return entry;
328 break;
329 case EXTCOMMUNITY_LIST_STANDARD:
330 if (ecommunity_cmp (entry->u.ecom, arg))
331 return entry;
332 break;
333 case COMMUNITY_LIST_EXPANDED:
334 case EXTCOMMUNITY_LIST_EXPANDED:
335 if (strcmp (entry->config, arg) == 0)
336 return entry;
337 break;
338 default:
339 break;
340 }
341 }
342 return NULL;
343}
344
345/* Internal function to perform regular expression match for community
346 attribute. */
347static int
348community_regexp_match (struct community *com, regex_t *reg)
349{
350 char *str;
351
352 /* When there is no communities attribute it is treated as empty
353 string. */
354 if (com == NULL || com->size == 0)
355 str = "";
356 else
357 str = community_str (com);
358
359 /* Regular expression match. */
360 if (regexec (reg, str, 0, NULL, 0) == 0)
361 return 1;
362
363 /* No match. */
364 return 0;
365}
366
367/* Delete community attribute using regular expression match. Return
368 modified communites attribute. */
369static struct community *
370community_regexp_delete (struct community *com, regex_t *reg)
371{
372 int i;
373 u_int32_t comval;
374 /* Maximum is "65535:65535" + '\0'. */
375 char c[12];
376 char *str;
377
378 if (! com)
379 return NULL;
380
381 i = 0;
382 while (i < com->size)
383 {
384 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
385 comval = ntohl (comval);
386
387 switch (comval)
388 {
389 case COMMUNITY_INTERNET:
390 str = "internet";
391 break;
392 case COMMUNITY_NO_EXPORT:
393 str = "no-export";
394 break;
395 case COMMUNITY_NO_ADVERTISE:
396 str = "no-advertise";
397 break;
398 case COMMUNITY_LOCAL_AS:
399 str = "local-AS";
400 break;
401 default:
402 sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF);
403 str = c;
404 break;
405 }
406
407 if (regexec (reg, str, 0, NULL, 0) == 0)
408 community_del_val (com, com_nthval (com, i));
409 else
410 i++;
411 }
412 return com;
413}
414
415/* When given community attribute matches to the community-list return
416 1 else return 0. */
417int
418community_list_match (struct community *com, struct community_list *list)
419{
420 struct community_entry *entry;
421
422 for (entry = list->head; entry; entry = entry->next)
423 {
424 if (entry->any)
425 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
426
427 if (entry->style == COMMUNITY_LIST_STANDARD)
428 {
429 if (community_include (entry->u.com, COMMUNITY_INTERNET))
430 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
431
432 if (community_match (com, entry->u.com))
433 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
434 }
435 else if (entry->style == COMMUNITY_LIST_EXPANDED)
436 {
437 if (community_regexp_match (com, entry->reg))
438 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
439 }
440 }
441 return 0;
442}
443
444/* Perform exact matching. In case of expanded community-list, do
445 same thing as community_list_match(). */
446int
447community_list_exact_match (struct community *com, struct community_list *list)
448{
449 struct community_entry *entry;
450
451 for (entry = list->head; entry; entry = entry->next)
452 {
453 if (entry->any)
454 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
455
456 if (entry->style == COMMUNITY_LIST_STANDARD)
457 {
458 if (community_include (entry->u.com, COMMUNITY_INTERNET))
459 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
460
461 if (community_cmp (com, entry->u.com))
462 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
463 }
464 else if (entry->style == COMMUNITY_LIST_EXPANDED)
465 {
466 if (community_regexp_match (com, entry->reg))
467 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
468 }
469 }
470 return 0;
471}
472
473/* Delete all permitted communities in the list from com1 */
474struct community *
475community_list_match_delete (struct community *com,
476 struct community_list *list)
477{
478 struct community_entry *entry;
479
480 for (entry = list->head; entry; entry = entry->next)
481 {
482 if (entry->any && entry->direct == COMMUNITY_PERMIT)
483 {
484 /* This is a tricky part. Currently only
485 route_set_community_delete() uses this function. In the
486 function com->size is zero, it free the community
487 structure. */
488 com->size = 0;
489 return com;
490 }
491
492 if (entry->style == COMMUNITY_LIST_STANDARD)
493 {
494 if (entry->direct == COMMUNITY_PERMIT)
495 community_delete (com, entry->u.com);
496 }
497 else if (entry->style == COMMUNITY_LIST_EXPANDED)
498 {
499 if (entry->direct == COMMUNITY_PERMIT)
500 community_regexp_delete (com, entry->reg);
501 }
502 }
503 return com;
504}
505
506/* To avoid duplicated entry in the community-list, this function
507 compares specified entry to existing entry. */
508int
509community_list_dup_check (struct community_list *list,
510 struct community_entry *new)
511{
512 struct community_entry *entry;
513
514 for (entry = list->head; entry; entry = entry->next)
515 {
516 if (entry->style != new->style)
517 continue;
518
519 if (entry->direct != new->direct)
520 continue;
521
522 if (entry->any != new->any)
523 continue;
524
525 if (entry->any)
526 return 1;
527
528 switch (entry->style)
529 {
530 case COMMUNITY_LIST_STANDARD:
531 if (community_cmp (entry->u.com, new->u.com))
532 return 1;
533 break;
534 case EXTCOMMUNITY_LIST_STANDARD:
535 if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
536 return 1;
537 break;
538 case COMMUNITY_LIST_EXPANDED:
539 case EXTCOMMUNITY_LIST_EXPANDED:
540 if (strcmp (entry->config, new->config) == 0)
541 return 1;
542 break;
543 default:
544 break;
545 }
546 }
547 return 0;
548}
549
550/* Set community-list. */
551int
552community_list_set (struct community_list_handler *ch,
553 char *name, char *str, int direct, int style)
554{
555 struct community_entry *entry;
556 struct community_list *list;
557 struct community *com;
558 regex_t *regex;
559
560 entry = NULL;
561
562 /* Get community list. */
563 list = community_list_get (ch, name, style);
564
565 /* When community-list already has entry, new entry should have same
566 style. If you want to have mixed style community-list, you can
567 comment out this check. */
568 if (! community_list_empty_p (list))
569 {
570 struct community_entry *first;
571
572 first = list->head;
573
574 if (style == COMMUNITY_LIST_AUTO)
575 style = first->style;
576 else if (style != first->style)
577 {
578 return (first->style == COMMUNITY_LIST_STANDARD
579 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
580 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
581 }
582 }
583
584 /* When str is NULL, it is matches any. */
585 if (! str)
586 {
587 entry = community_entry_new ();
588 entry->direct = direct;
589 entry->any = 1;
590 if (style == COMMUNITY_LIST_AUTO)
591 entry->style = COMMUNITY_LIST_STANDARD;
592 else
593 entry->style = style;
594 }
595 else
596 {
597 /* Standard community-list parse. String must be converted into
598 community structure without problem. */
599 if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO)
600 {
601 com = community_str2com (str);
602 if (com)
603 {
604 entry = community_entry_new ();
605 entry->u.com = com;
606 entry->direct = direct;
607 entry->style = COMMUNITY_LIST_STANDARD;
608 }
609 else if (style == COMMUNITY_LIST_STANDARD)
610 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
611
612 /* We can't convert string into communities value. When
613 community-list type is auto, fall dawn to regular expression
614 match. */
615 }
616
617 /* Expanded community-list parse. String may include regular
618 expression. */
619 if (! entry && (style == COMMUNITY_LIST_EXPANDED
620 || style == COMMUNITY_LIST_AUTO))
621 {
622 regex = bgp_regcomp (str);
623 if (regex)
624 {
625 entry = community_entry_new ();
626 entry->reg = regex;
627 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
628 entry->direct = direct;
629 entry->style = COMMUNITY_LIST_EXPANDED;
630 }
631 else
632 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
633 }
634 }
635
636 /* Do not put duplicated community entry. */
637 if (community_list_dup_check (list, entry))
638 community_entry_free (entry);
639 else
640 community_list_entry_add (list, entry);
641
642 return 0;
643}
644
645/* Unset community-list. When str is NULL, delete all of
646 community-list entry belongs to the specified name. */
647int
648community_list_unset (struct community_list_handler *ch,
649 char *name, char *str, int direct, int style)
650{
651 struct community_entry *entry;
652 struct community_list *list;
653 struct community *com;
654 regex_t *regex;
655
656 entry = NULL;
657
658 /* Lookup community list. */
659 list = community_list_lookup (ch, name, style);
660 if (list == NULL)
661 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
662
663 /* Delete all of entry belongs to this community-list. */
664 if (! str)
665 {
666 community_list_delete (list);
667 return 0;
668 }
669
670 /* Community list string is specified. Lookup entry from community
671 list. */
672 if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO)
673 {
674 com = community_str2com (str);
675 if (com)
676 {
677 entry = community_list_entry_lookup (list, com, direct);
678 community_free (com);
679 }
680 else if (style == COMMUNITY_LIST_STANDARD)
681 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
682
683 /* If we can't convert string into community and community-list
684 type is auto, fall dawn to expanded community-list. */
685 }
686
687 /* Expanded community-list parse. String may include regular
688 expression. */
689 if (! entry
690 && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO))
691 {
692 regex = bgp_regcomp (str);
693 if (regex)
694 {
695 entry = community_list_entry_lookup (list, str, direct);
696 bgp_regex_free (regex);
697 }
698 else
699 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
700 }
701
702 if (! entry)
703 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
704
705 community_list_entry_delete (list, entry, style);
706
707 return 0;
708}
709
710/* Set extcommunity-list. */
711int
712extcommunity_list_set (struct community_list_handler *ch,
713 char *name, char *str, int direct, int style)
714{
715 struct community_entry *entry;
716 struct community_list *list;
717 struct ecommunity *ecom;
718 regex_t *regex;
719
720 entry = NULL;
721
722 /* Get community list. */
723 list = community_list_get (ch, name, style);
724
725 /* When community-list already has entry, new entry should have same
726 style. If you want to have mixed style community-list, you can
727 comment out this check. */
728 if (! community_list_empty_p (list))
729 {
730 struct community_entry *first;
731
732 first = list->head;
733
734 if (style == EXTCOMMUNITY_LIST_AUTO)
735 style = first->style;
736 else if (style != first->style)
737 {
738 return (first->style == EXTCOMMUNITY_LIST_STANDARD
739 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
740 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
741 }
742 }
743
744 /* When str is NULL, it is matches any. */
745 if (! str)
746 {
747 entry = community_entry_new ();
748 entry->direct = direct;
749 entry->any = 1;
750 if (style == EXTCOMMUNITY_LIST_AUTO)
751 entry->style = EXTCOMMUNITY_LIST_STANDARD;
752 else
753 entry->style = style;
754 }
755 else
756 {
757 /* Standard extcommunity-list parse. String is converted into
758 ecommunity structure. */
759 if (style == EXTCOMMUNITY_LIST_STANDARD
760 || style == EXTCOMMUNITY_LIST_AUTO)
761 {
762 /* Type is unknown. String includes keyword. */
763 ecom = ecommunity_str2com (str, 0, 1);
764 if (ecom)
765 {
766 entry = community_entry_new ();
767 entry->config
768 = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
769 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
770 entry->u.ecom = ecom;
771 entry->direct = direct;
772 entry->style = EXTCOMMUNITY_LIST_STANDARD;
773 }
774 else if (style == EXTCOMMUNITY_LIST_STANDARD)
775 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
776
777 /* We can't convert string into communities value. When
778 community-list type is auto, fall dawn to regular expression
779 match. */
780 }
781
782 /* Expanded extcommunity-list parse. String may include regular
783 expression. */
784 if (! entry && (style == EXTCOMMUNITY_LIST_EXPANDED
785 || style == EXTCOMMUNITY_LIST_AUTO))
786 {
787 regex = bgp_regcomp (str);
788 if (regex)
789 {
790 entry = community_entry_new ();
791 entry->reg = regex;
792 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
793 entry->direct = direct;
794 entry->style = EXTCOMMUNITY_LIST_EXPANDED;
795 }
796 else
797 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
798 }
799 }
800
801 /* Do not put duplicated community entry. */
802 if (community_list_dup_check (list, entry))
803 community_entry_free (entry);
804 else
805 community_list_entry_add (list, entry);
806
807 return 0;
808}
809
810/* Unset extcommunity-list. When str is NULL, delete all of
811 extcommunity-list entry belongs to the specified name. */
812int
813extcommunity_list_unset (struct community_list_handler *ch,
814 char *name, char *str, int direct, int style)
815{
816 struct community_entry *entry;
817 struct community_list *list;
818 struct ecommunity *ecom = NULL;
819 regex_t *regex;
820
821 entry = NULL;
822
823 /* Lookup extcommunity list. */
824 list = community_list_lookup (ch, name, style);
825 if (list == NULL)
826 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
827
828 /* Delete all of entry belongs to this extcommunity-list. */
829 if (! str)
830 {
831 community_list_delete (list);
832 return 0;
833 }
834
835 /* Community list string is specified. Lookup entry from community
836 list. */
837 if (style == EXTCOMMUNITY_LIST_STANDARD || style == EXTCOMMUNITY_LIST_AUTO)
838 {
839 ecom = ecommunity_str2com (str, 0, 1);
840 if (ecom)
841 {
842 entry = community_list_entry_lookup (list, ecom, direct);
843 ecommunity_free (ecom);
844 }
845 else if (style == COMMUNITY_LIST_STANDARD)
846 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
847
848 /* If we can't convert string into community and community-list
849 type is auto, fall dawn to expanded community-list. */
850 }
851
852 /* Expanded community-list parse. String may include regular
853 expression. */
854 if (! entry
855 && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO))
856 {
857 regex = bgp_regcomp (str);
858 if (regex)
859 {
860 entry = community_list_entry_lookup (list, str, direct);
861 bgp_regex_free (regex);
862 }
863 else
864 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
865 }
866
867 if (! entry)
868 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
869
870 community_list_entry_delete (list, entry, style);
871
872 return 0;
873}
874
875/* Initializa community-list. Return community-list handler. */
876struct community_list_handler *
877community_list_init ()
878{
879 struct community_list_handler *ch;
880 ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER,
881 sizeof (struct community_list_handler));
882 return ch;
883}
884
885/* Terminate community-list. */
886void
887community_list_terminate (struct community_list_handler *ch)
888{
889 struct community_list_master *cm;
890 struct community_list *list;
891
892 cm = &ch->community_list;
893 while ((list = cm->num.head) != NULL)
894 community_list_delete (list);
895 while ((list = cm->str.head) != NULL)
896 community_list_delete (list);
897
898 cm = &ch->extcommunity_list;
899 while ((list = cm->num.head) != NULL)
900 community_list_delete (list);
901 while ((list = cm->str.head) != NULL)
902 community_list_delete (list);
903
904 XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch);
905}