]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_clist.c
Quagga: vrf_id not being set correctly
[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
5cbea288
DS
334static char *
335community_str_get (struct community *com, int i)
336{
337 int len;
338 u_int32_t comval;
339 u_int16_t as;
340 u_int16_t val;
341 char *str;
342 char *pnt;
343
344 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
345 comval = ntohl (comval);
346
347 switch (comval)
348 {
349 case COMMUNITY_INTERNET:
350 len = strlen (" internet");
351 break;
352 case COMMUNITY_NO_EXPORT:
353 len = strlen (" no-export");
354 break;
355 case COMMUNITY_NO_ADVERTISE:
356 len = strlen (" no-advertise");
357 break;
358 case COMMUNITY_LOCAL_AS:
359 len = strlen (" local-AS");
360 break;
361 default:
362 len = strlen (" 65536:65535");
363 break;
364 }
365
366 /* Allocate memory. */
367 str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len);
368
369 switch (comval)
370 {
371 case COMMUNITY_INTERNET:
372 strcpy (pnt, "internet");
373 pnt += strlen ("internet");
374 break;
375 case COMMUNITY_NO_EXPORT:
376 strcpy (pnt, "no-export");
377 pnt += strlen ("no-export");
378 break;
379 case COMMUNITY_NO_ADVERTISE:
380 strcpy (pnt, "no-advertise");
381 pnt += strlen ("no-advertise");
382 break;
383 case COMMUNITY_LOCAL_AS:
384 strcpy (pnt, "local-AS");
385 pnt += strlen ("local-AS");
386 break;
387 default:
388 as = (comval >> 16) & 0xFFFF;
389 val = comval & 0xFFFF;
390 sprintf (pnt, "%u:%d", as, val);
391 pnt += strlen (pnt);
392 break;
393 }
394
395 *pnt = '\0';
396
397 return str;
398}
399
400/* Internal function to perform regular expression match for
401 * * a single community. */
402static int
403community_regexp_include (regex_t * reg, struct community *com, int i)
404{
405 const char *str;
406
407 /* When there is no communities attribute it is treated as empty
408 * string. */
409 if (com == NULL || com->size == 0)
410 str = "";
411 else
412 str = community_str_get (com, i);
413
414 /* Regular expression match. */
415 if (regexec (reg, str, 0, NULL, 0) == 0)
416 return 1;
417
418 /* No match. */
419 return 0;
420}
421
718e3744 422/* Internal function to perform regular expression match for community
423 attribute. */
424static int
8708b74f 425community_regexp_match (struct community *com, regex_t * reg)
718e3744 426{
fd79ac91 427 const char *str;
718e3744 428
429 /* When there is no communities attribute it is treated as empty
430 string. */
431 if (com == NULL || com->size == 0)
432 str = "";
433 else
434 str = community_str (com);
435
436 /* Regular expression match. */
437 if (regexec (reg, str, 0, NULL, 0) == 0)
438 return 1;
439
440 /* No match. */
441 return 0;
442}
443
8708b74f 444static int
445ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
446{
fd79ac91 447 const char *str;
8708b74f 448
449 /* When there is no communities attribute it is treated as empty
450 string. */
451 if (ecom == NULL || ecom->size == 0)
452 str = "";
453 else
454 str = ecommunity_str (ecom);
455
456 /* Regular expression match. */
457 if (regexec (reg, str, 0, NULL, 0) == 0)
458 return 1;
459
460 /* No match. */
461 return 0;
462}
463
ffd0c037 464#if 0
718e3744 465/* Delete community attribute using regular expression match. Return
466 modified communites attribute. */
467static struct community *
8708b74f 468community_regexp_delete (struct community *com, regex_t * reg)
718e3744 469{
470 int i;
471 u_int32_t comval;
472 /* Maximum is "65535:65535" + '\0'. */
473 char c[12];
fd79ac91 474 const char *str;
718e3744 475
8708b74f 476 if (!com)
718e3744 477 return NULL;
478
479 i = 0;
480 while (i < com->size)
481 {
482 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
483 comval = ntohl (comval);
484
485 switch (comval)
8708b74f 486 {
487 case COMMUNITY_INTERNET:
488 str = "internet";
489 break;
490 case COMMUNITY_NO_EXPORT:
491 str = "no-export";
492 break;
493 case COMMUNITY_NO_ADVERTISE:
494 str = "no-advertise";
495 break;
496 case COMMUNITY_LOCAL_AS:
497 str = "local-AS";
498 break;
499 default:
500 sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF);
501 str = c;
502 break;
503 }
718e3744 504
505 if (regexec (reg, str, 0, NULL, 0) == 0)
8708b74f 506 community_del_val (com, com_nthval (com, i));
718e3744 507 else
8708b74f 508 i++;
718e3744 509 }
510 return com;
511}
ffd0c037 512#endif
718e3744 513
514/* When given community attribute matches to the community-list return
515 1 else return 0. */
516int
517community_list_match (struct community *com, struct community_list *list)
518{
519 struct community_entry *entry;
520
521 for (entry = list->head; entry; entry = entry->next)
522 {
523 if (entry->any)
8708b74f 524 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
718e3744 525
526 if (entry->style == COMMUNITY_LIST_STANDARD)
8708b74f 527 {
528 if (community_include (entry->u.com, COMMUNITY_INTERNET))
529 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
718e3744 530
8708b74f 531 if (community_match (com, entry->u.com))
532 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
533 }
718e3744 534 else if (entry->style == COMMUNITY_LIST_EXPANDED)
8708b74f 535 {
536 if (community_regexp_match (com, entry->reg))
537 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
538 }
539 }
540 return 0;
541}
542
543int
544ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
545{
546 struct community_entry *entry;
547
548 for (entry = list->head; entry; entry = entry->next)
549 {
550 if (entry->any)
551 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
552
553 if (entry->style == EXTCOMMUNITY_LIST_STANDARD)
554 {
555 if (ecommunity_match (ecom, entry->u.ecom))
556 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
557 }
558 else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED)
559 {
560 if (ecommunity_regexp_match (ecom, entry->reg))
561 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
562 }
718e3744 563 }
564 return 0;
565}
566
567/* Perform exact matching. In case of expanded community-list, do
568 same thing as community_list_match(). */
569int
8708b74f 570community_list_exact_match (struct community *com,
571 struct community_list *list)
718e3744 572{
573 struct community_entry *entry;
574
575 for (entry = list->head; entry; entry = entry->next)
576 {
577 if (entry->any)
8708b74f 578 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
718e3744 579
580 if (entry->style == COMMUNITY_LIST_STANDARD)
8708b74f 581 {
582 if (community_include (entry->u.com, COMMUNITY_INTERNET))
583 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
718e3744 584
8708b74f 585 if (community_cmp (com, entry->u.com))
586 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
587 }
718e3744 588 else if (entry->style == COMMUNITY_LIST_EXPANDED)
8708b74f 589 {
590 if (community_regexp_match (com, entry->reg))
591 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
592 }
718e3744 593 }
594 return 0;
595}
596
8708b74f 597/* Delete all permitted communities in the list from com. */
718e3744 598struct community *
599community_list_match_delete (struct community *com,
8708b74f 600 struct community_list *list)
718e3744 601{
602 struct community_entry *entry;
5cbea288
DS
603 u_int32_t val;
604 u_int32_t com_index_to_delete[com->size];
605 int delete_index = 0;
606 int i;
718e3744 607
5cbea288
DS
608 /* Loop over each community value and evaluate each against the
609 * community-list. If we need to delete a community value add its index to
610 * com_index_to_delete.
611 */
612 for (i = 0; i < com->size; i++)
718e3744 613 {
5cbea288
DS
614 val = community_val_get (com, i);
615
616 for (entry = list->head; entry; entry = entry->next)
8708b74f 617 {
5cbea288 618 if (entry->any)
847375b9 619 {
5cbea288
DS
620 if (entry->direct == COMMUNITY_PERMIT)
621 {
622 com_index_to_delete[delete_index] = i;
623 delete_index++;
624 }
625 break;
847375b9 626 }
718e3744 627
5cbea288
DS
628 else if ((entry->style == COMMUNITY_LIST_STANDARD)
629 && (community_include (entry->u.com, COMMUNITY_INTERNET)
630 || community_include (entry->u.com, val) ))
631 {
847375b9 632 if (entry->direct == COMMUNITY_PERMIT)
5cbea288
DS
633 {
634 com_index_to_delete[delete_index] = i;
635 delete_index++;
636 }
637 break;
638 }
639
640 else if ((entry->style == COMMUNITY_LIST_EXPANDED)
641 && community_regexp_include (entry->reg, com, i))
642 {
643 if (entry->direct == COMMUNITY_PERMIT)
644 {
645 com_index_to_delete[delete_index] = i;
646 delete_index++;
647 }
648 break;
649 }
650 }
651 }
652
653 /* Delete all of the communities we flagged for deletion */
654 for (i = delete_index-1; i >= 0; i--)
655 {
656 val = community_val_get (com, com_index_to_delete[i]);
657 community_del_val (com, &val);
718e3744 658 }
5cbea288 659
718e3744 660 return com;
661}
662
663/* To avoid duplicated entry in the community-list, this function
664 compares specified entry to existing entry. */
94f2b392 665static int
8708b74f 666community_list_dup_check (struct community_list *list,
667 struct community_entry *new)
718e3744 668{
669 struct community_entry *entry;
8708b74f 670
718e3744 671 for (entry = list->head; entry; entry = entry->next)
672 {
673 if (entry->style != new->style)
8708b74f 674 continue;
718e3744 675
676 if (entry->direct != new->direct)
8708b74f 677 continue;
718e3744 678
679 if (entry->any != new->any)
8708b74f 680 continue;
718e3744 681
682 if (entry->any)
8708b74f 683 return 1;
718e3744 684
685 switch (entry->style)
8708b74f 686 {
687 case COMMUNITY_LIST_STANDARD:
688 if (community_cmp (entry->u.com, new->u.com))
689 return 1;
690 break;
691 case EXTCOMMUNITY_LIST_STANDARD:
692 if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
693 return 1;
694 break;
695 case COMMUNITY_LIST_EXPANDED:
696 case EXTCOMMUNITY_LIST_EXPANDED:
697 if (strcmp (entry->config, new->config) == 0)
698 return 1;
699 break;
700 default:
701 break;
702 }
718e3744 703 }
704 return 0;
705}
6b0655a2 706
718e3744 707/* Set community-list. */
708int
709community_list_set (struct community_list_handler *ch,
fd79ac91 710 const char *name, const char *str, int direct, int style)
718e3744 711{
fee6e4e4 712 struct community_entry *entry = NULL;
718e3744 713 struct community_list *list;
fee6e4e4 714 struct community *com = NULL;
715 regex_t *regex = NULL;
718e3744 716
717 /* Get community list. */
fee6e4e4 718 list = community_list_get (ch, name, COMMUNITY_LIST_MASTER);
718e3744 719
720 /* When community-list already has entry, new entry should have same
721 style. If you want to have mixed style community-list, you can
722 comment out this check. */
8708b74f 723 if (!community_list_empty_p (list))
718e3744 724 {
725 struct community_entry *first;
726
727 first = list->head;
728
fee6e4e4 729 if (style != first->style)
730 {
731 return (first->style == COMMUNITY_LIST_STANDARD
732 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
733 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
734 }
718e3744 735 }
736
fee6e4e4 737 if (str)
718e3744 738 {
fee6e4e4 739 if (style == COMMUNITY_LIST_STANDARD)
740 com = community_str2com (str);
718e3744 741 else
fee6e4e4 742 regex = bgp_regcomp (str);
8708b74f 743
fee6e4e4 744 if (! com && ! regex)
745 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
718e3744 746 }
747
fee6e4e4 748 entry = community_entry_new ();
749 entry->direct = direct;
750 entry->style = style;
751 entry->any = (str ? 0 : 1);
752 entry->u.com = com;
753 entry->reg = regex;
754 entry->config = (regex ? XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
755
718e3744 756 /* Do not put duplicated community entry. */
757 if (community_list_dup_check (list, entry))
758 community_entry_free (entry);
759 else
518f0eb1
DS
760 {
761 community_list_entry_add (list, entry);
762 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_ADDED);
763 }
718e3744 764
765 return 0;
766}
767
768/* Unset community-list. When str is NULL, delete all of
769 community-list entry belongs to the specified name. */
770int
771community_list_unset (struct community_list_handler *ch,
fd79ac91 772 const char *name, const char *str,
773 int direct, int style)
718e3744 774{
fee6e4e4 775 struct community_entry *entry = NULL;
718e3744 776 struct community_list *list;
fee6e4e4 777 struct community *com = NULL;
778 regex_t *regex = NULL;
718e3744 779
780 /* Lookup community list. */
fee6e4e4 781 list = community_list_lookup (ch, name, COMMUNITY_LIST_MASTER);
718e3744 782 if (list == NULL)
783 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
784
785 /* Delete all of entry belongs to this community-list. */
8708b74f 786 if (!str)
718e3744 787 {
788 community_list_delete (list);
518f0eb1 789 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
718e3744 790 return 0;
791 }
792
fee6e4e4 793 if (style == COMMUNITY_LIST_STANDARD)
794 com = community_str2com (str);
795 else
796 regex = bgp_regcomp (str);
718e3744 797
fee6e4e4 798 if (! com && ! regex)
799 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
718e3744 800
fee6e4e4 801 if (com)
802 entry = community_list_entry_lookup (list, com, direct);
803 else
804 entry = community_list_entry_lookup (list, str, direct);
805
806 if (com)
807 community_free (com);
808 if (regex)
809 bgp_regex_free (regex);
718e3744 810
8708b74f 811 if (!entry)
718e3744 812 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
813
814 community_list_entry_delete (list, entry, style);
518f0eb1 815 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
718e3744 816
817 return 0;
818}
819
820/* Set extcommunity-list. */
821int
822extcommunity_list_set (struct community_list_handler *ch,
fd79ac91 823 const char *name, const char *str,
824 int direct, int style)
718e3744 825{
fee6e4e4 826 struct community_entry *entry = NULL;
718e3744 827 struct community_list *list;
fee6e4e4 828 struct ecommunity *ecom = NULL;
829 regex_t *regex = NULL;
718e3744 830
831 entry = NULL;
832
833 /* Get community list. */
fee6e4e4 834 list = community_list_get (ch, name, EXTCOMMUNITY_LIST_MASTER);
718e3744 835
836 /* When community-list already has entry, new entry should have same
837 style. If you want to have mixed style community-list, you can
838 comment out this check. */
8708b74f 839 if (!community_list_empty_p (list))
718e3744 840 {
841 struct community_entry *first;
842
843 first = list->head;
844
fee6e4e4 845 if (style != first->style)
846 {
847 return (first->style == EXTCOMMUNITY_LIST_STANDARD
848 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
849 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
850 }
718e3744 851 }
852
fee6e4e4 853 if (str)
718e3744 854 {
fee6e4e4 855 if (style == EXTCOMMUNITY_LIST_STANDARD)
856 ecom = ecommunity_str2com (str, 0, 1);
718e3744 857 else
fee6e4e4 858 regex = bgp_regcomp (str);
8708b74f 859
fee6e4e4 860 if (! ecom && ! regex)
861 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
718e3744 862 }
863
fee6e4e4 864 if (ecom)
865 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
866
867 entry = community_entry_new ();
868 entry->direct = direct;
869 entry->style = style;
870 entry->any = (str ? 0 : 1);
871 if (ecom)
872 entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
873 else if (regex)
874 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
875 else
876 entry->config = NULL;
877 entry->u.ecom = ecom;
878 entry->reg = regex;
879
718e3744 880 /* Do not put duplicated community entry. */
881 if (community_list_dup_check (list, entry))
882 community_entry_free (entry);
883 else
518f0eb1
DS
884 {
885 community_list_entry_add (list, entry);
886 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_ADDED);
887 }
718e3744 888
889 return 0;
890}
891
892/* Unset extcommunity-list. When str is NULL, delete all of
893 extcommunity-list entry belongs to the specified name. */
894int
895extcommunity_list_unset (struct community_list_handler *ch,
fd79ac91 896 const char *name, const char *str,
897 int direct, int style)
718e3744 898{
fee6e4e4 899 struct community_entry *entry = NULL;
718e3744 900 struct community_list *list;
901 struct ecommunity *ecom = NULL;
fee6e4e4 902 regex_t *regex = NULL;
718e3744 903
904 /* Lookup extcommunity list. */
fee6e4e4 905 list = community_list_lookup (ch, name, EXTCOMMUNITY_LIST_MASTER);
718e3744 906 if (list == NULL)
907 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
908
909 /* Delete all of entry belongs to this extcommunity-list. */
8708b74f 910 if (!str)
718e3744 911 {
912 community_list_delete (list);
518f0eb1 913 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
718e3744 914 return 0;
915 }
916
fee6e4e4 917 if (style == EXTCOMMUNITY_LIST_STANDARD)
918 ecom = ecommunity_str2com (str, 0, 1);
919 else
920 regex = bgp_regcomp (str);
718e3744 921
fee6e4e4 922 if (! ecom && ! regex)
923 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
718e3744 924
fee6e4e4 925 if (ecom)
926 entry = community_list_entry_lookup (list, ecom, direct);
927 else
928 entry = community_list_entry_lookup (list, str, direct);
929
930 if (ecom)
f6f434b2 931 ecommunity_free (&ecom);
fee6e4e4 932 if (regex)
933 bgp_regex_free (regex);
718e3744 934
8708b74f 935 if (!entry)
718e3744 936 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
937
938 community_list_entry_delete (list, entry, style);
518f0eb1 939 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
718e3744 940
941 return 0;
942}
943
944/* Initializa community-list. Return community-list handler. */
945struct community_list_handler *
94f2b392 946community_list_init (void)
718e3744 947{
948 struct community_list_handler *ch;
949 ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER,
8708b74f 950 sizeof (struct community_list_handler));
718e3744 951 return ch;
952}
953
954/* Terminate community-list. */
228da428 955void
718e3744 956community_list_terminate (struct community_list_handler *ch)
957{
958 struct community_list_master *cm;
959 struct community_list *list;
960
961 cm = &ch->community_list;
962 while ((list = cm->num.head) != NULL)
963 community_list_delete (list);
964 while ((list = cm->str.head) != NULL)
965 community_list_delete (list);
966
967 cm = &ch->extcommunity_list;
968 while ((list = cm->num.head) != NULL)
969 community_list_delete (list);
970 while ((list = cm->str.head) != NULL)
971 community_list_delete (list);
972
973 XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch);
974}