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