blob: b36f2341da2b5c88ceafd1d15113844b63a57ba4 [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 *
hassofee6e4e2005-02-02 16:29:31 +000037community_list_master_lookup (struct community_list_handler *ch, int master)
paul718e3742002-12-13 20:15:29 +000038{
39 if (ch)
hassofee6e4e2005-02-02 16:29:31 +000040 switch (master)
paul718e3742002-12-13 20:15:29 +000041 {
hassofee6e4e2005-02-02 16:29:31 +000042 case COMMUNITY_LIST_MASTER:
43 return &ch->community_list;
44 break;
45 case EXTCOMMUNITY_LIST_MASTER:
46 return &ch->extcommunity_list;
paul718e3742002-12-13 20:15:29 +000047 }
48 return NULL;
49}
50
51/* Allocate a new community list entry. */
52struct community_entry *
53community_entry_new ()
54{
55 struct community_entry *new;
56
57 new = XMALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry));
58 memset (new, 0, sizeof (struct community_entry));
59 return new;
60}
61
62/* Free community list entry. */
63void
64community_entry_free (struct community_entry *entry)
65{
66 switch (entry->style)
67 {
68 case COMMUNITY_LIST_STANDARD:
69 if (entry->u.com)
paul8708b742003-06-07 02:03:11 +000070 community_free (entry->u.com);
paul718e3742002-12-13 20:15:29 +000071 break;
72 case EXTCOMMUNITY_LIST_STANDARD:
73 /* In case of standard extcommunity-list, configuration string
paul8708b742003-06-07 02:03:11 +000074 is made by ecommunity_ecom2str(). */
paul718e3742002-12-13 20:15:29 +000075 if (entry->config)
paul8708b742003-06-07 02:03:11 +000076 XFREE (MTYPE_ECOMMUNITY_STR, entry->config);
paul718e3742002-12-13 20:15:29 +000077 if (entry->u.ecom)
paul8708b742003-06-07 02:03:11 +000078 ecommunity_free (entry->u.ecom);
paul718e3742002-12-13 20:15:29 +000079 break;
80 case COMMUNITY_LIST_EXPANDED:
81 case EXTCOMMUNITY_LIST_EXPANDED:
82 if (entry->config)
paul8708b742003-06-07 02:03:11 +000083 XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
paul718e3742002-12-13 20:15:29 +000084 if (entry->reg)
paul8708b742003-06-07 02:03:11 +000085 bgp_regex_free (entry->reg);
paul718e3742002-12-13 20:15:29 +000086 default:
87 break;
88 }
89 XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry);
90}
91
92/* Allocate a new community-list. */
93struct community_list *
94community_list_new ()
95{
96 struct community_list *new;
97
98 new = XMALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list));
99 memset (new, 0, sizeof (struct community_list));
100 return new;
101}
102
103/* Free community-list. */
104void
105community_list_free (struct community_list *list)
106{
107 if (list->name)
108 XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name);
109 XFREE (MTYPE_COMMUNITY_LIST, list);
110}
111
112struct community_list *
113community_list_insert (struct community_list_handler *ch,
hassofee6e4e2005-02-02 16:29:31 +0000114 const char *name, int master)
paul718e3742002-12-13 20:15:29 +0000115{
paulfd79ac92004-10-13 05:06:08 +0000116 size_t i;
paul718e3742002-12-13 20:15:29 +0000117 long number;
118 struct community_list *new;
119 struct community_list *point;
120 struct community_list_list *list;
121 struct community_list_master *cm;
122
123 /* Lookup community-list master. */
hassofee6e4e2005-02-02 16:29:31 +0000124 cm = community_list_master_lookup (ch, master);
paul8708b742003-06-07 02:03:11 +0000125 if (!cm)
paul718e3742002-12-13 20:15:29 +0000126 return NULL;
127
128 /* Allocate new community_list and copy given name. */
129 new = community_list_new ();
130 new->name = XSTRDUP (MTYPE_COMMUNITY_LIST_NAME, name);
131
132 /* If name is made by all digit character. We treat it as
133 number. */
134 for (number = 0, i = 0; i < strlen (name); i++)
135 {
136 if (isdigit ((int) name[i]))
paul8708b742003-06-07 02:03:11 +0000137 number = (number * 10) + (name[i] - '0');
paul718e3742002-12-13 20:15:29 +0000138 else
paul8708b742003-06-07 02:03:11 +0000139 break;
paul718e3742002-12-13 20:15:29 +0000140 }
141
142 /* In case of name is all digit character */
143 if (i == strlen (name))
144 {
145 new->sort = COMMUNITY_LIST_NUMBER;
146
147 /* Set access_list to number list. */
148 list = &cm->num;
149
150 for (point = list->head; point; point = point->next)
paul8708b742003-06-07 02:03:11 +0000151 if (atol (point->name) >= number)
152 break;
paul718e3742002-12-13 20:15:29 +0000153 }
154 else
155 {
156 new->sort = COMMUNITY_LIST_STRING;
157
158 /* Set access_list to string list. */
159 list = &cm->str;
paul8708b742003-06-07 02:03:11 +0000160
paul718e3742002-12-13 20:15:29 +0000161 /* Set point to insertion point. */
162 for (point = list->head; point; point = point->next)
paul8708b742003-06-07 02:03:11 +0000163 if (strcmp (point->name, name) >= 0)
164 break;
paul718e3742002-12-13 20:15:29 +0000165 }
166
167 /* Link to upper list. */
168 new->parent = list;
169
170 /* In case of this is the first element of master. */
171 if (list->head == NULL)
172 {
173 list->head = list->tail = new;
174 return new;
175 }
176
177 /* In case of insertion is made at the tail of access_list. */
178 if (point == NULL)
179 {
180 new->prev = list->tail;
181 list->tail->next = new;
182 list->tail = new;
183 return new;
184 }
185
186 /* In case of insertion is made at the head of access_list. */
187 if (point == list->head)
188 {
189 new->next = list->head;
190 list->head->prev = new;
191 list->head = new;
192 return new;
193 }
194
195 /* Insertion is made at middle of the access_list. */
196 new->next = point;
197 new->prev = point->prev;
198
199 if (point->prev)
200 point->prev->next = new;
201 point->prev = new;
202
203 return new;
204}
205
206struct community_list *
207community_list_lookup (struct community_list_handler *ch,
hassofee6e4e2005-02-02 16:29:31 +0000208 const char *name, int master)
paul718e3742002-12-13 20:15:29 +0000209{
210 struct community_list *list;
211 struct community_list_master *cm;
212
paul8708b742003-06-07 02:03:11 +0000213 if (!name)
paul718e3742002-12-13 20:15:29 +0000214 return NULL;
215
hassofee6e4e2005-02-02 16:29:31 +0000216 cm = community_list_master_lookup (ch, master);
paul8708b742003-06-07 02:03:11 +0000217 if (!cm)
paul718e3742002-12-13 20:15:29 +0000218 return NULL;
219
220 for (list = cm->num.head; list; list = list->next)
221 if (strcmp (list->name, name) == 0)
222 return list;
223 for (list = cm->str.head; list; list = list->next)
224 if (strcmp (list->name, name) == 0)
225 return list;
226
227 return NULL;
228}
229
230struct community_list *
hassofee6e4e2005-02-02 16:29:31 +0000231community_list_get (struct community_list_handler *ch,
232 const char *name, int master)
paul718e3742002-12-13 20:15:29 +0000233{
234 struct community_list *list;
235
hassofee6e4e2005-02-02 16:29:31 +0000236 list = community_list_lookup (ch, name, master);
paul8708b742003-06-07 02:03:11 +0000237 if (!list)
hassofee6e4e2005-02-02 16:29:31 +0000238 list = community_list_insert (ch, name, master);
paul718e3742002-12-13 20:15:29 +0000239 return list;
240}
241
242void
243community_list_delete (struct community_list *list)
244{
245 struct community_list_list *clist;
246 struct community_entry *entry, *next;
247
248 for (entry = list->head; entry; entry = next)
249 {
250 next = entry->next;
251 community_entry_free (entry);
252 }
253
254 clist = list->parent;
255
256 if (list->next)
257 list->next->prev = list->prev;
258 else
259 clist->tail = list->prev;
260
261 if (list->prev)
262 list->prev->next = list->next;
263 else
264 clist->head = list->next;
265
266 community_list_free (list);
267}
268
paul8708b742003-06-07 02:03:11 +0000269int
paul718e3742002-12-13 20:15:29 +0000270community_list_empty_p (struct community_list *list)
271{
272 return (list->head == NULL && list->tail == NULL) ? 1 : 0;
273}
274
275/* Add community-list entry to the list. */
276static void
paul8708b742003-06-07 02:03:11 +0000277community_list_entry_add (struct community_list *list,
278 struct community_entry *entry)
paul718e3742002-12-13 20:15:29 +0000279{
280 entry->next = NULL;
281 entry->prev = list->tail;
282
283 if (list->tail)
284 list->tail->next = entry;
285 else
286 list->head = entry;
287 list->tail = entry;
288}
289
290/* Delete community-list entry from the list. */
291static void
292community_list_entry_delete (struct community_list *list,
paul8708b742003-06-07 02:03:11 +0000293 struct community_entry *entry, int style)
paul718e3742002-12-13 20:15:29 +0000294{
295 if (entry->next)
296 entry->next->prev = entry->prev;
297 else
298 list->tail = entry->prev;
299
300 if (entry->prev)
301 entry->prev->next = entry->next;
302 else
303 list->head = entry->next;
304
305 community_entry_free (entry);
306
307 if (community_list_empty_p (list))
308 community_list_delete (list);
309}
310
311/* Lookup community-list entry from the list. */
312static struct community_entry *
paulfd79ac92004-10-13 05:06:08 +0000313community_list_entry_lookup (struct community_list *list, const void *arg,
paul8708b742003-06-07 02:03:11 +0000314 int direct)
paul718e3742002-12-13 20:15:29 +0000315{
316 struct community_entry *entry;
317
318 for (entry = list->head; entry; entry = entry->next)
319 {
320 switch (entry->style)
paul8708b742003-06-07 02:03:11 +0000321 {
322 case COMMUNITY_LIST_STANDARD:
323 if (community_cmp (entry->u.com, arg))
324 return entry;
325 break;
326 case EXTCOMMUNITY_LIST_STANDARD:
327 if (ecommunity_cmp (entry->u.ecom, arg))
328 return entry;
329 break;
330 case COMMUNITY_LIST_EXPANDED:
331 case EXTCOMMUNITY_LIST_EXPANDED:
332 if (strcmp (entry->config, arg) == 0)
333 return entry;
334 break;
335 default:
336 break;
337 }
paul718e3742002-12-13 20:15:29 +0000338 }
339 return NULL;
340}
341
342/* Internal function to perform regular expression match for community
343 attribute. */
344static int
paul8708b742003-06-07 02:03:11 +0000345community_regexp_match (struct community *com, regex_t * reg)
paul718e3742002-12-13 20:15:29 +0000346{
paulfd79ac92004-10-13 05:06:08 +0000347 const char *str;
paul718e3742002-12-13 20:15:29 +0000348
349 /* When there is no communities attribute it is treated as empty
350 string. */
351 if (com == NULL || com->size == 0)
352 str = "";
353 else
354 str = community_str (com);
355
356 /* Regular expression match. */
357 if (regexec (reg, str, 0, NULL, 0) == 0)
358 return 1;
359
360 /* No match. */
361 return 0;
362}
363
paul8708b742003-06-07 02:03:11 +0000364static int
365ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
366{
paulfd79ac92004-10-13 05:06:08 +0000367 const char *str;
paul8708b742003-06-07 02:03:11 +0000368
369 /* When there is no communities attribute it is treated as empty
370 string. */
371 if (ecom == NULL || ecom->size == 0)
372 str = "";
373 else
374 str = ecommunity_str (ecom);
375
376 /* Regular expression match. */
377 if (regexec (reg, str, 0, NULL, 0) == 0)
378 return 1;
379
380 /* No match. */
381 return 0;
382}
383
paul718e3742002-12-13 20:15:29 +0000384/* Delete community attribute using regular expression match. Return
385 modified communites attribute. */
386static struct community *
paul8708b742003-06-07 02:03:11 +0000387community_regexp_delete (struct community *com, regex_t * reg)
paul718e3742002-12-13 20:15:29 +0000388{
389 int i;
390 u_int32_t comval;
391 /* Maximum is "65535:65535" + '\0'. */
392 char c[12];
paulfd79ac92004-10-13 05:06:08 +0000393 const char *str;
paul718e3742002-12-13 20:15:29 +0000394
paul8708b742003-06-07 02:03:11 +0000395 if (!com)
paul718e3742002-12-13 20:15:29 +0000396 return NULL;
397
398 i = 0;
399 while (i < com->size)
400 {
401 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
402 comval = ntohl (comval);
403
404 switch (comval)
paul8708b742003-06-07 02:03:11 +0000405 {
406 case COMMUNITY_INTERNET:
407 str = "internet";
408 break;
409 case COMMUNITY_NO_EXPORT:
410 str = "no-export";
411 break;
412 case COMMUNITY_NO_ADVERTISE:
413 str = "no-advertise";
414 break;
415 case COMMUNITY_LOCAL_AS:
416 str = "local-AS";
417 break;
418 default:
419 sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF);
420 str = c;
421 break;
422 }
paul718e3742002-12-13 20:15:29 +0000423
424 if (regexec (reg, str, 0, NULL, 0) == 0)
paul8708b742003-06-07 02:03:11 +0000425 community_del_val (com, com_nthval (com, i));
paul718e3742002-12-13 20:15:29 +0000426 else
paul8708b742003-06-07 02:03:11 +0000427 i++;
paul718e3742002-12-13 20:15:29 +0000428 }
429 return com;
430}
431
432/* When given community attribute matches to the community-list return
433 1 else return 0. */
434int
435community_list_match (struct community *com, struct community_list *list)
436{
437 struct community_entry *entry;
438
439 for (entry = list->head; entry; entry = entry->next)
440 {
441 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000442 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000443
444 if (entry->style == COMMUNITY_LIST_STANDARD)
paul8708b742003-06-07 02:03:11 +0000445 {
446 if (community_include (entry->u.com, COMMUNITY_INTERNET))
447 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000448
paul8708b742003-06-07 02:03:11 +0000449 if (community_match (com, entry->u.com))
450 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
451 }
paul718e3742002-12-13 20:15:29 +0000452 else if (entry->style == COMMUNITY_LIST_EXPANDED)
paul8708b742003-06-07 02:03:11 +0000453 {
454 if (community_regexp_match (com, entry->reg))
455 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
456 }
457 }
458 return 0;
459}
460
461int
462ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
463{
464 struct community_entry *entry;
465
466 for (entry = list->head; entry; entry = entry->next)
467 {
468 if (entry->any)
469 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
470
471 if (entry->style == EXTCOMMUNITY_LIST_STANDARD)
472 {
473 if (ecommunity_match (ecom, entry->u.ecom))
474 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
475 }
476 else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED)
477 {
478 if (ecommunity_regexp_match (ecom, entry->reg))
479 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
480 }
paul718e3742002-12-13 20:15:29 +0000481 }
482 return 0;
483}
484
485/* Perform exact matching. In case of expanded community-list, do
486 same thing as community_list_match(). */
487int
paul8708b742003-06-07 02:03:11 +0000488community_list_exact_match (struct community *com,
489 struct community_list *list)
paul718e3742002-12-13 20:15:29 +0000490{
491 struct community_entry *entry;
492
493 for (entry = list->head; entry; entry = entry->next)
494 {
495 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000496 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000497
498 if (entry->style == COMMUNITY_LIST_STANDARD)
paul8708b742003-06-07 02:03:11 +0000499 {
500 if (community_include (entry->u.com, COMMUNITY_INTERNET))
501 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000502
paul8708b742003-06-07 02:03:11 +0000503 if (community_cmp (com, entry->u.com))
504 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
505 }
paul718e3742002-12-13 20:15:29 +0000506 else if (entry->style == COMMUNITY_LIST_EXPANDED)
paul8708b742003-06-07 02:03:11 +0000507 {
508 if (community_regexp_match (com, entry->reg))
509 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
510 }
paul718e3742002-12-13 20:15:29 +0000511 }
512 return 0;
513}
514
paul8708b742003-06-07 02:03:11 +0000515/* Delete all permitted communities in the list from com. */
paul718e3742002-12-13 20:15:29 +0000516struct community *
517community_list_match_delete (struct community *com,
paul8708b742003-06-07 02:03:11 +0000518 struct community_list *list)
paul718e3742002-12-13 20:15:29 +0000519{
520 struct community_entry *entry;
521
522 for (entry = list->head; entry; entry = entry->next)
523 {
paul847375b2003-06-09 18:48:31 +0000524 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000525 {
paul847375b2003-06-09 18:48:31 +0000526 if (entry->direct == COMMUNITY_PERMIT)
527 {
528 /* This is a tricky part. Currently only
529 * route_set_community_delete() uses this function. In the
530 * function com->size is zero, it free the community
531 * structure.
532 */
533 com->size = 0;
534 }
paul8708b742003-06-07 02:03:11 +0000535 return com;
536 }
paul718e3742002-12-13 20:15:29 +0000537
paul847375b2003-06-09 18:48:31 +0000538 if ((entry->style == COMMUNITY_LIST_STANDARD)
539 && (community_include (entry->u.com, COMMUNITY_INTERNET)
540 || community_match (com, entry->u.com) ))
paul8708b742003-06-07 02:03:11 +0000541 {
paul847375b2003-06-09 18:48:31 +0000542 if (entry->direct == COMMUNITY_PERMIT)
543 community_delete (com, entry->u.com);
544 else
545 break;
paul8708b742003-06-07 02:03:11 +0000546 }
paul847375b2003-06-09 18:48:31 +0000547 else if ((entry->style == COMMUNITY_LIST_EXPANDED)
548 && community_regexp_match (com, entry->reg))
paul8708b742003-06-07 02:03:11 +0000549 {
550 if (entry->direct == COMMUNITY_PERMIT)
551 community_regexp_delete (com, entry->reg);
paul847375b2003-06-09 18:48:31 +0000552 else
553 break;
paul8708b742003-06-07 02:03:11 +0000554 }
paul718e3742002-12-13 20:15:29 +0000555 }
556 return com;
557}
558
559/* To avoid duplicated entry in the community-list, this function
560 compares specified entry to existing entry. */
561int
paul8708b742003-06-07 02:03:11 +0000562community_list_dup_check (struct community_list *list,
563 struct community_entry *new)
paul718e3742002-12-13 20:15:29 +0000564{
565 struct community_entry *entry;
paul8708b742003-06-07 02:03:11 +0000566
paul718e3742002-12-13 20:15:29 +0000567 for (entry = list->head; entry; entry = entry->next)
568 {
569 if (entry->style != new->style)
paul8708b742003-06-07 02:03:11 +0000570 continue;
paul718e3742002-12-13 20:15:29 +0000571
572 if (entry->direct != new->direct)
paul8708b742003-06-07 02:03:11 +0000573 continue;
paul718e3742002-12-13 20:15:29 +0000574
575 if (entry->any != new->any)
paul8708b742003-06-07 02:03:11 +0000576 continue;
paul718e3742002-12-13 20:15:29 +0000577
578 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000579 return 1;
paul718e3742002-12-13 20:15:29 +0000580
581 switch (entry->style)
paul8708b742003-06-07 02:03:11 +0000582 {
583 case COMMUNITY_LIST_STANDARD:
584 if (community_cmp (entry->u.com, new->u.com))
585 return 1;
586 break;
587 case EXTCOMMUNITY_LIST_STANDARD:
588 if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
589 return 1;
590 break;
591 case COMMUNITY_LIST_EXPANDED:
592 case EXTCOMMUNITY_LIST_EXPANDED:
593 if (strcmp (entry->config, new->config) == 0)
594 return 1;
595 break;
596 default:
597 break;
598 }
paul718e3742002-12-13 20:15:29 +0000599 }
600 return 0;
601}
602
603/* Set community-list. */
604int
605community_list_set (struct community_list_handler *ch,
paulfd79ac92004-10-13 05:06:08 +0000606 const char *name, const char *str, int direct, int style)
paul718e3742002-12-13 20:15:29 +0000607{
hassofee6e4e2005-02-02 16:29:31 +0000608 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000609 struct community_list *list;
hassofee6e4e2005-02-02 16:29:31 +0000610 struct community *com = NULL;
611 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000612
613 /* Get community list. */
hassofee6e4e2005-02-02 16:29:31 +0000614 list = community_list_get (ch, name, COMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000615
616 /* When community-list already has entry, new entry should have same
617 style. If you want to have mixed style community-list, you can
618 comment out this check. */
paul8708b742003-06-07 02:03:11 +0000619 if (!community_list_empty_p (list))
paul718e3742002-12-13 20:15:29 +0000620 {
621 struct community_entry *first;
622
623 first = list->head;
624
hassofee6e4e2005-02-02 16:29:31 +0000625 if (style != first->style)
626 {
627 return (first->style == COMMUNITY_LIST_STANDARD
628 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
629 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
630 }
paul718e3742002-12-13 20:15:29 +0000631 }
632
hassofee6e4e2005-02-02 16:29:31 +0000633 if (str)
paul718e3742002-12-13 20:15:29 +0000634 {
hassofee6e4e2005-02-02 16:29:31 +0000635 if (style == COMMUNITY_LIST_STANDARD)
636 com = community_str2com (str);
paul718e3742002-12-13 20:15:29 +0000637 else
hassofee6e4e2005-02-02 16:29:31 +0000638 regex = bgp_regcomp (str);
paul8708b742003-06-07 02:03:11 +0000639
hassofee6e4e2005-02-02 16:29:31 +0000640 if (! com && ! regex)
641 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000642 }
643
hassofee6e4e2005-02-02 16:29:31 +0000644 entry = community_entry_new ();
645 entry->direct = direct;
646 entry->style = style;
647 entry->any = (str ? 0 : 1);
648 entry->u.com = com;
649 entry->reg = regex;
650 entry->config = (regex ? XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
651
paul718e3742002-12-13 20:15:29 +0000652 /* Do not put duplicated community entry. */
653 if (community_list_dup_check (list, entry))
654 community_entry_free (entry);
655 else
656 community_list_entry_add (list, entry);
657
658 return 0;
659}
660
661/* Unset community-list. When str is NULL, delete all of
662 community-list entry belongs to the specified name. */
663int
664community_list_unset (struct community_list_handler *ch,
paulfd79ac92004-10-13 05:06:08 +0000665 const char *name, const char *str,
666 int direct, int style)
paul718e3742002-12-13 20:15:29 +0000667{
hassofee6e4e2005-02-02 16:29:31 +0000668 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000669 struct community_list *list;
hassofee6e4e2005-02-02 16:29:31 +0000670 struct community *com = NULL;
671 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000672
673 /* Lookup community list. */
hassofee6e4e2005-02-02 16:29:31 +0000674 list = community_list_lookup (ch, name, COMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000675 if (list == NULL)
676 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
677
678 /* Delete all of entry belongs to this community-list. */
paul8708b742003-06-07 02:03:11 +0000679 if (!str)
paul718e3742002-12-13 20:15:29 +0000680 {
681 community_list_delete (list);
682 return 0;
683 }
684
hassofee6e4e2005-02-02 16:29:31 +0000685 if (style == COMMUNITY_LIST_STANDARD)
686 com = community_str2com (str);
687 else
688 regex = bgp_regcomp (str);
paul718e3742002-12-13 20:15:29 +0000689
hassofee6e4e2005-02-02 16:29:31 +0000690 if (! com && ! regex)
691 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000692
hassofee6e4e2005-02-02 16:29:31 +0000693 if (com)
694 entry = community_list_entry_lookup (list, com, direct);
695 else
696 entry = community_list_entry_lookup (list, str, direct);
697
698 if (com)
699 community_free (com);
700 if (regex)
701 bgp_regex_free (regex);
paul718e3742002-12-13 20:15:29 +0000702
paul8708b742003-06-07 02:03:11 +0000703 if (!entry)
paul718e3742002-12-13 20:15:29 +0000704 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
705
706 community_list_entry_delete (list, entry, style);
707
708 return 0;
709}
710
711/* Set extcommunity-list. */
712int
713extcommunity_list_set (struct community_list_handler *ch,
paulfd79ac92004-10-13 05:06:08 +0000714 const char *name, const char *str,
715 int direct, int style)
paul718e3742002-12-13 20:15:29 +0000716{
hassofee6e4e2005-02-02 16:29:31 +0000717 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000718 struct community_list *list;
hassofee6e4e2005-02-02 16:29:31 +0000719 struct ecommunity *ecom = NULL;
720 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000721
722 entry = NULL;
723
724 /* Get community list. */
hassofee6e4e2005-02-02 16:29:31 +0000725 list = community_list_get (ch, name, EXTCOMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000726
727 /* When community-list already has entry, new entry should have same
728 style. If you want to have mixed style community-list, you can
729 comment out this check. */
paul8708b742003-06-07 02:03:11 +0000730 if (!community_list_empty_p (list))
paul718e3742002-12-13 20:15:29 +0000731 {
732 struct community_entry *first;
733
734 first = list->head;
735
hassofee6e4e2005-02-02 16:29:31 +0000736 if (style != first->style)
737 {
738 return (first->style == EXTCOMMUNITY_LIST_STANDARD
739 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
740 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
741 }
paul718e3742002-12-13 20:15:29 +0000742 }
743
hassofee6e4e2005-02-02 16:29:31 +0000744 if (str)
paul718e3742002-12-13 20:15:29 +0000745 {
hassofee6e4e2005-02-02 16:29:31 +0000746 if (style == EXTCOMMUNITY_LIST_STANDARD)
747 ecom = ecommunity_str2com (str, 0, 1);
paul718e3742002-12-13 20:15:29 +0000748 else
hassofee6e4e2005-02-02 16:29:31 +0000749 regex = bgp_regcomp (str);
750
751 if (! ecom && ! regex)
752 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000753 }
hassofee6e4e2005-02-02 16:29:31 +0000754
755 if (ecom)
756 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
757
758 entry = community_entry_new ();
759 entry->direct = direct;
760 entry->style = style;
761 entry->any = (str ? 0 : 1);
762 if (ecom)
763 entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
764 else if (regex)
765 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
paul718e3742002-12-13 20:15:29 +0000766 else
hassofee6e4e2005-02-02 16:29:31 +0000767 entry->config = NULL;
768 entry->u.ecom = ecom;
769 entry->reg = regex;
paul718e3742002-12-13 20:15:29 +0000770
771 /* Do not put duplicated community entry. */
772 if (community_list_dup_check (list, entry))
773 community_entry_free (entry);
774 else
775 community_list_entry_add (list, entry);
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,
paulfd79ac92004-10-13 05:06:08 +0000784 const char *name, const char *str,
785 int direct, int style)
paul718e3742002-12-13 20:15:29 +0000786{
hassofee6e4e2005-02-02 16:29:31 +0000787 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000788 struct community_list *list;
789 struct ecommunity *ecom = NULL;
hassofee6e4e2005-02-02 16:29:31 +0000790 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000791
792 /* Lookup extcommunity list. */
hassofee6e4e2005-02-02 16:29:31 +0000793 list = community_list_lookup (ch, name, EXTCOMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000794 if (list == NULL)
795 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
796
797 /* Delete all of entry belongs to this extcommunity-list. */
paul8708b742003-06-07 02:03:11 +0000798 if (!str)
paul718e3742002-12-13 20:15:29 +0000799 {
800 community_list_delete (list);
801 return 0;
802 }
803
hassofee6e4e2005-02-02 16:29:31 +0000804 if (style == EXTCOMMUNITY_LIST_STANDARD)
805 ecom = ecommunity_str2com (str, 0, 1);
806 else
807 regex = bgp_regcomp (str);
paul718e3742002-12-13 20:15:29 +0000808
hassofee6e4e2005-02-02 16:29:31 +0000809 if (! ecom && ! regex)
810 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000811
hassofee6e4e2005-02-02 16:29:31 +0000812 if (ecom)
813 entry = community_list_entry_lookup (list, ecom, direct);
814 else
815 entry = community_list_entry_lookup (list, str, direct);
816
817 if (ecom)
818 ecommunity_free (ecom);
819 if (regex)
820 bgp_regex_free (regex);
paul718e3742002-12-13 20:15:29 +0000821
paul8708b742003-06-07 02:03:11 +0000822 if (!entry)
paul718e3742002-12-13 20:15:29 +0000823 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
824
825 community_list_entry_delete (list, entry, style);
826
827 return 0;
828}
829
830/* Initializa community-list. Return community-list handler. */
831struct community_list_handler *
832community_list_init ()
833{
834 struct community_list_handler *ch;
835 ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER,
paul8708b742003-06-07 02:03:11 +0000836 sizeof (struct community_list_handler));
paul718e3742002-12-13 20:15:29 +0000837 return ch;
838}
839
840/* Terminate community-list. */
841void
842community_list_terminate (struct community_list_handler *ch)
843{
844 struct community_list_master *cm;
845 struct community_list *list;
846
847 cm = &ch->community_list;
848 while ((list = cm->num.head) != NULL)
849 community_list_delete (list);
850 while ((list = cm->str.head) != NULL)
851 community_list_delete (list);
852
853 cm = &ch->extcommunity_list;
854 while ((list = cm->num.head) != NULL)
855 community_list_delete (list);
856 while ((list = cm->str.head) != NULL)
857 community_list_delete (list);
858
859 XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch);
860}