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