blob: 3cf1d2ea8b325d0a58d3dae06f9f5215958626c7 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP community-list and extcommunity-list.
2 Copyright (C) 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "command.h"
24#include "prefix.h"
25#include "memory.h"
26
27#include "bgpd/bgpd.h"
28#include "bgpd/bgp_community.h"
29#include "bgpd/bgp_ecommunity.h"
30#include "bgpd/bgp_aspath.h"
31#include "bgpd/bgp_regex.h"
32#include "bgpd/bgp_clist.h"
33
34/* Lookup master structure for community-list or
35 extcommunity-list. */
36struct community_list_master *
37community_list_master_lookup (struct community_list_handler *ch, int style)
38{
39 if (ch)
40 switch (style)
41 {
42 case COMMUNITY_LIST_STANDARD:
43 case COMMUNITY_LIST_EXPANDED:
44 case COMMUNITY_LIST_AUTO:
paul8708b742003-06-07 02:03:11 +000045 return &ch->community_list;
46 break;
paul718e3742002-12-13 20:15:29 +000047 case EXTCOMMUNITY_LIST_STANDARD:
48 case EXTCOMMUNITY_LIST_EXPANDED:
49 case EXTCOMMUNITY_LIST_AUTO:
paul8708b742003-06-07 02:03:11 +000050 return &ch->extcommunity_list;
paul718e3742002-12-13 20:15:29 +000051 }
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)
paul8708b742003-06-07 02:03:11 +000074 community_free (entry->u.com);
paul718e3742002-12-13 20:15:29 +000075 break;
76 case EXTCOMMUNITY_LIST_STANDARD:
77 /* In case of standard extcommunity-list, configuration string
paul8708b742003-06-07 02:03:11 +000078 is made by ecommunity_ecom2str(). */
paul718e3742002-12-13 20:15:29 +000079 if (entry->config)
paul8708b742003-06-07 02:03:11 +000080 XFREE (MTYPE_ECOMMUNITY_STR, entry->config);
paul718e3742002-12-13 20:15:29 +000081 if (entry->u.ecom)
paul8708b742003-06-07 02:03:11 +000082 ecommunity_free (entry->u.ecom);
paul718e3742002-12-13 20:15:29 +000083 break;
84 case COMMUNITY_LIST_EXPANDED:
85 case EXTCOMMUNITY_LIST_EXPANDED:
86 if (entry->config)
paul8708b742003-06-07 02:03:11 +000087 XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
paul718e3742002-12-13 20:15:29 +000088 if (entry->reg)
paul8708b742003-06-07 02:03:11 +000089 bgp_regex_free (entry->reg);
paul718e3742002-12-13 20:15:29 +000090 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,
paul8708b742003-06-07 02:03:11 +0000118 char *name, int style)
paul718e3742002-12-13 20:15:29 +0000119{
120 int i;
121 long number;
122 struct community_list *new;
123 struct community_list *point;
124 struct community_list_list *list;
125 struct community_list_master *cm;
126
127 /* Lookup community-list master. */
128 cm = community_list_master_lookup (ch, style);
paul8708b742003-06-07 02:03:11 +0000129 if (!cm)
paul718e3742002-12-13 20:15:29 +0000130 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]))
paul8708b742003-06-07 02:03:11 +0000141 number = (number * 10) + (name[i] - '0');
paul718e3742002-12-13 20:15:29 +0000142 else
paul8708b742003-06-07 02:03:11 +0000143 break;
paul718e3742002-12-13 20:15:29 +0000144 }
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)
paul8708b742003-06-07 02:03:11 +0000155 if (atol (point->name) >= number)
156 break;
paul718e3742002-12-13 20:15:29 +0000157 }
158 else
159 {
160 new->sort = COMMUNITY_LIST_STRING;
161
162 /* Set access_list to string list. */
163 list = &cm->str;
paul8708b742003-06-07 02:03:11 +0000164
paul718e3742002-12-13 20:15:29 +0000165 /* Set point to insertion point. */
166 for (point = list->head; point; point = point->next)
paul8708b742003-06-07 02:03:11 +0000167 if (strcmp (point->name, name) >= 0)
168 break;
paul718e3742002-12-13 20:15:29 +0000169 }
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,
paul8708b742003-06-07 02:03:11 +0000212 char *name, int style)
paul718e3742002-12-13 20:15:29 +0000213{
214 struct community_list *list;
215 struct community_list_master *cm;
216
paul8708b742003-06-07 02:03:11 +0000217 if (!name)
paul718e3742002-12-13 20:15:29 +0000218 return NULL;
219
220 cm = community_list_master_lookup (ch, style);
paul8708b742003-06-07 02:03:11 +0000221 if (!cm)
paul718e3742002-12-13 20:15:29 +0000222 return NULL;
223
224 for (list = cm->num.head; list; list = list->next)
225 if (strcmp (list->name, name) == 0)
226 return list;
227 for (list = cm->str.head; list; list = list->next)
228 if (strcmp (list->name, name) == 0)
229 return list;
230
231 return NULL;
232}
233
234struct community_list *
235community_list_get (struct community_list_handler *ch, char *name, int style)
236{
237 struct community_list *list;
238
239 list = community_list_lookup (ch, name, style);
paul8708b742003-06-07 02:03:11 +0000240 if (!list)
paul718e3742002-12-13 20:15:29 +0000241 list = community_list_insert (ch, name, style);
242 return list;
243}
244
245void
246community_list_delete (struct community_list *list)
247{
248 struct community_list_list *clist;
249 struct community_entry *entry, *next;
250
251 for (entry = list->head; entry; entry = next)
252 {
253 next = entry->next;
254 community_entry_free (entry);
255 }
256
257 clist = list->parent;
258
259 if (list->next)
260 list->next->prev = list->prev;
261 else
262 clist->tail = list->prev;
263
264 if (list->prev)
265 list->prev->next = list->next;
266 else
267 clist->head = list->next;
268
269 community_list_free (list);
270}
271
paul8708b742003-06-07 02:03:11 +0000272int
paul718e3742002-12-13 20:15:29 +0000273community_list_empty_p (struct community_list *list)
274{
275 return (list->head == NULL && list->tail == NULL) ? 1 : 0;
276}
277
278/* Add community-list entry to the list. */
279static void
paul8708b742003-06-07 02:03:11 +0000280community_list_entry_add (struct community_list *list,
281 struct community_entry *entry)
paul718e3742002-12-13 20:15:29 +0000282{
283 entry->next = NULL;
284 entry->prev = list->tail;
285
286 if (list->tail)
287 list->tail->next = entry;
288 else
289 list->head = entry;
290 list->tail = entry;
291}
292
293/* Delete community-list entry from the list. */
294static void
295community_list_entry_delete (struct community_list *list,
paul8708b742003-06-07 02:03:11 +0000296 struct community_entry *entry, int style)
paul718e3742002-12-13 20:15:29 +0000297{
298 if (entry->next)
299 entry->next->prev = entry->prev;
300 else
301 list->tail = entry->prev;
302
303 if (entry->prev)
304 entry->prev->next = entry->next;
305 else
306 list->head = entry->next;
307
308 community_entry_free (entry);
309
310 if (community_list_empty_p (list))
311 community_list_delete (list);
312}
313
314/* Lookup community-list entry from the list. */
315static struct community_entry *
316community_list_entry_lookup (struct community_list *list, void *arg,
paul8708b742003-06-07 02:03:11 +0000317 int direct)
paul718e3742002-12-13 20:15:29 +0000318{
319 struct community_entry *entry;
320
321 for (entry = list->head; entry; entry = entry->next)
322 {
323 switch (entry->style)
paul8708b742003-06-07 02:03:11 +0000324 {
325 case COMMUNITY_LIST_STANDARD:
326 if (community_cmp (entry->u.com, arg))
327 return entry;
328 break;
329 case EXTCOMMUNITY_LIST_STANDARD:
330 if (ecommunity_cmp (entry->u.ecom, arg))
331 return entry;
332 break;
333 case COMMUNITY_LIST_EXPANDED:
334 case EXTCOMMUNITY_LIST_EXPANDED:
335 if (strcmp (entry->config, arg) == 0)
336 return entry;
337 break;
338 default:
339 break;
340 }
paul718e3742002-12-13 20:15:29 +0000341 }
342 return NULL;
343}
344
345/* Internal function to perform regular expression match for community
346 attribute. */
347static int
paul8708b742003-06-07 02:03:11 +0000348community_regexp_match (struct community *com, regex_t * reg)
paul718e3742002-12-13 20:15:29 +0000349{
350 char *str;
351
352 /* When there is no communities attribute it is treated as empty
353 string. */
354 if (com == NULL || com->size == 0)
355 str = "";
356 else
357 str = community_str (com);
358
359 /* Regular expression match. */
360 if (regexec (reg, str, 0, NULL, 0) == 0)
361 return 1;
362
363 /* No match. */
364 return 0;
365}
366
paul8708b742003-06-07 02:03:11 +0000367static int
368ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
369{
370 char *str;
371
372 /* When there is no communities attribute it is treated as empty
373 string. */
374 if (ecom == NULL || ecom->size == 0)
375 str = "";
376 else
377 str = ecommunity_str (ecom);
378
379 /* Regular expression match. */
380 if (regexec (reg, str, 0, NULL, 0) == 0)
381 return 1;
382
383 /* No match. */
384 return 0;
385}
386
paul718e3742002-12-13 20:15:29 +0000387/* Delete community attribute using regular expression match. Return
388 modified communites attribute. */
389static struct community *
paul8708b742003-06-07 02:03:11 +0000390community_regexp_delete (struct community *com, regex_t * reg)
paul718e3742002-12-13 20:15:29 +0000391{
392 int i;
393 u_int32_t comval;
394 /* Maximum is "65535:65535" + '\0'. */
395 char c[12];
396 char *str;
397
paul8708b742003-06-07 02:03:11 +0000398 if (!com)
paul718e3742002-12-13 20:15:29 +0000399 return NULL;
400
401 i = 0;
402 while (i < com->size)
403 {
404 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
405 comval = ntohl (comval);
406
407 switch (comval)
paul8708b742003-06-07 02:03:11 +0000408 {
409 case COMMUNITY_INTERNET:
410 str = "internet";
411 break;
412 case COMMUNITY_NO_EXPORT:
413 str = "no-export";
414 break;
415 case COMMUNITY_NO_ADVERTISE:
416 str = "no-advertise";
417 break;
418 case COMMUNITY_LOCAL_AS:
419 str = "local-AS";
420 break;
421 default:
422 sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF);
423 str = c;
424 break;
425 }
paul718e3742002-12-13 20:15:29 +0000426
427 if (regexec (reg, str, 0, NULL, 0) == 0)
paul8708b742003-06-07 02:03:11 +0000428 community_del_val (com, com_nthval (com, i));
paul718e3742002-12-13 20:15:29 +0000429 else
paul8708b742003-06-07 02:03:11 +0000430 i++;
paul718e3742002-12-13 20:15:29 +0000431 }
432 return com;
433}
434
435/* When given community attribute matches to the community-list return
436 1 else return 0. */
437int
438community_list_match (struct community *com, struct community_list *list)
439{
440 struct community_entry *entry;
441
442 for (entry = list->head; entry; entry = entry->next)
443 {
444 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000445 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000446
447 if (entry->style == COMMUNITY_LIST_STANDARD)
paul8708b742003-06-07 02:03:11 +0000448 {
449 if (community_include (entry->u.com, COMMUNITY_INTERNET))
450 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000451
paul8708b742003-06-07 02:03:11 +0000452 if (community_match (com, entry->u.com))
453 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
454 }
paul718e3742002-12-13 20:15:29 +0000455 else if (entry->style == COMMUNITY_LIST_EXPANDED)
paul8708b742003-06-07 02:03:11 +0000456 {
457 if (community_regexp_match (com, entry->reg))
458 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
459 }
460 }
461 return 0;
462}
463
464int
465ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
466{
467 struct community_entry *entry;
468
469 for (entry = list->head; entry; entry = entry->next)
470 {
471 if (entry->any)
472 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
473
474 if (entry->style == EXTCOMMUNITY_LIST_STANDARD)
475 {
476 if (ecommunity_match (ecom, entry->u.ecom))
477 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
478 }
479 else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED)
480 {
481 if (ecommunity_regexp_match (ecom, entry->reg))
482 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
483 }
paul718e3742002-12-13 20:15:29 +0000484 }
485 return 0;
486}
487
488/* Perform exact matching. In case of expanded community-list, do
489 same thing as community_list_match(). */
490int
paul8708b742003-06-07 02:03:11 +0000491community_list_exact_match (struct community *com,
492 struct community_list *list)
paul718e3742002-12-13 20:15:29 +0000493{
494 struct community_entry *entry;
495
496 for (entry = list->head; entry; entry = entry->next)
497 {
498 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000499 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000500
501 if (entry->style == COMMUNITY_LIST_STANDARD)
paul8708b742003-06-07 02:03:11 +0000502 {
503 if (community_include (entry->u.com, COMMUNITY_INTERNET))
504 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000505
paul8708b742003-06-07 02:03:11 +0000506 if (community_cmp (com, entry->u.com))
507 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
508 }
paul718e3742002-12-13 20:15:29 +0000509 else if (entry->style == COMMUNITY_LIST_EXPANDED)
paul8708b742003-06-07 02:03:11 +0000510 {
511 if (community_regexp_match (com, entry->reg))
512 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
513 }
paul718e3742002-12-13 20:15:29 +0000514 }
515 return 0;
516}
517
paul8708b742003-06-07 02:03:11 +0000518/* Delete all permitted communities in the list from com. */
paul718e3742002-12-13 20:15:29 +0000519struct community *
520community_list_match_delete (struct community *com,
paul8708b742003-06-07 02:03:11 +0000521 struct community_list *list)
paul718e3742002-12-13 20:15:29 +0000522{
523 struct community_entry *entry;
524
525 for (entry = list->head; entry; entry = entry->next)
526 {
527 if (entry->any && entry->direct == COMMUNITY_PERMIT)
paul8708b742003-06-07 02:03:11 +0000528 {
529 /* This is a tricky part. Currently only
530 route_set_community_delete() uses this function. In the
531 function com->size is zero, it free the community
532 structure. */
533 com->size = 0;
534 return com;
535 }
paul718e3742002-12-13 20:15:29 +0000536
537 if (entry->style == COMMUNITY_LIST_STANDARD)
paul8708b742003-06-07 02:03:11 +0000538 {
539 if (entry->direct == COMMUNITY_PERMIT)
540 community_delete (com, entry->u.com);
541 }
paul718e3742002-12-13 20:15:29 +0000542 else if (entry->style == COMMUNITY_LIST_EXPANDED)
paul8708b742003-06-07 02:03:11 +0000543 {
544 if (entry->direct == COMMUNITY_PERMIT)
545 community_regexp_delete (com, entry->reg);
546 }
paul718e3742002-12-13 20:15:29 +0000547 }
548 return com;
549}
550
551/* To avoid duplicated entry in the community-list, this function
552 compares specified entry to existing entry. */
553int
paul8708b742003-06-07 02:03:11 +0000554community_list_dup_check (struct community_list *list,
555 struct community_entry *new)
paul718e3742002-12-13 20:15:29 +0000556{
557 struct community_entry *entry;
paul8708b742003-06-07 02:03:11 +0000558
paul718e3742002-12-13 20:15:29 +0000559 for (entry = list->head; entry; entry = entry->next)
560 {
561 if (entry->style != new->style)
paul8708b742003-06-07 02:03:11 +0000562 continue;
paul718e3742002-12-13 20:15:29 +0000563
564 if (entry->direct != new->direct)
paul8708b742003-06-07 02:03:11 +0000565 continue;
paul718e3742002-12-13 20:15:29 +0000566
567 if (entry->any != new->any)
paul8708b742003-06-07 02:03:11 +0000568 continue;
paul718e3742002-12-13 20:15:29 +0000569
570 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000571 return 1;
paul718e3742002-12-13 20:15:29 +0000572
573 switch (entry->style)
paul8708b742003-06-07 02:03:11 +0000574 {
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 }
paul718e3742002-12-13 20:15:29 +0000591 }
592 return 0;
593}
594
595/* Set community-list. */
596int
597community_list_set (struct community_list_handler *ch,
paul8708b742003-06-07 02:03:11 +0000598 char *name, char *str, int direct, int style)
paul718e3742002-12-13 20:15:29 +0000599{
600 struct community_entry *entry;
601 struct community_list *list;
602 struct community *com;
603 regex_t *regex;
604
605 entry = NULL;
606
607 /* Get community list. */
608 list = community_list_get (ch, name, style);
609
610 /* When community-list already has entry, new entry should have same
611 style. If you want to have mixed style community-list, you can
612 comment out this check. */
paul8708b742003-06-07 02:03:11 +0000613 if (!community_list_empty_p (list))
paul718e3742002-12-13 20:15:29 +0000614 {
615 struct community_entry *first;
616
617 first = list->head;
618
619 if (style == COMMUNITY_LIST_AUTO)
paul8708b742003-06-07 02:03:11 +0000620 style = first->style;
paul718e3742002-12-13 20:15:29 +0000621 else if (style != first->style)
paul8708b742003-06-07 02:03:11 +0000622 {
623 return (first->style == COMMUNITY_LIST_STANDARD
624 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
625 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
626 }
paul718e3742002-12-13 20:15:29 +0000627 }
628
629 /* When str is NULL, it is matches any. */
paul8708b742003-06-07 02:03:11 +0000630 if (!str)
paul718e3742002-12-13 20:15:29 +0000631 {
632 entry = community_entry_new ();
633 entry->direct = direct;
634 entry->any = 1;
635 if (style == COMMUNITY_LIST_AUTO)
paul8708b742003-06-07 02:03:11 +0000636 entry->style = COMMUNITY_LIST_STANDARD;
paul718e3742002-12-13 20:15:29 +0000637 else
paul8708b742003-06-07 02:03:11 +0000638 entry->style = style;
paul718e3742002-12-13 20:15:29 +0000639 }
640 else
641 {
642 /* Standard community-list parse. String must be converted into
paul8708b742003-06-07 02:03:11 +0000643 community structure without problem. */
paul718e3742002-12-13 20:15:29 +0000644 if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO)
paul8708b742003-06-07 02:03:11 +0000645 {
646 com = community_str2com (str);
647 if (com)
648 {
649 entry = community_entry_new ();
650 entry->u.com = com;
651 entry->direct = direct;
652 entry->style = COMMUNITY_LIST_STANDARD;
653 }
654 else if (style == COMMUNITY_LIST_STANDARD)
655 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
656
657 /* We can't convert string into communities value. When
658 community-list type is auto, fall dawn to regular expression
659 match. */
660 }
paul718e3742002-12-13 20:15:29 +0000661
662 /* Expanded community-list parse. String may include regular
paul8708b742003-06-07 02:03:11 +0000663 expression. */
664 if (!entry && (style == COMMUNITY_LIST_EXPANDED
665 || style == COMMUNITY_LIST_AUTO))
666 {
667 regex = bgp_regcomp (str);
668 if (regex)
669 {
670 entry = community_entry_new ();
671 entry->reg = regex;
672 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
673 entry->direct = direct;
674 entry->style = COMMUNITY_LIST_EXPANDED;
675 }
676 else
677 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
678 }
paul718e3742002-12-13 20:15:29 +0000679 }
680
681 /* Do not put duplicated community entry. */
682 if (community_list_dup_check (list, entry))
683 community_entry_free (entry);
684 else
685 community_list_entry_add (list, entry);
686
687 return 0;
688}
689
690/* Unset community-list. When str is NULL, delete all of
691 community-list entry belongs to the specified name. */
692int
693community_list_unset (struct community_list_handler *ch,
paul8708b742003-06-07 02:03:11 +0000694 char *name, char *str, int direct, int style)
paul718e3742002-12-13 20:15:29 +0000695{
696 struct community_entry *entry;
697 struct community_list *list;
698 struct community *com;
699 regex_t *regex;
700
701 entry = NULL;
702
703 /* Lookup community list. */
704 list = community_list_lookup (ch, name, style);
705 if (list == NULL)
706 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
707
708 /* Delete all of entry belongs to this community-list. */
paul8708b742003-06-07 02:03:11 +0000709 if (!str)
paul718e3742002-12-13 20:15:29 +0000710 {
711 community_list_delete (list);
712 return 0;
713 }
714
715 /* Community list string is specified. Lookup entry from community
716 list. */
717 if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO)
718 {
719 com = community_str2com (str);
720 if (com)
paul8708b742003-06-07 02:03:11 +0000721 {
722 entry = community_list_entry_lookup (list, com, direct);
723 community_free (com);
724 }
paul718e3742002-12-13 20:15:29 +0000725 else if (style == COMMUNITY_LIST_STANDARD)
paul8708b742003-06-07 02:03:11 +0000726 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000727
728 /* If we can't convert string into community and community-list
paul8708b742003-06-07 02:03:11 +0000729 type is auto, fall dawn to expanded community-list. */
paul718e3742002-12-13 20:15:29 +0000730 }
731
732 /* Expanded community-list parse. String may include regular
733 expression. */
paul8708b742003-06-07 02:03:11 +0000734 if (!entry
paul718e3742002-12-13 20:15:29 +0000735 && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO))
736 {
737 regex = bgp_regcomp (str);
738 if (regex)
paul8708b742003-06-07 02:03:11 +0000739 {
740 entry = community_list_entry_lookup (list, str, direct);
741 bgp_regex_free (regex);
742 }
paul718e3742002-12-13 20:15:29 +0000743 else
paul8708b742003-06-07 02:03:11 +0000744 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000745 }
746
paul8708b742003-06-07 02:03:11 +0000747 if (!entry)
paul718e3742002-12-13 20:15:29 +0000748 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
749
750 community_list_entry_delete (list, entry, style);
751
752 return 0;
753}
754
755/* Set extcommunity-list. */
756int
757extcommunity_list_set (struct community_list_handler *ch,
paul8708b742003-06-07 02:03:11 +0000758 char *name, char *str, int direct, int style)
paul718e3742002-12-13 20:15:29 +0000759{
760 struct community_entry *entry;
761 struct community_list *list;
762 struct ecommunity *ecom;
763 regex_t *regex;
764
765 entry = NULL;
766
767 /* Get community list. */
768 list = community_list_get (ch, name, style);
769
770 /* When community-list already has entry, new entry should have same
771 style. If you want to have mixed style community-list, you can
772 comment out this check. */
paul8708b742003-06-07 02:03:11 +0000773 if (!community_list_empty_p (list))
paul718e3742002-12-13 20:15:29 +0000774 {
775 struct community_entry *first;
776
777 first = list->head;
778
779 if (style == EXTCOMMUNITY_LIST_AUTO)
paul8708b742003-06-07 02:03:11 +0000780 style = first->style;
paul718e3742002-12-13 20:15:29 +0000781 else if (style != first->style)
paul8708b742003-06-07 02:03:11 +0000782 {
783 return (first->style == EXTCOMMUNITY_LIST_STANDARD
784 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
785 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
786 }
paul718e3742002-12-13 20:15:29 +0000787 }
788
789 /* When str is NULL, it is matches any. */
paul8708b742003-06-07 02:03:11 +0000790 if (!str)
paul718e3742002-12-13 20:15:29 +0000791 {
792 entry = community_entry_new ();
793 entry->direct = direct;
794 entry->any = 1;
795 if (style == EXTCOMMUNITY_LIST_AUTO)
paul8708b742003-06-07 02:03:11 +0000796 entry->style = EXTCOMMUNITY_LIST_STANDARD;
paul718e3742002-12-13 20:15:29 +0000797 else
paul8708b742003-06-07 02:03:11 +0000798 entry->style = style;
paul718e3742002-12-13 20:15:29 +0000799 }
800 else
801 {
802 /* Standard extcommunity-list parse. String is converted into
paul8708b742003-06-07 02:03:11 +0000803 ecommunity structure. */
paul718e3742002-12-13 20:15:29 +0000804 if (style == EXTCOMMUNITY_LIST_STANDARD
paul8708b742003-06-07 02:03:11 +0000805 || style == EXTCOMMUNITY_LIST_AUTO)
806 {
807 /* Type is unknown. String includes keyword. */
808 ecom = ecommunity_str2com (str, 0, 1);
809 if (ecom)
810 {
811 entry = community_entry_new ();
812 entry->config
813 =
814 ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
815 ecom->str =
816 ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
817 entry->u.ecom = ecom;
818 entry->direct = direct;
819 entry->style = EXTCOMMUNITY_LIST_STANDARD;
820 }
821 else if (style == EXTCOMMUNITY_LIST_STANDARD)
822 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000823
paul8708b742003-06-07 02:03:11 +0000824 /* We can't convert string into communities value. When
825 community-list type is auto, fall dawn to regular expression
826 match. */
827 }
paul718e3742002-12-13 20:15:29 +0000828
829 /* Expanded extcommunity-list parse. String may include regular
paul8708b742003-06-07 02:03:11 +0000830 expression. */
831 if (!entry && (style == EXTCOMMUNITY_LIST_EXPANDED
832 || style == EXTCOMMUNITY_LIST_AUTO))
833 {
834 regex = bgp_regcomp (str);
835 if (regex)
836 {
837 entry = community_entry_new ();
838 entry->reg = regex;
839 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
840 entry->direct = direct;
841 entry->style = EXTCOMMUNITY_LIST_EXPANDED;
842 }
843 else
844 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
845 }
paul718e3742002-12-13 20:15:29 +0000846 }
847
848 /* Do not put duplicated community entry. */
849 if (community_list_dup_check (list, entry))
850 community_entry_free (entry);
851 else
852 community_list_entry_add (list, entry);
853
854 return 0;
855}
856
857/* Unset extcommunity-list. When str is NULL, delete all of
858 extcommunity-list entry belongs to the specified name. */
859int
860extcommunity_list_unset (struct community_list_handler *ch,
paul8708b742003-06-07 02:03:11 +0000861 char *name, char *str, int direct, int style)
paul718e3742002-12-13 20:15:29 +0000862{
863 struct community_entry *entry;
864 struct community_list *list;
865 struct ecommunity *ecom = NULL;
866 regex_t *regex;
867
868 entry = NULL;
869
870 /* Lookup extcommunity list. */
871 list = community_list_lookup (ch, name, style);
872 if (list == NULL)
873 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
874
875 /* Delete all of entry belongs to this extcommunity-list. */
paul8708b742003-06-07 02:03:11 +0000876 if (!str)
paul718e3742002-12-13 20:15:29 +0000877 {
878 community_list_delete (list);
879 return 0;
880 }
881
882 /* Community list string is specified. Lookup entry from community
883 list. */
884 if (style == EXTCOMMUNITY_LIST_STANDARD || style == EXTCOMMUNITY_LIST_AUTO)
885 {
886 ecom = ecommunity_str2com (str, 0, 1);
887 if (ecom)
paul8708b742003-06-07 02:03:11 +0000888 {
889 entry = community_list_entry_lookup (list, ecom, direct);
890 ecommunity_free (ecom);
891 }
paul718e3742002-12-13 20:15:29 +0000892 else if (style == COMMUNITY_LIST_STANDARD)
paul8708b742003-06-07 02:03:11 +0000893 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000894
895 /* If we can't convert string into community and community-list
paul8708b742003-06-07 02:03:11 +0000896 type is auto, fall dawn to expanded community-list. */
paul718e3742002-12-13 20:15:29 +0000897 }
898
899 /* Expanded community-list parse. String may include regular
900 expression. */
paul8708b742003-06-07 02:03:11 +0000901 if (!entry
paul718e3742002-12-13 20:15:29 +0000902 && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO))
903 {
904 regex = bgp_regcomp (str);
905 if (regex)
paul8708b742003-06-07 02:03:11 +0000906 {
907 entry = community_list_entry_lookup (list, str, direct);
908 bgp_regex_free (regex);
909 }
paul718e3742002-12-13 20:15:29 +0000910 else
paul8708b742003-06-07 02:03:11 +0000911 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000912 }
913
paul8708b742003-06-07 02:03:11 +0000914 if (!entry)
paul718e3742002-12-13 20:15:29 +0000915 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
916
917 community_list_entry_delete (list, entry, style);
918
919 return 0;
920}
921
922/* Initializa community-list. Return community-list handler. */
923struct community_list_handler *
924community_list_init ()
925{
926 struct community_list_handler *ch;
927 ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER,
paul8708b742003-06-07 02:03:11 +0000928 sizeof (struct community_list_handler));
paul718e3742002-12-13 20:15:29 +0000929 return ch;
930}
931
932/* Terminate community-list. */
933void
934community_list_terminate (struct community_list_handler *ch)
935{
936 struct community_list_master *cm;
937 struct community_list *list;
938
939 cm = &ch->community_list;
940 while ((list = cm->num.head) != NULL)
941 community_list_delete (list);
942 while ((list = cm->str.head) != NULL)
943 community_list_delete (list);
944
945 cm = &ch->extcommunity_list;
946 while ((list = cm->num.head) != NULL)
947 community_list_delete (list);
948 while ((list = cm->str.head) != NULL)
949 community_list_delete (list);
950
951 XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch);
952}