blob: 800bd01290109b81aa8ad3d6d9e6cd13b50ff0f4 [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"
Donald Sharp04907292016-01-07 10:03:01 -050026#include "filter.h"
paul718e3742002-12-13 20:15:29 +000027
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"
David Lamparter6b0655a2014-06-04 06:53:35 +020034
paul718e3742002-12-13 20:15:29 +000035/* Lookup master structure for community-list or
36 extcommunity-list. */
37struct community_list_master *
hassofee6e4e2005-02-02 16:29:31 +000038community_list_master_lookup (struct community_list_handler *ch, int master)
paul718e3742002-12-13 20:15:29 +000039{
40 if (ch)
hassofee6e4e2005-02-02 16:29:31 +000041 switch (master)
paul718e3742002-12-13 20:15:29 +000042 {
hassofee6e4e2005-02-02 16:29:31 +000043 case COMMUNITY_LIST_MASTER:
44 return &ch->community_list;
hassofee6e4e2005-02-02 16:29:31 +000045 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. */
paul94f2b392005-06-28 12:44:16 +000052static struct community_entry *
Stephen Hemminger66e5cd82009-02-09 10:14:16 -080053community_entry_new (void)
paul718e3742002-12-13 20:15:29 +000054{
Stephen Hemminger393deb92008-08-18 14:13:29 -070055 return XCALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry));
paul718e3742002-12-13 20:15:29 +000056}
57
58/* Free community list entry. */
paul94f2b392005-06-28 12:44:16 +000059static void
paul718e3742002-12-13 20:15:29 +000060community_entry_free (struct community_entry *entry)
61{
62 switch (entry->style)
63 {
64 case COMMUNITY_LIST_STANDARD:
65 if (entry->u.com)
paul8708b742003-06-07 02:03:11 +000066 community_free (entry->u.com);
paul718e3742002-12-13 20:15:29 +000067 break;
68 case EXTCOMMUNITY_LIST_STANDARD:
69 /* In case of standard extcommunity-list, configuration string
paul8708b742003-06-07 02:03:11 +000070 is made by ecommunity_ecom2str(). */
paul718e3742002-12-13 20:15:29 +000071 if (entry->config)
paul8708b742003-06-07 02:03:11 +000072 XFREE (MTYPE_ECOMMUNITY_STR, entry->config);
paul718e3742002-12-13 20:15:29 +000073 if (entry->u.ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +000074 ecommunity_free (&entry->u.ecom);
paul718e3742002-12-13 20:15:29 +000075 break;
76 case COMMUNITY_LIST_EXPANDED:
77 case EXTCOMMUNITY_LIST_EXPANDED:
78 if (entry->config)
paul8708b742003-06-07 02:03:11 +000079 XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
paul718e3742002-12-13 20:15:29 +000080 if (entry->reg)
paul8708b742003-06-07 02:03:11 +000081 bgp_regex_free (entry->reg);
paul718e3742002-12-13 20:15:29 +000082 default:
83 break;
84 }
85 XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry);
86}
87
88/* Allocate a new community-list. */
paul94f2b392005-06-28 12:44:16 +000089static struct community_list *
Stephen Hemminger66e5cd82009-02-09 10:14:16 -080090community_list_new (void)
paul718e3742002-12-13 20:15:29 +000091{
Stephen Hemminger393deb92008-08-18 14:13:29 -070092 return XCALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list));
paul718e3742002-12-13 20:15:29 +000093}
94
95/* Free community-list. */
paul94f2b392005-06-28 12:44:16 +000096static void
paul718e3742002-12-13 20:15:29 +000097community_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
paul94f2b392005-06-28 12:44:16 +0000104static struct community_list *
paul718e3742002-12-13 20:15:29 +0000105community_list_insert (struct community_list_handler *ch,
hassofee6e4e2005-02-02 16:29:31 +0000106 const char *name, int master)
paul718e3742002-12-13 20:15:29 +0000107{
paulfd79ac92004-10-13 05:06:08 +0000108 size_t i;
paul718e3742002-12-13 20:15:29 +0000109 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. */
hassofee6e4e2005-02-02 16:29:31 +0000116 cm = community_list_master_lookup (ch, master);
paul8708b742003-06-07 02:03:11 +0000117 if (!cm)
paul718e3742002-12-13 20:15:29 +0000118 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]))
paul8708b742003-06-07 02:03:11 +0000129 number = (number * 10) + (name[i] - '0');
paul718e3742002-12-13 20:15:29 +0000130 else
paul8708b742003-06-07 02:03:11 +0000131 break;
paul718e3742002-12-13 20:15:29 +0000132 }
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)
paul8708b742003-06-07 02:03:11 +0000143 if (atol (point->name) >= number)
144 break;
paul718e3742002-12-13 20:15:29 +0000145 }
146 else
147 {
148 new->sort = COMMUNITY_LIST_STRING;
149
150 /* Set access_list to string list. */
151 list = &cm->str;
paul8708b742003-06-07 02:03:11 +0000152
paul718e3742002-12-13 20:15:29 +0000153 /* Set point to insertion point. */
154 for (point = list->head; point; point = point->next)
paul8708b742003-06-07 02:03:11 +0000155 if (strcmp (point->name, name) >= 0)
156 break;
paul718e3742002-12-13 20:15:29 +0000157 }
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,
hassofee6e4e2005-02-02 16:29:31 +0000200 const char *name, int master)
paul718e3742002-12-13 20:15:29 +0000201{
202 struct community_list *list;
203 struct community_list_master *cm;
204
paul8708b742003-06-07 02:03:11 +0000205 if (!name)
paul718e3742002-12-13 20:15:29 +0000206 return NULL;
207
hassofee6e4e2005-02-02 16:29:31 +0000208 cm = community_list_master_lookup (ch, master);
paul8708b742003-06-07 02:03:11 +0000209 if (!cm)
paul718e3742002-12-13 20:15:29 +0000210 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
paul94f2b392005-06-28 12:44:16 +0000222static struct community_list *
hassofee6e4e2005-02-02 16:29:31 +0000223community_list_get (struct community_list_handler *ch,
224 const char *name, int master)
paul718e3742002-12-13 20:15:29 +0000225{
226 struct community_list *list;
227
hassofee6e4e2005-02-02 16:29:31 +0000228 list = community_list_lookup (ch, name, master);
paul8708b742003-06-07 02:03:11 +0000229 if (!list)
hassofee6e4e2005-02-02 16:29:31 +0000230 list = community_list_insert (ch, name, master);
paul718e3742002-12-13 20:15:29 +0000231 return list;
232}
233
paul94f2b392005-06-28 12:44:16 +0000234static void
paul718e3742002-12-13 20:15:29 +0000235community_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
paul94f2b392005-06-28 12:44:16 +0000261static int
paul718e3742002-12-13 20:15:29 +0000262community_list_empty_p (struct community_list *list)
263{
264 return (list->head == NULL && list->tail == NULL) ? 1 : 0;
265}
David Lamparter6b0655a2014-06-04 06:53:35 +0200266
paul718e3742002-12-13 20:15:29 +0000267/* Add community-list entry to the list. */
268static void
paul8708b742003-06-07 02:03:11 +0000269community_list_entry_add (struct community_list *list,
270 struct community_entry *entry)
paul718e3742002-12-13 20:15:29 +0000271{
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,
paul8708b742003-06-07 02:03:11 +0000285 struct community_entry *entry, int style)
paul718e3742002-12-13 20:15:29 +0000286{
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 *
paulfd79ac92004-10-13 05:06:08 +0000305community_list_entry_lookup (struct community_list *list, const void *arg,
paul8708b742003-06-07 02:03:11 +0000306 int direct)
paul718e3742002-12-13 20:15:29 +0000307{
308 struct community_entry *entry;
309
310 for (entry = list->head; entry; entry = entry->next)
311 {
312 switch (entry->style)
paul8708b742003-06-07 02:03:11 +0000313 {
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 }
paul718e3742002-12-13 20:15:29 +0000330 }
331 return NULL;
332}
David Lamparter6b0655a2014-06-04 06:53:35 +0200333
Daniel Waltond3ac7332015-08-24 10:19:10 -0400334static 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{
Christian Franke32e41f72016-06-14 20:06:59 +0200405 char *str;
406 int rv;
Daniel Waltond3ac7332015-08-24 10:19:10 -0400407
408 /* When there is no communities attribute it is treated as empty
409 * string. */
410 if (com == NULL || com->size == 0)
Christian Franke32e41f72016-06-14 20:06:59 +0200411 str = XSTRDUP(MTYPE_COMMUNITY_STR, "");
Daniel Waltond3ac7332015-08-24 10:19:10 -0400412 else
413 str = community_str_get (com, i);
414
415 /* Regular expression match. */
Christian Franke32e41f72016-06-14 20:06:59 +0200416 rv = regexec (reg, str, 0, NULL, 0);
417
418 XFREE(MTYPE_COMMUNITY_STR, str);
419
420 if (rv == 0)
Daniel Waltond3ac7332015-08-24 10:19:10 -0400421 return 1;
422
423 /* No match. */
424 return 0;
425}
426
paul718e3742002-12-13 20:15:29 +0000427/* Internal function to perform regular expression match for community
428 attribute. */
429static int
paul8708b742003-06-07 02:03:11 +0000430community_regexp_match (struct community *com, regex_t * reg)
paul718e3742002-12-13 20:15:29 +0000431{
paulfd79ac92004-10-13 05:06:08 +0000432 const char *str;
paul718e3742002-12-13 20:15:29 +0000433
434 /* When there is no communities attribute it is treated as empty
435 string. */
436 if (com == NULL || com->size == 0)
437 str = "";
438 else
439 str = community_str (com);
440
441 /* Regular expression match. */
442 if (regexec (reg, str, 0, NULL, 0) == 0)
443 return 1;
444
445 /* No match. */
446 return 0;
447}
448
paul8708b742003-06-07 02:03:11 +0000449static int
450ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
451{
paulfd79ac92004-10-13 05:06:08 +0000452 const char *str;
paul8708b742003-06-07 02:03:11 +0000453
454 /* When there is no communities attribute it is treated as empty
455 string. */
456 if (ecom == NULL || ecom->size == 0)
457 str = "";
458 else
459 str = ecommunity_str (ecom);
460
461 /* Regular expression match. */
462 if (regexec (reg, str, 0, NULL, 0) == 0)
463 return 1;
464
465 /* No match. */
466 return 0;
467}
468
paul718e3742002-12-13 20:15:29 +0000469/* When given community attribute matches to the community-list return
470 1 else return 0. */
471int
472community_list_match (struct community *com, struct community_list *list)
473{
474 struct community_entry *entry;
475
476 for (entry = list->head; entry; entry = entry->next)
477 {
478 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000479 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000480
481 if (entry->style == COMMUNITY_LIST_STANDARD)
paul8708b742003-06-07 02:03:11 +0000482 {
483 if (community_include (entry->u.com, COMMUNITY_INTERNET))
484 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000485
paul8708b742003-06-07 02:03:11 +0000486 if (community_match (com, entry->u.com))
487 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
488 }
paul718e3742002-12-13 20:15:29 +0000489 else if (entry->style == COMMUNITY_LIST_EXPANDED)
paul8708b742003-06-07 02:03:11 +0000490 {
491 if (community_regexp_match (com, entry->reg))
492 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
493 }
494 }
495 return 0;
496}
497
498int
499ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
500{
501 struct community_entry *entry;
502
503 for (entry = list->head; entry; entry = entry->next)
504 {
505 if (entry->any)
506 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
507
508 if (entry->style == EXTCOMMUNITY_LIST_STANDARD)
509 {
510 if (ecommunity_match (ecom, entry->u.ecom))
511 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
512 }
513 else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED)
514 {
515 if (ecommunity_regexp_match (ecom, entry->reg))
516 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
517 }
paul718e3742002-12-13 20:15:29 +0000518 }
519 return 0;
520}
521
522/* Perform exact matching. In case of expanded community-list, do
523 same thing as community_list_match(). */
524int
paul8708b742003-06-07 02:03:11 +0000525community_list_exact_match (struct community *com,
526 struct community_list *list)
paul718e3742002-12-13 20:15:29 +0000527{
528 struct community_entry *entry;
529
530 for (entry = list->head; entry; entry = entry->next)
531 {
532 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000533 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000534
535 if (entry->style == COMMUNITY_LIST_STANDARD)
paul8708b742003-06-07 02:03:11 +0000536 {
537 if (community_include (entry->u.com, COMMUNITY_INTERNET))
538 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
paul718e3742002-12-13 20:15:29 +0000539
paul8708b742003-06-07 02:03:11 +0000540 if (community_cmp (com, entry->u.com))
541 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
542 }
paul718e3742002-12-13 20:15:29 +0000543 else if (entry->style == COMMUNITY_LIST_EXPANDED)
paul8708b742003-06-07 02:03:11 +0000544 {
545 if (community_regexp_match (com, entry->reg))
546 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
547 }
paul718e3742002-12-13 20:15:29 +0000548 }
549 return 0;
550}
551
paul8708b742003-06-07 02:03:11 +0000552/* Delete all permitted communities in the list from com. */
paul718e3742002-12-13 20:15:29 +0000553struct community *
554community_list_match_delete (struct community *com,
paul8708b742003-06-07 02:03:11 +0000555 struct community_list *list)
paul718e3742002-12-13 20:15:29 +0000556{
557 struct community_entry *entry;
Daniel Waltond3ac7332015-08-24 10:19:10 -0400558 u_int32_t val;
559 u_int32_t com_index_to_delete[com->size];
560 int delete_index = 0;
561 int i;
paul718e3742002-12-13 20:15:29 +0000562
Daniel Waltond3ac7332015-08-24 10:19:10 -0400563 /* Loop over each community value and evaluate each against the
564 * community-list. If we need to delete a community value add its index to
565 * com_index_to_delete.
566 */
567 for (i = 0; i < com->size; i++)
paul718e3742002-12-13 20:15:29 +0000568 {
Daniel Waltond3ac7332015-08-24 10:19:10 -0400569 val = community_val_get (com, i);
paul718e3742002-12-13 20:15:29 +0000570
Daniel Waltond3ac7332015-08-24 10:19:10 -0400571 for (entry = list->head; entry; entry = entry->next)
paul8708b742003-06-07 02:03:11 +0000572 {
Daniel Waltond3ac7332015-08-24 10:19:10 -0400573 if (entry->any)
574 {
paul847375b2003-06-09 18:48:31 +0000575 if (entry->direct == COMMUNITY_PERMIT)
Daniel Waltond3ac7332015-08-24 10:19:10 -0400576 {
577 com_index_to_delete[delete_index] = i;
578 delete_index++;
579 }
580 break;
581 }
582
583 else if ((entry->style == COMMUNITY_LIST_STANDARD)
584 && (community_include (entry->u.com, COMMUNITY_INTERNET)
585 || community_include (entry->u.com, val) ))
586 {
587 if (entry->direct == COMMUNITY_PERMIT)
588 {
589 com_index_to_delete[delete_index] = i;
590 delete_index++;
591 }
592 break;
593 }
594
595 else if ((entry->style == COMMUNITY_LIST_EXPANDED)
596 && community_regexp_include (entry->reg, com, i))
597 {
598 if (entry->direct == COMMUNITY_PERMIT)
599 {
600 com_index_to_delete[delete_index] = i;
601 delete_index++;
602 }
603 break;
604 }
605 }
606 }
607
608 /* Delete all of the communities we flagged for deletion */
609 for (i = delete_index-1; i >= 0; i--)
610 {
611 val = community_val_get (com, com_index_to_delete[i]);
612 community_del_val (com, &val);
paul718e3742002-12-13 20:15:29 +0000613 }
Daniel Waltond3ac7332015-08-24 10:19:10 -0400614
paul718e3742002-12-13 20:15:29 +0000615 return com;
616}
617
618/* To avoid duplicated entry in the community-list, this function
619 compares specified entry to existing entry. */
paul94f2b392005-06-28 12:44:16 +0000620static int
paul8708b742003-06-07 02:03:11 +0000621community_list_dup_check (struct community_list *list,
622 struct community_entry *new)
paul718e3742002-12-13 20:15:29 +0000623{
624 struct community_entry *entry;
paul8708b742003-06-07 02:03:11 +0000625
paul718e3742002-12-13 20:15:29 +0000626 for (entry = list->head; entry; entry = entry->next)
627 {
628 if (entry->style != new->style)
paul8708b742003-06-07 02:03:11 +0000629 continue;
paul718e3742002-12-13 20:15:29 +0000630
631 if (entry->direct != new->direct)
paul8708b742003-06-07 02:03:11 +0000632 continue;
paul718e3742002-12-13 20:15:29 +0000633
634 if (entry->any != new->any)
paul8708b742003-06-07 02:03:11 +0000635 continue;
paul718e3742002-12-13 20:15:29 +0000636
637 if (entry->any)
paul8708b742003-06-07 02:03:11 +0000638 return 1;
paul718e3742002-12-13 20:15:29 +0000639
640 switch (entry->style)
paul8708b742003-06-07 02:03:11 +0000641 {
642 case COMMUNITY_LIST_STANDARD:
643 if (community_cmp (entry->u.com, new->u.com))
644 return 1;
645 break;
646 case EXTCOMMUNITY_LIST_STANDARD:
647 if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
648 return 1;
649 break;
650 case COMMUNITY_LIST_EXPANDED:
651 case EXTCOMMUNITY_LIST_EXPANDED:
Christian Frankec0a613f2016-06-06 22:22:15 +0200652 if (entry->config && new->config
653 && strcmp (entry->config, new->config) == 0)
654 return 1;
655 if (!entry->config && !new->config)
paul8708b742003-06-07 02:03:11 +0000656 return 1;
657 break;
658 default:
659 break;
660 }
paul718e3742002-12-13 20:15:29 +0000661 }
662 return 0;
663}
David Lamparter6b0655a2014-06-04 06:53:35 +0200664
paul718e3742002-12-13 20:15:29 +0000665/* Set community-list. */
666int
667community_list_set (struct community_list_handler *ch,
paulfd79ac92004-10-13 05:06:08 +0000668 const char *name, const char *str, int direct, int style)
paul718e3742002-12-13 20:15:29 +0000669{
hassofee6e4e2005-02-02 16:29:31 +0000670 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000671 struct community_list *list;
hassofee6e4e2005-02-02 16:29:31 +0000672 struct community *com = NULL;
673 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000674
675 /* Get community list. */
hassofee6e4e2005-02-02 16:29:31 +0000676 list = community_list_get (ch, name, COMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000677
678 /* When community-list already has entry, new entry should have same
679 style. If you want to have mixed style community-list, you can
680 comment out this check. */
paul8708b742003-06-07 02:03:11 +0000681 if (!community_list_empty_p (list))
paul718e3742002-12-13 20:15:29 +0000682 {
683 struct community_entry *first;
684
685 first = list->head;
686
hassofee6e4e2005-02-02 16:29:31 +0000687 if (style != first->style)
688 {
689 return (first->style == COMMUNITY_LIST_STANDARD
690 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
691 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
692 }
paul718e3742002-12-13 20:15:29 +0000693 }
694
hassofee6e4e2005-02-02 16:29:31 +0000695 if (str)
paul718e3742002-12-13 20:15:29 +0000696 {
hassofee6e4e2005-02-02 16:29:31 +0000697 if (style == COMMUNITY_LIST_STANDARD)
698 com = community_str2com (str);
paul718e3742002-12-13 20:15:29 +0000699 else
hassofee6e4e2005-02-02 16:29:31 +0000700 regex = bgp_regcomp (str);
paul8708b742003-06-07 02:03:11 +0000701
hassofee6e4e2005-02-02 16:29:31 +0000702 if (! com && ! regex)
703 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000704 }
705
hassofee6e4e2005-02-02 16:29:31 +0000706 entry = community_entry_new ();
707 entry->direct = direct;
708 entry->style = style;
709 entry->any = (str ? 0 : 1);
710 entry->u.com = com;
711 entry->reg = regex;
712 entry->config = (regex ? XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
713
paul718e3742002-12-13 20:15:29 +0000714 /* Do not put duplicated community entry. */
715 if (community_list_dup_check (list, entry))
716 community_entry_free (entry);
717 else
718 community_list_entry_add (list, entry);
719
720 return 0;
721}
722
723/* Unset community-list. When str is NULL, delete all of
724 community-list entry belongs to the specified name. */
725int
726community_list_unset (struct community_list_handler *ch,
paulfd79ac92004-10-13 05:06:08 +0000727 const char *name, const char *str,
728 int direct, int style)
paul718e3742002-12-13 20:15:29 +0000729{
hassofee6e4e2005-02-02 16:29:31 +0000730 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000731 struct community_list *list;
hassofee6e4e2005-02-02 16:29:31 +0000732 struct community *com = NULL;
733 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000734
735 /* Lookup community list. */
hassofee6e4e2005-02-02 16:29:31 +0000736 list = community_list_lookup (ch, name, COMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000737 if (list == NULL)
738 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
739
740 /* Delete all of entry belongs to this community-list. */
paul8708b742003-06-07 02:03:11 +0000741 if (!str)
paul718e3742002-12-13 20:15:29 +0000742 {
743 community_list_delete (list);
744 return 0;
745 }
746
hassofee6e4e2005-02-02 16:29:31 +0000747 if (style == COMMUNITY_LIST_STANDARD)
748 com = community_str2com (str);
749 else
750 regex = bgp_regcomp (str);
paul718e3742002-12-13 20:15:29 +0000751
hassofee6e4e2005-02-02 16:29:31 +0000752 if (! com && ! regex)
753 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000754
hassofee6e4e2005-02-02 16:29:31 +0000755 if (com)
756 entry = community_list_entry_lookup (list, com, direct);
757 else
758 entry = community_list_entry_lookup (list, str, direct);
759
760 if (com)
761 community_free (com);
762 if (regex)
763 bgp_regex_free (regex);
paul718e3742002-12-13 20:15:29 +0000764
paul8708b742003-06-07 02:03:11 +0000765 if (!entry)
paul718e3742002-12-13 20:15:29 +0000766 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
767
768 community_list_entry_delete (list, entry, style);
769
770 return 0;
771}
772
773/* Set extcommunity-list. */
774int
775extcommunity_list_set (struct community_list_handler *ch,
paulfd79ac92004-10-13 05:06:08 +0000776 const char *name, const char *str,
777 int direct, int style)
paul718e3742002-12-13 20:15:29 +0000778{
hassofee6e4e2005-02-02 16:29:31 +0000779 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000780 struct community_list *list;
hassofee6e4e2005-02-02 16:29:31 +0000781 struct ecommunity *ecom = NULL;
782 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000783
784 entry = NULL;
785
786 /* Get community list. */
hassofee6e4e2005-02-02 16:29:31 +0000787 list = community_list_get (ch, name, EXTCOMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000788
789 /* When community-list already has entry, new entry should have same
790 style. If you want to have mixed style community-list, you can
791 comment out this check. */
paul8708b742003-06-07 02:03:11 +0000792 if (!community_list_empty_p (list))
paul718e3742002-12-13 20:15:29 +0000793 {
794 struct community_entry *first;
795
796 first = list->head;
797
hassofee6e4e2005-02-02 16:29:31 +0000798 if (style != first->style)
799 {
800 return (first->style == EXTCOMMUNITY_LIST_STANDARD
801 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
802 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
803 }
paul718e3742002-12-13 20:15:29 +0000804 }
805
hassofee6e4e2005-02-02 16:29:31 +0000806 if (str)
paul718e3742002-12-13 20:15:29 +0000807 {
hassofee6e4e2005-02-02 16:29:31 +0000808 if (style == EXTCOMMUNITY_LIST_STANDARD)
809 ecom = ecommunity_str2com (str, 0, 1);
paul718e3742002-12-13 20:15:29 +0000810 else
hassofee6e4e2005-02-02 16:29:31 +0000811 regex = bgp_regcomp (str);
812
813 if (! ecom && ! regex)
814 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000815 }
hassofee6e4e2005-02-02 16:29:31 +0000816
817 if (ecom)
818 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
819
820 entry = community_entry_new ();
821 entry->direct = direct;
822 entry->style = style;
823 entry->any = (str ? 0 : 1);
824 if (ecom)
825 entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
826 else if (regex)
827 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
paul718e3742002-12-13 20:15:29 +0000828 else
hassofee6e4e2005-02-02 16:29:31 +0000829 entry->config = NULL;
830 entry->u.ecom = ecom;
831 entry->reg = regex;
paul718e3742002-12-13 20:15:29 +0000832
833 /* Do not put duplicated community entry. */
834 if (community_list_dup_check (list, entry))
835 community_entry_free (entry);
836 else
837 community_list_entry_add (list, entry);
838
839 return 0;
840}
841
842/* Unset extcommunity-list. When str is NULL, delete all of
843 extcommunity-list entry belongs to the specified name. */
844int
845extcommunity_list_unset (struct community_list_handler *ch,
paulfd79ac92004-10-13 05:06:08 +0000846 const char *name, const char *str,
847 int direct, int style)
paul718e3742002-12-13 20:15:29 +0000848{
hassofee6e4e2005-02-02 16:29:31 +0000849 struct community_entry *entry = NULL;
paul718e3742002-12-13 20:15:29 +0000850 struct community_list *list;
851 struct ecommunity *ecom = NULL;
hassofee6e4e2005-02-02 16:29:31 +0000852 regex_t *regex = NULL;
paul718e3742002-12-13 20:15:29 +0000853
854 /* Lookup extcommunity list. */
hassofee6e4e2005-02-02 16:29:31 +0000855 list = community_list_lookup (ch, name, EXTCOMMUNITY_LIST_MASTER);
paul718e3742002-12-13 20:15:29 +0000856 if (list == NULL)
857 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
858
859 /* Delete all of entry belongs to this extcommunity-list. */
paul8708b742003-06-07 02:03:11 +0000860 if (!str)
paul718e3742002-12-13 20:15:29 +0000861 {
862 community_list_delete (list);
863 return 0;
864 }
865
hassofee6e4e2005-02-02 16:29:31 +0000866 if (style == EXTCOMMUNITY_LIST_STANDARD)
867 ecom = ecommunity_str2com (str, 0, 1);
868 else
869 regex = bgp_regcomp (str);
paul718e3742002-12-13 20:15:29 +0000870
hassofee6e4e2005-02-02 16:29:31 +0000871 if (! ecom && ! regex)
872 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
paul718e3742002-12-13 20:15:29 +0000873
hassofee6e4e2005-02-02 16:29:31 +0000874 if (ecom)
875 entry = community_list_entry_lookup (list, ecom, direct);
876 else
877 entry = community_list_entry_lookup (list, str, direct);
878
879 if (ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000880 ecommunity_free (&ecom);
hassofee6e4e2005-02-02 16:29:31 +0000881 if (regex)
882 bgp_regex_free (regex);
paul718e3742002-12-13 20:15:29 +0000883
paul8708b742003-06-07 02:03:11 +0000884 if (!entry)
paul718e3742002-12-13 20:15:29 +0000885 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
886
887 community_list_entry_delete (list, entry, style);
888
889 return 0;
890}
891
892/* Initializa community-list. Return community-list handler. */
893struct community_list_handler *
paul94f2b392005-06-28 12:44:16 +0000894community_list_init (void)
paul718e3742002-12-13 20:15:29 +0000895{
896 struct community_list_handler *ch;
897 ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER,
paul8708b742003-06-07 02:03:11 +0000898 sizeof (struct community_list_handler));
paul718e3742002-12-13 20:15:29 +0000899 return ch;
900}
901
902/* Terminate community-list. */
Chris Caputo228da422009-07-18 05:44:03 +0000903void
paul718e3742002-12-13 20:15:29 +0000904community_list_terminate (struct community_list_handler *ch)
905{
906 struct community_list_master *cm;
907 struct community_list *list;
908
909 cm = &ch->community_list;
910 while ((list = cm->num.head) != NULL)
911 community_list_delete (list);
912 while ((list = cm->str.head) != NULL)
913 community_list_delete (list);
914
915 cm = &ch->extcommunity_list;
916 while ((list = cm->num.head) != NULL)
917 community_list_delete (list);
918 while ((list = cm->str.head) != NULL)
919 community_list_delete (list);
920
921 XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch);
922}