blob: f75fc55b379ebed0cf4f6729462a97aed37b8734 [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;
hassofee6e4e2005-02-02 16:29:31 +000044 case EXTCOMMUNITY_LIST_MASTER:
45 return &ch->extcommunity_list;
paul718e3742002-12-13 20:15:29 +000046 }
47 return NULL;
48}
49
50/* Allocate a new community list entry. */
paul94f2b392005-06-28 12:44:16 +000051static struct community_entry *
paul718e3742002-12-13 20:15:29 +000052community_entry_new ()
53{
54 struct community_entry *new;
55
56 new = XMALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry));
57 memset (new, 0, sizeof (struct community_entry));
58 return new;
59}
60
61/* Free community list entry. */
paul94f2b392005-06-28 12:44:16 +000062static void
paul718e3742002-12-13 20:15:29 +000063community_entry_free (struct community_entry *entry)
64{
65 switch (entry->style)
66 {
67 case COMMUNITY_LIST_STANDARD:
68 if (entry->u.com)
paul8708b742003-06-07 02:03:11 +000069 community_free (entry->u.com);
paul718e3742002-12-13 20:15:29 +000070 break;
71 case EXTCOMMUNITY_LIST_STANDARD:
72 /* In case of standard extcommunity-list, configuration string
paul8708b742003-06-07 02:03:11 +000073 is made by ecommunity_ecom2str(). */
paul718e3742002-12-13 20:15:29 +000074 if (entry->config)
paul8708b742003-06-07 02:03:11 +000075 XFREE (MTYPE_ECOMMUNITY_STR, entry->config);
paul718e3742002-12-13 20:15:29 +000076 if (entry->u.ecom)
paul8708b742003-06-07 02:03:11 +000077 ecommunity_free (entry->u.ecom);
paul718e3742002-12-13 20:15:29 +000078 break;
79 case COMMUNITY_LIST_EXPANDED:
80 case EXTCOMMUNITY_LIST_EXPANDED:
81 if (entry->config)
paul8708b742003-06-07 02:03:11 +000082 XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
paul718e3742002-12-13 20:15:29 +000083 if (entry->reg)
paul8708b742003-06-07 02:03:11 +000084 bgp_regex_free (entry->reg);
paul718e3742002-12-13 20:15:29 +000085 default:
86 break;
87 }
88 XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry);
89}
90
91/* Allocate a new community-list. */
paul94f2b392005-06-28 12:44:16 +000092static struct community_list *
paul718e3742002-12-13 20:15:29 +000093community_list_new ()
94{
95 struct community_list *new;
96
97 new = XMALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list));
98 memset (new, 0, sizeof (struct community_list));
99 return new;
100}
101
102/* Free community-list. */
paul94f2b392005-06-28 12:44:16 +0000103static void
paul718e3742002-12-13 20:15:29 +0000104community_list_free (struct community_list *list)
105{
106 if (list->name)
107 XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name);
108 XFREE (MTYPE_COMMUNITY_LIST, list);
109}
110
paul94f2b392005-06-28 12:44:16 +0000111static struct community_list *
paul718e3742002-12-13 20:15:29 +0000112community_list_insert (struct community_list_handler *ch,
hassofee6e4e2005-02-02 16:29:31 +0000113 const char *name, int master)
paul718e3742002-12-13 20:15:29 +0000114{
paulfd79ac92004-10-13 05:06:08 +0000115 size_t i;
paul718e3742002-12-13 20:15:29 +0000116 long number;
117 struct community_list *new;
118 struct community_list *point;
119 struct community_list_list *list;
120 struct community_list_master *cm;
121
122 /* Lookup community-list master. */
hassofee6e4e2005-02-02 16:29:31 +0000123 cm = community_list_master_lookup (ch, master);
paul8708b742003-06-07 02:03:11 +0000124 if (!cm)
paul718e3742002-12-13 20:15:29 +0000125 return NULL;
126
127 /* Allocate new community_list and copy given name. */
128 new = community_list_new ();
129 new->name = XSTRDUP (MTYPE_COMMUNITY_LIST_NAME, name);
130
131 /* If name is made by all digit character. We treat it as
132 number. */
133 for (number = 0, i = 0; i < strlen (name); i++)
134 {
135 if (isdigit ((int) name[i]))
paul8708b742003-06-07 02:03:11 +0000136 number = (number * 10) + (name[i] - '0');
paul718e3742002-12-13 20:15:29 +0000137 else
paul8708b742003-06-07 02:03:11 +0000138 break;
paul718e3742002-12-13 20:15:29 +0000139 }
140
141 /* In case of name is all digit character */
142 if (i == strlen (name))
143 {
144 new->sort = COMMUNITY_LIST_NUMBER;
145
146 /* Set access_list to number list. */
147 list = &cm->num;
148
149 for (point = list->head; point; point = point->next)
paul8708b742003-06-07 02:03:11 +0000150 if (atol (point->name) >= number)
151 break;
paul718e3742002-12-13 20:15:29 +0000152 }
153 else
154 {
155 new->sort = COMMUNITY_LIST_STRING;
156
157 /* Set access_list to string list. */
158 list = &cm->str;
paul8708b742003-06-07 02:03:11 +0000159
paul718e3742002-12-13 20:15:29 +0000160 /* Set point to insertion point. */
161 for (point = list->head; point; point = point->next)
paul8708b742003-06-07 02:03:11 +0000162 if (strcmp (point->name, name) >= 0)
163 break;
paul718e3742002-12-13 20:15:29 +0000164 }
165
166 /* Link to upper list. */
167 new->parent = list;
168
169 /* In case of this is the first element of master. */
170 if (list->head == NULL)
171 {
172 list->head = list->tail = new;
173 return new;
174 }
175
176 /* In case of insertion is made at the tail of access_list. */
177 if (point == NULL)
178 {
179 new->prev = list->tail;
180 list->tail->next = new;
181 list->tail = new;
182 return new;
183 }
184
185 /* In case of insertion is made at the head of access_list. */
186 if (point == list->head)
187 {
188 new->next = list->head;
189 list->head->prev = new;
190 list->head = new;
191 return new;
192 }
193
194 /* Insertion is made at middle of the access_list. */
195 new->next = point;
196 new->prev = point->prev;
197
198 if (point->prev)
199 point->prev->next = new;
200 point->prev = new;
201
202 return new;
203}
204
205struct community_list *
206community_list_lookup (struct community_list_handler *ch,
hassofee6e4e2005-02-02 16:29:31 +0000207 const char *name, int master)
paul718e3742002-12-13 20:15:29 +0000208{
209 struct community_list *list;
210 struct community_list_master *cm;
211
paul8708b742003-06-07 02:03:11 +0000212 if (!name)
paul718e3742002-12-13 20:15:29 +0000213 return NULL;
214
hassofee6e4e2005-02-02 16:29:31 +0000215 cm = community_list_master_lookup (ch, master);
paul8708b742003-06-07 02:03:11 +0000216 if (!cm)
paul718e3742002-12-13 20:15:29 +0000217 return NULL;
218
219 for (list = cm->num.head; list; list = list->next)
220 if (strcmp (list->name, name) == 0)
221 return list;
222 for (list = cm->str.head; list; list = list->next)
223 if (strcmp (list->name, name) == 0)
224 return list;
225
226 return NULL;
227}
228
paul94f2b392005-06-28 12:44:16 +0000229static struct community_list *
hassofee6e4e2005-02-02 16:29:31 +0000230community_list_get (struct community_list_handler *ch,
231 const char *name, int master)
paul718e3742002-12-13 20:15:29 +0000232{
233 struct community_list *list;
234
hassofee6e4e2005-02-02 16:29:31 +0000235 list = community_list_lookup (ch, name, master);
paul8708b742003-06-07 02:03:11 +0000236 if (!list)
hassofee6e4e2005-02-02 16:29:31 +0000237 list = community_list_insert (ch, name, master);
paul718e3742002-12-13 20:15:29 +0000238 return list;
239}
240
paul94f2b392005-06-28 12:44:16 +0000241static void
paul718e3742002-12-13 20:15:29 +0000242community_list_delete (struct community_list *list)
243{
244 struct community_list_list *clist;
245 struct community_entry *entry, *next;
246
247 for (entry = list->head; entry; entry = next)
248 {
249 next = entry->next;
250 community_entry_free (entry);
251 }
252
253 clist = list->parent;
254
255 if (list->next)
256 list->next->prev = list->prev;
257 else
258 clist->tail = list->prev;
259
260 if (list->prev)
261 list->prev->next = list->next;
262 else
263 clist->head = list->next;
264
265 community_list_free (list);
266}
267
paul94f2b392005-06-28 12:44:16 +0000268static int
paul718e3742002-12-13 20:15:29 +0000269community_list_empty_p (struct community_list *list)
270{
271 return (list->head == NULL && list->tail == NULL) ? 1 : 0;
272}
273
274/* Add community-list entry to the list. */
275static void
paul8708b742003-06-07 02:03:11 +0000276community_list_entry_add (struct community_list *list,
277 struct community_entry *entry)
paul718e3742002-12-13 20:15:29 +0000278{
279 entry->next = NULL;
280 entry->prev = list->tail;
281
282 if (list->tail)
283 list->tail->next = entry;
284 else
285 list->head = entry;
286 list->tail = entry;
287}
288
289/* Delete community-list entry from the list. */
290static void
291community_list_entry_delete (struct community_list *list,
paul8708b742003-06-07 02:03:11 +0000292 struct community_entry *entry, int style)
paul718e3742002-12-13 20:15:29 +0000293{
294 if (entry->next)
295 entry->next->prev = entry->prev;
296 else
297 list->tail = entry->prev;
298
299 if (entry->prev)
300 entry->prev->next = entry->next;
301 else
302 list->head = entry->next;
303
304 community_entry_free (entry);
305
306 if (community_list_empty_p (list))
307 community_list_delete (list);
308}
309
310/* Lookup community-list entry from the list. */
311static struct community_entry *
paulfd79ac92004-10-13 05:06:08 +0000312community_list_entry_lookup (struct community_list *list, const void *arg,
paul8708b742003-06-07 02:03:11 +0000313 int direct)
paul718e3742002-12-13 20:15:29 +0000314{
315 struct community_entry *entry;
316
317 for (entry = list->head; entry; entry = entry->next)
318 {
319 switch (entry->style)
paul8708b742003-06-07 02:03:11 +0000320 {
321 case COMMUNITY_LIST_STANDARD:
322 if (community_cmp (entry->u.com, arg))
323 return entry;
324 break;
325 case EXTCOMMUNITY_LIST_STANDARD:
326 if (ecommunity_cmp (entry->u.ecom, arg))
327 return entry;
328 break;
329 case COMMUNITY_LIST_EXPANDED:
330 case EXTCOMMUNITY_LIST_EXPANDED:
331 if (strcmp (entry->config, arg) == 0)
332 return entry;
333 break;
334 default:
335 break;
336 }
paul718e3742002-12-13 20:15:29 +0000337 }
338 return NULL;
339}
340
341/* Internal function to perform regular expression match for community
342 attribute. */
343static int
paul8708b742003-06-07 02:03:11 +0000344community_regexp_match (struct community *com, regex_t * reg)
paul718e3742002-12-13 20:15:29 +0000345{
paulfd79ac92004-10-13 05:06:08 +0000346 const char *str;
paul718e3742002-12-13 20:15:29 +0000347
348 /* When there is no communities attribute it is treated as empty
349 string. */
350 if (com == NULL || com->size == 0)
351 str = "";
352 else
353 str = community_str (com);
354
355 /* Regular expression match. */
356 if (regexec (reg, str, 0, NULL, 0) == 0)
357 return 1;
358
359 /* No match. */
360 return 0;
361}
362
paul8708b742003-06-07 02:03:11 +0000363static int
364ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
365{
paulfd79ac92004-10-13 05:06:08 +0000366 const char *str;
paul8708b742003-06-07 02:03:11 +0000367
368 /* When there is no communities attribute it is treated as empty
369 string. */
370 if (ecom == NULL || ecom->size == 0)
371 str = "";
372 else
373 str = ecommunity_str (ecom);
374
375 /* Regular expression match. */
376 if (regexec (reg, str, 0, NULL, 0) == 0)
377 return 1;
378
379 /* No match. */
380 return 0;
381}
382
paul718e3742002-12-13 20:15:29 +0000383/* Delete community attribute using regular expression match. Return
384 modified communites attribute. */
385static struct community *
paul8708b742003-06-07 02:03:11 +0000386community_regexp_delete (struct community *com, regex_t * reg)
paul718e3742002-12-13 20:15:29 +0000387{
388 int i;
389 u_int32_t comval;
390 /* Maximum is "65535:65535" + '\0'. */
391 char c[12];
paulfd79ac92004-10-13 05:06:08 +0000392 const char *str;
paul718e3742002-12-13 20:15:29 +0000393
paul8708b742003-06-07 02:03:11 +0000394 if (!com)
paul718e3742002-12-13 20:15:29 +0000395 return NULL;
396
397 i = 0;
398 while (i < com->size)
399 {
400 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
401 comval = ntohl (comval);
402
403 switch (comval)
paul8708b742003-06-07 02:03:11 +0000404 {
405 case COMMUNITY_INTERNET:
406 str = "internet";
407 break;
408 case COMMUNITY_NO_EXPORT:
409 str = "no-export";
410 break;
411 case COMMUNITY_NO_ADVERTISE:
412 str = "no-advertise";
413 break;
414 case COMMUNITY_LOCAL_AS:
415 str = "local-AS";
416 break;
417 default:
418 sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF);
419 str = c;
420 break;
421 }
paul718e3742002-12-13 20:15:29 +0000422
423 if (regexec (reg, str, 0, NULL, 0) == 0)
paul8708b742003-06-07 02:03:11 +0000424 community_del_val (com, com_nthval (com, i));
paul718e3742002-12-13 20:15:29 +0000425 else
paul8708b742003-06-07 02:03:11 +0000426 i++;
paul718e3742002-12-13 20:15:29 +0000427 }
428 return com;
429}
430
431/* When given community attribute matches to the community-list return
432 1 else return 0. */
433int
434community_list_match (struct community *com, struct community_list *list)
435{
436 struct community_entry *entry;
437
438 for (entry = list->head; entry; entry = entry->next)
439 {
440 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000441 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000442
443 if (entry->style == COMMUNITY_LIST_STANDARD)
paul8708b742003-06-07 02:03:11 +0000444 {
445 if (community_include (entry->u.com, COMMUNITY_INTERNET))
446 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000447
paul8708b742003-06-07 02:03:11 +0000448 if (community_match (com, entry->u.com))
449 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
450 }
paul718e3742002-12-13 20:15:29 +0000451 else if (entry->style == COMMUNITY_LIST_EXPANDED)
paul8708b742003-06-07 02:03:11 +0000452 {
453 if (community_regexp_match (com, entry->reg))
454 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
455 }
456 }
457 return 0;
458}
459
460int
461ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
462{
463 struct community_entry *entry;
464
465 for (entry = list->head; entry; entry = entry->next)
466 {
467 if (entry->any)
468 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
469
470 if (entry->style == EXTCOMMUNITY_LIST_STANDARD)
471 {
472 if (ecommunity_match (ecom, entry->u.ecom))
473 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
474 }
475 else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED)
476 {
477 if (ecommunity_regexp_match (ecom, entry->reg))
478 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
479 }
paul718e3742002-12-13 20:15:29 +0000480 }
481 return 0;
482}
483
484/* Perform exact matching. In case of expanded community-list, do
485 same thing as community_list_match(). */
486int
paul8708b742003-06-07 02:03:11 +0000487community_list_exact_match (struct community *com,
488 struct community_list *list)
paul718e3742002-12-13 20:15:29 +0000489{
490 struct community_entry *entry;
491
492 for (entry = list->head; entry; entry = entry->next)
493 {
494 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000495 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000496
497 if (entry->style == COMMUNITY_LIST_STANDARD)
paul8708b742003-06-07 02:03:11 +0000498 {
499 if (community_include (entry->u.com, COMMUNITY_INTERNET))
500 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000501
paul8708b742003-06-07 02:03:11 +0000502 if (community_cmp (com, entry->u.com))
503 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
504 }
paul718e3742002-12-13 20:15:29 +0000505 else if (entry->style == COMMUNITY_LIST_EXPANDED)
paul8708b742003-06-07 02:03:11 +0000506 {
507 if (community_regexp_match (com, entry->reg))
508 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
509 }
paul718e3742002-12-13 20:15:29 +0000510 }
511 return 0;
512}
513
paul8708b742003-06-07 02:03:11 +0000514/* Delete all permitted communities in the list from com. */
paul718e3742002-12-13 20:15:29 +0000515struct community *
516community_list_match_delete (struct community *com,
paul8708b742003-06-07 02:03:11 +0000517 struct community_list *list)
paul718e3742002-12-13 20:15:29 +0000518{
519 struct community_entry *entry;
520
521 for (entry = list->head; entry; entry = entry->next)
522 {
paul847375b2003-06-09 18:48:31 +0000523 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000524 {
paul847375b2003-06-09 18:48:31 +0000525 if (entry->direct == COMMUNITY_PERMIT)
526 {
527 /* This is a tricky part. Currently only
528 * route_set_community_delete() uses this function. In the
529 * function com->size is zero, it free the community
530 * structure.
531 */
532 com->size = 0;
533 }
paul8708b742003-06-07 02:03:11 +0000534 return com;
535 }
paul718e3742002-12-13 20:15:29 +0000536
paul847375b2003-06-09 18:48:31 +0000537 if ((entry->style == COMMUNITY_LIST_STANDARD)
538 && (community_include (entry->u.com, COMMUNITY_INTERNET)
539 || community_match (com, entry->u.com) ))
paul8708b742003-06-07 02:03:11 +0000540 {
paul847375b2003-06-09 18:48:31 +0000541 if (entry->direct == COMMUNITY_PERMIT)
542 community_delete (com, entry->u.com);
543 else
544 break;
paul8708b742003-06-07 02:03:11 +0000545 }
paul847375b2003-06-09 18:48:31 +0000546 else if ((entry->style == COMMUNITY_LIST_EXPANDED)
547 && community_regexp_match (com, entry->reg))
paul8708b742003-06-07 02:03:11 +0000548 {
549 if (entry->direct == COMMUNITY_PERMIT)
550 community_regexp_delete (com, entry->reg);
paul847375b2003-06-09 18:48:31 +0000551 else
552 break;
paul8708b742003-06-07 02:03:11 +0000553 }
paul718e3742002-12-13 20:15:29 +0000554 }
555 return com;
556}
557
558/* To avoid duplicated entry in the community-list, this function
559 compares specified entry to existing entry. */
paul94f2b392005-06-28 12:44:16 +0000560static int
paul8708b742003-06-07 02:03:11 +0000561community_list_dup_check (struct community_list *list,
562 struct community_entry *new)
paul718e3742002-12-13 20:15:29 +0000563{
564 struct community_entry *entry;
paul8708b742003-06-07 02:03:11 +0000565
paul718e3742002-12-13 20:15:29 +0000566 for (entry = list->head; entry; entry = entry->next)
567 {
568 if (entry->style != new->style)
paul8708b742003-06-07 02:03:11 +0000569 continue;
paul718e3742002-12-13 20:15:29 +0000570
571 if (entry->direct != new->direct)
paul8708b742003-06-07 02:03:11 +0000572 continue;
paul718e3742002-12-13 20:15:29 +0000573
574 if (entry->any != new->any)
paul8708b742003-06-07 02:03:11 +0000575 continue;
paul718e3742002-12-13 20:15:29 +0000576
577 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000578 return 1;
paul718e3742002-12-13 20:15:29 +0000579
580 switch (entry->style)
paul8708b742003-06-07 02:03:11 +0000581 {
582 case COMMUNITY_LIST_STANDARD:
583 if (community_cmp (entry->u.com, new->u.com))
584 return 1;
585 break;
586 case EXTCOMMUNITY_LIST_STANDARD:
587 if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
588 return 1;
589 break;
590 case COMMUNITY_LIST_EXPANDED:
591 case EXTCOMMUNITY_LIST_EXPANDED:
592 if (strcmp (entry->config, new->config) == 0)
593 return 1;
594 break;
595 default:
596 break;
597 }
paul718e3742002-12-13 20:15:29 +0000598 }
599 return 0;
600}
601
602/* Set community-list. */
603int
604community_list_set (struct community_list_handler *ch,
paulfd79ac92004-10-13 05:06:08 +0000605 const char *name, const char *str, int direct, int style)
paul718e3742002-12-13 20:15:29 +0000606{
hassofee6e4e2005-02-02 16:29:31 +0000607 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000608 struct community_list *list;
hassofee6e4e2005-02-02 16:29:31 +0000609 struct community *com = NULL;
610 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000611
612 /* Get community list. */
hassofee6e4e2005-02-02 16:29:31 +0000613 list = community_list_get (ch, name, COMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000614
615 /* When community-list already has entry, new entry should have same
616 style. If you want to have mixed style community-list, you can
617 comment out this check. */
paul8708b742003-06-07 02:03:11 +0000618 if (!community_list_empty_p (list))
paul718e3742002-12-13 20:15:29 +0000619 {
620 struct community_entry *first;
621
622 first = list->head;
623
hassofee6e4e2005-02-02 16:29:31 +0000624 if (style != first->style)
625 {
626 return (first->style == COMMUNITY_LIST_STANDARD
627 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
628 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
629 }
paul718e3742002-12-13 20:15:29 +0000630 }
631
hassofee6e4e2005-02-02 16:29:31 +0000632 if (str)
paul718e3742002-12-13 20:15:29 +0000633 {
hassofee6e4e2005-02-02 16:29:31 +0000634 if (style == COMMUNITY_LIST_STANDARD)
635 com = community_str2com (str);
paul718e3742002-12-13 20:15:29 +0000636 else
hassofee6e4e2005-02-02 16:29:31 +0000637 regex = bgp_regcomp (str);
paul8708b742003-06-07 02:03:11 +0000638
hassofee6e4e2005-02-02 16:29:31 +0000639 if (! com && ! regex)
640 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000641 }
642
hassofee6e4e2005-02-02 16:29:31 +0000643 entry = community_entry_new ();
644 entry->direct = direct;
645 entry->style = style;
646 entry->any = (str ? 0 : 1);
647 entry->u.com = com;
648 entry->reg = regex;
649 entry->config = (regex ? XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
650
paul718e3742002-12-13 20:15:29 +0000651 /* Do not put duplicated community entry. */
652 if (community_list_dup_check (list, entry))
653 community_entry_free (entry);
654 else
655 community_list_entry_add (list, entry);
656
657 return 0;
658}
659
660/* Unset community-list. When str is NULL, delete all of
661 community-list entry belongs to the specified name. */
662int
663community_list_unset (struct community_list_handler *ch,
paulfd79ac92004-10-13 05:06:08 +0000664 const char *name, const char *str,
665 int direct, int style)
paul718e3742002-12-13 20:15:29 +0000666{
hassofee6e4e2005-02-02 16:29:31 +0000667 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000668 struct community_list *list;
hassofee6e4e2005-02-02 16:29:31 +0000669 struct community *com = NULL;
670 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000671
672 /* Lookup community list. */
hassofee6e4e2005-02-02 16:29:31 +0000673 list = community_list_lookup (ch, name, COMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000674 if (list == NULL)
675 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
676
677 /* Delete all of entry belongs to this community-list. */
paul8708b742003-06-07 02:03:11 +0000678 if (!str)
paul718e3742002-12-13 20:15:29 +0000679 {
680 community_list_delete (list);
681 return 0;
682 }
683
hassofee6e4e2005-02-02 16:29:31 +0000684 if (style == COMMUNITY_LIST_STANDARD)
685 com = community_str2com (str);
686 else
687 regex = bgp_regcomp (str);
paul718e3742002-12-13 20:15:29 +0000688
hassofee6e4e2005-02-02 16:29:31 +0000689 if (! com && ! regex)
690 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000691
hassofee6e4e2005-02-02 16:29:31 +0000692 if (com)
693 entry = community_list_entry_lookup (list, com, direct);
694 else
695 entry = community_list_entry_lookup (list, str, direct);
696
697 if (com)
698 community_free (com);
699 if (regex)
700 bgp_regex_free (regex);
paul718e3742002-12-13 20:15:29 +0000701
paul8708b742003-06-07 02:03:11 +0000702 if (!entry)
paul718e3742002-12-13 20:15:29 +0000703 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
704
705 community_list_entry_delete (list, entry, style);
706
707 return 0;
708}
709
710/* Set extcommunity-list. */
711int
712extcommunity_list_set (struct community_list_handler *ch,
paulfd79ac92004-10-13 05:06:08 +0000713 const char *name, const char *str,
714 int direct, int style)
paul718e3742002-12-13 20:15:29 +0000715{
hassofee6e4e2005-02-02 16:29:31 +0000716 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000717 struct community_list *list;
hassofee6e4e2005-02-02 16:29:31 +0000718 struct ecommunity *ecom = NULL;
719 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000720
721 entry = NULL;
722
723 /* Get community list. */
hassofee6e4e2005-02-02 16:29:31 +0000724 list = community_list_get (ch, name, EXTCOMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000725
726 /* When community-list already has entry, new entry should have same
727 style. If you want to have mixed style community-list, you can
728 comment out this check. */
paul8708b742003-06-07 02:03:11 +0000729 if (!community_list_empty_p (list))
paul718e3742002-12-13 20:15:29 +0000730 {
731 struct community_entry *first;
732
733 first = list->head;
734
hassofee6e4e2005-02-02 16:29:31 +0000735 if (style != first->style)
736 {
737 return (first->style == EXTCOMMUNITY_LIST_STANDARD
738 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
739 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
740 }
paul718e3742002-12-13 20:15:29 +0000741 }
742
hassofee6e4e2005-02-02 16:29:31 +0000743 if (str)
paul718e3742002-12-13 20:15:29 +0000744 {
hassofee6e4e2005-02-02 16:29:31 +0000745 if (style == EXTCOMMUNITY_LIST_STANDARD)
746 ecom = ecommunity_str2com (str, 0, 1);
paul718e3742002-12-13 20:15:29 +0000747 else
hassofee6e4e2005-02-02 16:29:31 +0000748 regex = bgp_regcomp (str);
749
750 if (! ecom && ! regex)
751 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000752 }
hassofee6e4e2005-02-02 16:29:31 +0000753
754 if (ecom)
755 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
756
757 entry = community_entry_new ();
758 entry->direct = direct;
759 entry->style = style;
760 entry->any = (str ? 0 : 1);
761 if (ecom)
762 entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
763 else if (regex)
764 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
paul718e3742002-12-13 20:15:29 +0000765 else
hassofee6e4e2005-02-02 16:29:31 +0000766 entry->config = NULL;
767 entry->u.ecom = ecom;
768 entry->reg = regex;
paul718e3742002-12-13 20:15:29 +0000769
770 /* Do not put duplicated community entry. */
771 if (community_list_dup_check (list, entry))
772 community_entry_free (entry);
773 else
774 community_list_entry_add (list, entry);
775
776 return 0;
777}
778
779/* Unset extcommunity-list. When str is NULL, delete all of
780 extcommunity-list entry belongs to the specified name. */
781int
782extcommunity_list_unset (struct community_list_handler *ch,
paulfd79ac92004-10-13 05:06:08 +0000783 const char *name, const char *str,
784 int direct, int style)
paul718e3742002-12-13 20:15:29 +0000785{
hassofee6e4e2005-02-02 16:29:31 +0000786 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000787 struct community_list *list;
788 struct ecommunity *ecom = NULL;
hassofee6e4e2005-02-02 16:29:31 +0000789 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000790
791 /* Lookup extcommunity list. */
hassofee6e4e2005-02-02 16:29:31 +0000792 list = community_list_lookup (ch, name, EXTCOMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000793 if (list == NULL)
794 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
795
796 /* Delete all of entry belongs to this extcommunity-list. */
paul8708b742003-06-07 02:03:11 +0000797 if (!str)
paul718e3742002-12-13 20:15:29 +0000798 {
799 community_list_delete (list);
800 return 0;
801 }
802
hassofee6e4e2005-02-02 16:29:31 +0000803 if (style == EXTCOMMUNITY_LIST_STANDARD)
804 ecom = ecommunity_str2com (str, 0, 1);
805 else
806 regex = bgp_regcomp (str);
paul718e3742002-12-13 20:15:29 +0000807
hassofee6e4e2005-02-02 16:29:31 +0000808 if (! ecom && ! regex)
809 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000810
hassofee6e4e2005-02-02 16:29:31 +0000811 if (ecom)
812 entry = community_list_entry_lookup (list, ecom, direct);
813 else
814 entry = community_list_entry_lookup (list, str, direct);
815
816 if (ecom)
817 ecommunity_free (ecom);
818 if (regex)
819 bgp_regex_free (regex);
paul718e3742002-12-13 20:15:29 +0000820
paul8708b742003-06-07 02:03:11 +0000821 if (!entry)
paul718e3742002-12-13 20:15:29 +0000822 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
823
824 community_list_entry_delete (list, entry, style);
825
826 return 0;
827}
828
829/* Initializa community-list. Return community-list handler. */
830struct community_list_handler *
paul94f2b392005-06-28 12:44:16 +0000831community_list_init (void)
paul718e3742002-12-13 20:15:29 +0000832{
833 struct community_list_handler *ch;
834 ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER,
paul8708b742003-06-07 02:03:11 +0000835 sizeof (struct community_list_handler));
paul718e3742002-12-13 20:15:29 +0000836 return ch;
837}
838
839/* Terminate community-list. */
paul94f2b392005-06-28 12:44:16 +0000840static void
paul718e3742002-12-13 20:15:29 +0000841community_list_terminate (struct community_list_handler *ch)
842{
843 struct community_list_master *cm;
844 struct community_list *list;
845
846 cm = &ch->community_list;
847 while ((list = cm->num.head) != NULL)
848 community_list_delete (list);
849 while ((list = cm->str.head) != NULL)
850 community_list_delete (list);
851
852 cm = &ch->extcommunity_list;
853 while ((list = cm->num.head) != NULL)
854 community_list_delete (list);
855 while ((list = cm->str.head) != NULL)
856 community_list_delete (list);
857
858 XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch);
859}