]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_clist.c
* bgp_route.c, bgp_vty.c, bgp_zebra.c, bgpd.[ch]: "enforce-multihop"
[mirror_frr.git] / bgpd / bgp_clist.c
CommitLineData
718e3744 1/* 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\f
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:
8708b74f 45 return &ch->community_list;
46 break;
718e3744 47 case EXTCOMMUNITY_LIST_STANDARD:
48 case EXTCOMMUNITY_LIST_EXPANDED:
49 case EXTCOMMUNITY_LIST_AUTO:
8708b74f 50 return &ch->extcommunity_list;
718e3744 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)
8708b74f 74 community_free (entry->u.com);
718e3744 75 break;
76 case EXTCOMMUNITY_LIST_STANDARD:
77 /* In case of standard extcommunity-list, configuration string
8708b74f 78 is made by ecommunity_ecom2str(). */
718e3744 79 if (entry->config)
8708b74f 80 XFREE (MTYPE_ECOMMUNITY_STR, entry->config);
718e3744 81 if (entry->u.ecom)
8708b74f 82 ecommunity_free (entry->u.ecom);
718e3744 83 break;
84 case COMMUNITY_LIST_EXPANDED:
85 case EXTCOMMUNITY_LIST_EXPANDED:
86 if (entry->config)
8708b74f 87 XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
718e3744 88 if (entry->reg)
8708b74f 89 bgp_regex_free (entry->reg);
718e3744 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,
fd79ac91 118 const char *name, int style)
718e3744 119{
fd79ac91 120 size_t i;
718e3744 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);
8708b74f 129 if (!cm)
718e3744 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]))
8708b74f 141 number = (number * 10) + (name[i] - '0');
718e3744 142 else
8708b74f 143 break;
718e3744 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)
8708b74f 155 if (atol (point->name) >= number)
156 break;
718e3744 157 }
158 else
159 {
160 new->sort = COMMUNITY_LIST_STRING;
161
162 /* Set access_list to string list. */
163 list = &cm->str;
8708b74f 164
718e3744 165 /* Set point to insertion point. */
166 for (point = list->head; point; point = point->next)
8708b74f 167 if (strcmp (point->name, name) >= 0)
168 break;
718e3744 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,
fd79ac91 212 const char *name, int style)
718e3744 213{
214 struct community_list *list;
215 struct community_list_master *cm;
216
8708b74f 217 if (!name)
718e3744 218 return NULL;
219
220 cm = community_list_master_lookup (ch, style);
8708b74f 221 if (!cm)
718e3744 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 *
fd79ac91 235community_list_get (struct community_list_handler *ch,
236 const char *name, int style)
718e3744 237{
238 struct community_list *list;
239
240 list = community_list_lookup (ch, name, style);
8708b74f 241 if (!list)
718e3744 242 list = community_list_insert (ch, name, style);
243 return list;
244}
245
246void
247community_list_delete (struct community_list *list)
248{
249 struct community_list_list *clist;
250 struct community_entry *entry, *next;
251
252 for (entry = list->head; entry; entry = next)
253 {
254 next = entry->next;
255 community_entry_free (entry);
256 }
257
258 clist = list->parent;
259
260 if (list->next)
261 list->next->prev = list->prev;
262 else
263 clist->tail = list->prev;
264
265 if (list->prev)
266 list->prev->next = list->next;
267 else
268 clist->head = list->next;
269
270 community_list_free (list);
271}
272
8708b74f 273int
718e3744 274community_list_empty_p (struct community_list *list)
275{
276 return (list->head == NULL && list->tail == NULL) ? 1 : 0;
277}
278\f
279/* Add community-list entry to the list. */
280static void
8708b74f 281community_list_entry_add (struct community_list *list,
282 struct community_entry *entry)
718e3744 283{
284 entry->next = NULL;
285 entry->prev = list->tail;
286
287 if (list->tail)
288 list->tail->next = entry;
289 else
290 list->head = entry;
291 list->tail = entry;
292}
293
294/* Delete community-list entry from the list. */
295static void
296community_list_entry_delete (struct community_list *list,
8708b74f 297 struct community_entry *entry, int style)
718e3744 298{
299 if (entry->next)
300 entry->next->prev = entry->prev;
301 else
302 list->tail = entry->prev;
303
304 if (entry->prev)
305 entry->prev->next = entry->next;
306 else
307 list->head = entry->next;
308
309 community_entry_free (entry);
310
311 if (community_list_empty_p (list))
312 community_list_delete (list);
313}
314
315/* Lookup community-list entry from the list. */
316static struct community_entry *
fd79ac91 317community_list_entry_lookup (struct community_list *list, const void *arg,
8708b74f 318 int direct)
718e3744 319{
320 struct community_entry *entry;
321
322 for (entry = list->head; entry; entry = entry->next)
323 {
324 switch (entry->style)
8708b74f 325 {
326 case COMMUNITY_LIST_STANDARD:
327 if (community_cmp (entry->u.com, arg))
328 return entry;
329 break;
330 case EXTCOMMUNITY_LIST_STANDARD:
331 if (ecommunity_cmp (entry->u.ecom, arg))
332 return entry;
333 break;
334 case COMMUNITY_LIST_EXPANDED:
335 case EXTCOMMUNITY_LIST_EXPANDED:
336 if (strcmp (entry->config, arg) == 0)
337 return entry;
338 break;
339 default:
340 break;
341 }
718e3744 342 }
343 return NULL;
344}
345\f
346/* Internal function to perform regular expression match for community
347 attribute. */
348static int
8708b74f 349community_regexp_match (struct community *com, regex_t * reg)
718e3744 350{
fd79ac91 351 const char *str;
718e3744 352
353 /* When there is no communities attribute it is treated as empty
354 string. */
355 if (com == NULL || com->size == 0)
356 str = "";
357 else
358 str = community_str (com);
359
360 /* Regular expression match. */
361 if (regexec (reg, str, 0, NULL, 0) == 0)
362 return 1;
363
364 /* No match. */
365 return 0;
366}
367
8708b74f 368static int
369ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
370{
fd79ac91 371 const char *str;
8708b74f 372
373 /* When there is no communities attribute it is treated as empty
374 string. */
375 if (ecom == NULL || ecom->size == 0)
376 str = "";
377 else
378 str = ecommunity_str (ecom);
379
380 /* Regular expression match. */
381 if (regexec (reg, str, 0, NULL, 0) == 0)
382 return 1;
383
384 /* No match. */
385 return 0;
386}
387
718e3744 388/* Delete community attribute using regular expression match. Return
389 modified communites attribute. */
390static struct community *
8708b74f 391community_regexp_delete (struct community *com, regex_t * reg)
718e3744 392{
393 int i;
394 u_int32_t comval;
395 /* Maximum is "65535:65535" + '\0'. */
396 char c[12];
fd79ac91 397 const char *str;
718e3744 398
8708b74f 399 if (!com)
718e3744 400 return NULL;
401
402 i = 0;
403 while (i < com->size)
404 {
405 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
406 comval = ntohl (comval);
407
408 switch (comval)
8708b74f 409 {
410 case COMMUNITY_INTERNET:
411 str = "internet";
412 break;
413 case COMMUNITY_NO_EXPORT:
414 str = "no-export";
415 break;
416 case COMMUNITY_NO_ADVERTISE:
417 str = "no-advertise";
418 break;
419 case COMMUNITY_LOCAL_AS:
420 str = "local-AS";
421 break;
422 default:
423 sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF);
424 str = c;
425 break;
426 }
718e3744 427
428 if (regexec (reg, str, 0, NULL, 0) == 0)
8708b74f 429 community_del_val (com, com_nthval (com, i));
718e3744 430 else
8708b74f 431 i++;
718e3744 432 }
433 return com;
434}
435
436/* When given community attribute matches to the community-list return
437 1 else return 0. */
438int
439community_list_match (struct community *com, struct community_list *list)
440{
441 struct community_entry *entry;
442
443 for (entry = list->head; entry; entry = entry->next)
444 {
445 if (entry->any)
8708b74f 446 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
718e3744 447
448 if (entry->style == COMMUNITY_LIST_STANDARD)
8708b74f 449 {
450 if (community_include (entry->u.com, COMMUNITY_INTERNET))
451 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
718e3744 452
8708b74f 453 if (community_match (com, entry->u.com))
454 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
455 }
718e3744 456 else if (entry->style == COMMUNITY_LIST_EXPANDED)
8708b74f 457 {
458 if (community_regexp_match (com, entry->reg))
459 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
460 }
461 }
462 return 0;
463}
464
465int
466ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
467{
468 struct community_entry *entry;
469
470 for (entry = list->head; entry; entry = entry->next)
471 {
472 if (entry->any)
473 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
474
475 if (entry->style == EXTCOMMUNITY_LIST_STANDARD)
476 {
477 if (ecommunity_match (ecom, entry->u.ecom))
478 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
479 }
480 else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED)
481 {
482 if (ecommunity_regexp_match (ecom, entry->reg))
483 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
484 }
718e3744 485 }
486 return 0;
487}
488
489/* Perform exact matching. In case of expanded community-list, do
490 same thing as community_list_match(). */
491int
8708b74f 492community_list_exact_match (struct community *com,
493 struct community_list *list)
718e3744 494{
495 struct community_entry *entry;
496
497 for (entry = list->head; entry; entry = entry->next)
498 {
499 if (entry->any)
8708b74f 500 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
718e3744 501
502 if (entry->style == COMMUNITY_LIST_STANDARD)
8708b74f 503 {
504 if (community_include (entry->u.com, COMMUNITY_INTERNET))
505 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
718e3744 506
8708b74f 507 if (community_cmp (com, entry->u.com))
508 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
509 }
718e3744 510 else if (entry->style == COMMUNITY_LIST_EXPANDED)
8708b74f 511 {
512 if (community_regexp_match (com, entry->reg))
513 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
514 }
718e3744 515 }
516 return 0;
517}
518
8708b74f 519/* Delete all permitted communities in the list from com. */
718e3744 520struct community *
521community_list_match_delete (struct community *com,
8708b74f 522 struct community_list *list)
718e3744 523{
524 struct community_entry *entry;
525
526 for (entry = list->head; entry; entry = entry->next)
527 {
847375b9 528 if (entry->any)
8708b74f 529 {
847375b9 530 if (entry->direct == COMMUNITY_PERMIT)
531 {
532 /* This is a tricky part. Currently only
533 * route_set_community_delete() uses this function. In the
534 * function com->size is zero, it free the community
535 * structure.
536 */
537 com->size = 0;
538 }
8708b74f 539 return com;
540 }
718e3744 541
847375b9 542 if ((entry->style == COMMUNITY_LIST_STANDARD)
543 && (community_include (entry->u.com, COMMUNITY_INTERNET)
544 || community_match (com, entry->u.com) ))
8708b74f 545 {
847375b9 546 if (entry->direct == COMMUNITY_PERMIT)
547 community_delete (com, entry->u.com);
548 else
549 break;
8708b74f 550 }
847375b9 551 else if ((entry->style == COMMUNITY_LIST_EXPANDED)
552 && community_regexp_match (com, entry->reg))
8708b74f 553 {
554 if (entry->direct == COMMUNITY_PERMIT)
555 community_regexp_delete (com, entry->reg);
847375b9 556 else
557 break;
8708b74f 558 }
718e3744 559 }
560 return com;
561}
562
563/* To avoid duplicated entry in the community-list, this function
564 compares specified entry to existing entry. */
565int
8708b74f 566community_list_dup_check (struct community_list *list,
567 struct community_entry *new)
718e3744 568{
569 struct community_entry *entry;
8708b74f 570
718e3744 571 for (entry = list->head; entry; entry = entry->next)
572 {
573 if (entry->style != new->style)
8708b74f 574 continue;
718e3744 575
576 if (entry->direct != new->direct)
8708b74f 577 continue;
718e3744 578
579 if (entry->any != new->any)
8708b74f 580 continue;
718e3744 581
582 if (entry->any)
8708b74f 583 return 1;
718e3744 584
585 switch (entry->style)
8708b74f 586 {
587 case COMMUNITY_LIST_STANDARD:
588 if (community_cmp (entry->u.com, new->u.com))
589 return 1;
590 break;
591 case EXTCOMMUNITY_LIST_STANDARD:
592 if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
593 return 1;
594 break;
595 case COMMUNITY_LIST_EXPANDED:
596 case EXTCOMMUNITY_LIST_EXPANDED:
597 if (strcmp (entry->config, new->config) == 0)
598 return 1;
599 break;
600 default:
601 break;
602 }
718e3744 603 }
604 return 0;
605}
606\f
607/* Set community-list. */
608int
609community_list_set (struct community_list_handler *ch,
fd79ac91 610 const char *name, const char *str, int direct, int style)
718e3744 611{
612 struct community_entry *entry;
613 struct community_list *list;
614 struct community *com;
615 regex_t *regex;
616
617 entry = NULL;
618
619 /* Get community list. */
620 list = community_list_get (ch, name, style);
621
622 /* When community-list already has entry, new entry should have same
623 style. If you want to have mixed style community-list, you can
624 comment out this check. */
8708b74f 625 if (!community_list_empty_p (list))
718e3744 626 {
627 struct community_entry *first;
628
629 first = list->head;
630
631 if (style == COMMUNITY_LIST_AUTO)
8708b74f 632 style = first->style;
718e3744 633 else if (style != first->style)
8708b74f 634 {
635 return (first->style == COMMUNITY_LIST_STANDARD
636 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
637 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
638 }
718e3744 639 }
640
641 /* When str is NULL, it is matches any. */
8708b74f 642 if (!str)
718e3744 643 {
644 entry = community_entry_new ();
645 entry->direct = direct;
646 entry->any = 1;
647 if (style == COMMUNITY_LIST_AUTO)
8708b74f 648 entry->style = COMMUNITY_LIST_STANDARD;
718e3744 649 else
8708b74f 650 entry->style = style;
718e3744 651 }
652 else
653 {
654 /* Standard community-list parse. String must be converted into
8708b74f 655 community structure without problem. */
718e3744 656 if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO)
8708b74f 657 {
658 com = community_str2com (str);
659 if (com)
660 {
661 entry = community_entry_new ();
662 entry->u.com = com;
663 entry->direct = direct;
664 entry->style = COMMUNITY_LIST_STANDARD;
665 }
666 else if (style == COMMUNITY_LIST_STANDARD)
667 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
668
669 /* We can't convert string into communities value. When
670 community-list type is auto, fall dawn to regular expression
671 match. */
672 }
718e3744 673
674 /* Expanded community-list parse. String may include regular
8708b74f 675 expression. */
676 if (!entry && (style == COMMUNITY_LIST_EXPANDED
677 || style == COMMUNITY_LIST_AUTO))
678 {
679 regex = bgp_regcomp (str);
680 if (regex)
681 {
682 entry = community_entry_new ();
683 entry->reg = regex;
684 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
685 entry->direct = direct;
686 entry->style = COMMUNITY_LIST_EXPANDED;
687 }
688 else
689 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
690 }
718e3744 691 }
692
693 /* Do not put duplicated community entry. */
694 if (community_list_dup_check (list, entry))
695 community_entry_free (entry);
696 else
697 community_list_entry_add (list, entry);
698
699 return 0;
700}
701
702/* Unset community-list. When str is NULL, delete all of
703 community-list entry belongs to the specified name. */
704int
705community_list_unset (struct community_list_handler *ch,
fd79ac91 706 const char *name, const char *str,
707 int direct, int style)
718e3744 708{
709 struct community_entry *entry;
710 struct community_list *list;
711 struct community *com;
712 regex_t *regex;
713
714 entry = NULL;
715
716 /* Lookup community list. */
717 list = community_list_lookup (ch, name, style);
718 if (list == NULL)
719 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
720
721 /* Delete all of entry belongs to this community-list. */
8708b74f 722 if (!str)
718e3744 723 {
724 community_list_delete (list);
725 return 0;
726 }
727
728 /* Community list string is specified. Lookup entry from community
729 list. */
730 if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO)
731 {
732 com = community_str2com (str);
733 if (com)
8708b74f 734 {
735 entry = community_list_entry_lookup (list, com, direct);
736 community_free (com);
737 }
718e3744 738 else if (style == COMMUNITY_LIST_STANDARD)
8708b74f 739 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
718e3744 740
741 /* If we can't convert string into community and community-list
8708b74f 742 type is auto, fall dawn to expanded community-list. */
718e3744 743 }
744
745 /* Expanded community-list parse. String may include regular
746 expression. */
8708b74f 747 if (!entry
718e3744 748 && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO))
749 {
750 regex = bgp_regcomp (str);
751 if (regex)
8708b74f 752 {
753 entry = community_list_entry_lookup (list, str, direct);
754 bgp_regex_free (regex);
755 }
718e3744 756 else
8708b74f 757 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
718e3744 758 }
759
8708b74f 760 if (!entry)
718e3744 761 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
762
763 community_list_entry_delete (list, entry, style);
764
765 return 0;
766}
767
768/* Set extcommunity-list. */
769int
770extcommunity_list_set (struct community_list_handler *ch,
fd79ac91 771 const char *name, const char *str,
772 int direct, int style)
718e3744 773{
774 struct community_entry *entry;
775 struct community_list *list;
776 struct ecommunity *ecom;
777 regex_t *regex;
778
779 entry = NULL;
780
781 /* Get community list. */
782 list = community_list_get (ch, name, style);
783
784 /* When community-list already has entry, new entry should have same
785 style. If you want to have mixed style community-list, you can
786 comment out this check. */
8708b74f 787 if (!community_list_empty_p (list))
718e3744 788 {
789 struct community_entry *first;
790
791 first = list->head;
792
793 if (style == EXTCOMMUNITY_LIST_AUTO)
8708b74f 794 style = first->style;
718e3744 795 else if (style != first->style)
8708b74f 796 {
797 return (first->style == EXTCOMMUNITY_LIST_STANDARD
798 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
799 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
800 }
718e3744 801 }
802
803 /* When str is NULL, it is matches any. */
8708b74f 804 if (!str)
718e3744 805 {
806 entry = community_entry_new ();
807 entry->direct = direct;
808 entry->any = 1;
809 if (style == EXTCOMMUNITY_LIST_AUTO)
8708b74f 810 entry->style = EXTCOMMUNITY_LIST_STANDARD;
718e3744 811 else
8708b74f 812 entry->style = style;
718e3744 813 }
814 else
815 {
816 /* Standard extcommunity-list parse. String is converted into
8708b74f 817 ecommunity structure. */
718e3744 818 if (style == EXTCOMMUNITY_LIST_STANDARD
8708b74f 819 || style == EXTCOMMUNITY_LIST_AUTO)
820 {
821 /* Type is unknown. String includes keyword. */
822 ecom = ecommunity_str2com (str, 0, 1);
823 if (ecom)
824 {
825 entry = community_entry_new ();
826 entry->config
827 =
828 ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
829 ecom->str =
830 ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
831 entry->u.ecom = ecom;
832 entry->direct = direct;
833 entry->style = EXTCOMMUNITY_LIST_STANDARD;
834 }
835 else if (style == EXTCOMMUNITY_LIST_STANDARD)
836 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
837
838 /* We can't convert string into communities value. When
839 community-list type is auto, fall dawn to regular expression
840 match. */
841 }
718e3744 842
843 /* Expanded extcommunity-list parse. String may include regular
8708b74f 844 expression. */
845 if (!entry && (style == EXTCOMMUNITY_LIST_EXPANDED
846 || style == EXTCOMMUNITY_LIST_AUTO))
847 {
848 regex = bgp_regcomp (str);
849 if (regex)
850 {
851 entry = community_entry_new ();
852 entry->reg = regex;
853 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
854 entry->direct = direct;
855 entry->style = EXTCOMMUNITY_LIST_EXPANDED;
856 }
857 else
858 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
859 }
718e3744 860 }
861
862 /* Do not put duplicated community entry. */
863 if (community_list_dup_check (list, entry))
864 community_entry_free (entry);
865 else
866 community_list_entry_add (list, entry);
867
868 return 0;
869}
870
871/* Unset extcommunity-list. When str is NULL, delete all of
872 extcommunity-list entry belongs to the specified name. */
873int
874extcommunity_list_unset (struct community_list_handler *ch,
fd79ac91 875 const char *name, const char *str,
876 int direct, int style)
718e3744 877{
878 struct community_entry *entry;
879 struct community_list *list;
880 struct ecommunity *ecom = NULL;
881 regex_t *regex;
882
883 entry = NULL;
884
885 /* Lookup extcommunity list. */
886 list = community_list_lookup (ch, name, style);
887 if (list == NULL)
888 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
889
890 /* Delete all of entry belongs to this extcommunity-list. */
8708b74f 891 if (!str)
718e3744 892 {
893 community_list_delete (list);
894 return 0;
895 }
896
897 /* Community list string is specified. Lookup entry from community
898 list. */
899 if (style == EXTCOMMUNITY_LIST_STANDARD || style == EXTCOMMUNITY_LIST_AUTO)
900 {
901 ecom = ecommunity_str2com (str, 0, 1);
902 if (ecom)
8708b74f 903 {
904 entry = community_list_entry_lookup (list, ecom, direct);
905 ecommunity_free (ecom);
906 }
718e3744 907 else if (style == COMMUNITY_LIST_STANDARD)
8708b74f 908 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
718e3744 909
910 /* If we can't convert string into community and community-list
8708b74f 911 type is auto, fall dawn to expanded community-list. */
718e3744 912 }
913
914 /* Expanded community-list parse. String may include regular
915 expression. */
8708b74f 916 if (!entry
718e3744 917 && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO))
918 {
919 regex = bgp_regcomp (str);
920 if (regex)
8708b74f 921 {
922 entry = community_list_entry_lookup (list, str, direct);
923 bgp_regex_free (regex);
924 }
718e3744 925 else
8708b74f 926 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
718e3744 927 }
928
8708b74f 929 if (!entry)
718e3744 930 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
931
932 community_list_entry_delete (list, entry, style);
933
934 return 0;
935}
936
937/* Initializa community-list. Return community-list handler. */
938struct community_list_handler *
939community_list_init ()
940{
941 struct community_list_handler *ch;
942 ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER,
8708b74f 943 sizeof (struct community_list_handler));
718e3744 944 return ch;
945}
946
947/* Terminate community-list. */
948void
949community_list_terminate (struct community_list_handler *ch)
950{
951 struct community_list_master *cm;
952 struct community_list *list;
953
954 cm = &ch->community_list;
955 while ((list = cm->num.head) != NULL)
956 community_list_delete (list);
957 while ((list = cm->str.head) != NULL)
958 community_list_delete (list);
959
960 cm = &ch->extcommunity_list;
961 while ((list = cm->num.head) != NULL)
962 community_list_delete (list);
963 while ((list = cm->str.head) != NULL)
964 community_list_delete (list);
965
966 XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch);
967}