Line data Source code
1 : /* BGP community-list and extcommunity-list.
2 : Copyright (C) 1999 Kunihiro Ishiguro
3 :
4 : This file is part of GNU Zebra.
5 :
6 : GNU Zebra is free software; you can redistribute it and/or modify it
7 : under the terms of the GNU General Public License as published by the
8 : Free Software Foundation; either version 2, or (at your option) any
9 : later version.
10 :
11 : GNU Zebra is distributed in the hope that it will be useful, but
12 : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with GNU Zebra; see the file COPYING. If not, write to the Free
18 : Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 : 02111-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. */
36 : struct community_list_master *
37 0 : community_list_master_lookup (struct community_list_handler *ch, int master)
38 : {
39 0 : if (ch)
40 0 : switch (master)
41 : {
42 : case COMMUNITY_LIST_MASTER:
43 0 : return &ch->community_list;
44 : case EXTCOMMUNITY_LIST_MASTER:
45 0 : return &ch->extcommunity_list;
46 : }
47 0 : return NULL;
48 : }
49 :
50 : /* Allocate a new community list entry. */
51 : static struct community_entry *
52 0 : community_entry_new (void)
53 : {
54 0 : return XCALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry));
55 : }
56 :
57 : /* Free community list entry. */
58 : static void
59 0 : community_entry_free (struct community_entry *entry)
60 : {
61 0 : switch (entry->style)
62 : {
63 : case COMMUNITY_LIST_STANDARD:
64 0 : if (entry->u.com)
65 0 : community_free (entry->u.com);
66 0 : break;
67 : case EXTCOMMUNITY_LIST_STANDARD:
68 : /* In case of standard extcommunity-list, configuration string
69 : is made by ecommunity_ecom2str(). */
70 0 : if (entry->config)
71 0 : XFREE (MTYPE_ECOMMUNITY_STR, entry->config);
72 0 : if (entry->u.ecom)
73 0 : ecommunity_free (&entry->u.ecom);
74 0 : break;
75 : case COMMUNITY_LIST_EXPANDED:
76 : case EXTCOMMUNITY_LIST_EXPANDED:
77 0 : if (entry->config)
78 0 : XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
79 0 : if (entry->reg)
80 0 : bgp_regex_free (entry->reg);
81 : default:
82 0 : break;
83 : }
84 0 : XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry);
85 0 : }
86 :
87 : /* Allocate a new community-list. */
88 : static struct community_list *
89 0 : community_list_new (void)
90 : {
91 0 : return XCALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list));
92 : }
93 :
94 : /* Free community-list. */
95 : static void
96 0 : community_list_free (struct community_list *list)
97 : {
98 0 : if (list->name)
99 0 : XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name);
100 0 : XFREE (MTYPE_COMMUNITY_LIST, list);
101 0 : }
102 :
103 : static struct community_list *
104 0 : community_list_insert (struct community_list_handler *ch,
105 : const char *name, int master)
106 : {
107 : size_t i;
108 : long number;
109 : struct community_list *new;
110 : struct community_list *point;
111 : struct community_list_list *list;
112 : struct community_list_master *cm;
113 :
114 : /* Lookup community-list master. */
115 0 : cm = community_list_master_lookup (ch, master);
116 0 : if (!cm)
117 0 : return NULL;
118 :
119 : /* Allocate new community_list and copy given name. */
120 0 : new = community_list_new ();
121 0 : new->name = XSTRDUP (MTYPE_COMMUNITY_LIST_NAME, name);
122 :
123 : /* If name is made by all digit character. We treat it as
124 : number. */
125 0 : for (number = 0, i = 0; i < strlen (name); i++)
126 : {
127 0 : if (isdigit ((int) name[i]))
128 0 : number = (number * 10) + (name[i] - '0');
129 : else
130 0 : break;
131 : }
132 :
133 : /* In case of name is all digit character */
134 0 : if (i == strlen (name))
135 : {
136 0 : new->sort = COMMUNITY_LIST_NUMBER;
137 :
138 : /* Set access_list to number list. */
139 0 : list = &cm->num;
140 :
141 0 : for (point = list->head; point; point = point->next)
142 0 : if (atol (point->name) >= number)
143 0 : break;
144 : }
145 : else
146 : {
147 0 : new->sort = COMMUNITY_LIST_STRING;
148 :
149 : /* Set access_list to string list. */
150 0 : list = &cm->str;
151 :
152 : /* Set point to insertion point. */
153 0 : for (point = list->head; point; point = point->next)
154 0 : if (strcmp (point->name, name) >= 0)
155 0 : break;
156 : }
157 :
158 : /* Link to upper list. */
159 0 : new->parent = list;
160 :
161 : /* In case of this is the first element of master. */
162 0 : if (list->head == NULL)
163 : {
164 0 : list->head = list->tail = new;
165 0 : return new;
166 : }
167 :
168 : /* In case of insertion is made at the tail of access_list. */
169 0 : if (point == NULL)
170 : {
171 0 : new->prev = list->tail;
172 0 : list->tail->next = new;
173 0 : list->tail = new;
174 0 : return new;
175 : }
176 :
177 : /* In case of insertion is made at the head of access_list. */
178 0 : if (point == list->head)
179 : {
180 0 : new->next = list->head;
181 0 : list->head->prev = new;
182 0 : list->head = new;
183 0 : return new;
184 : }
185 :
186 : /* Insertion is made at middle of the access_list. */
187 0 : new->next = point;
188 0 : new->prev = point->prev;
189 :
190 0 : if (point->prev)
191 0 : point->prev->next = new;
192 0 : point->prev = new;
193 :
194 0 : return new;
195 : }
196 :
197 : struct community_list *
198 0 : community_list_lookup (struct community_list_handler *ch,
199 : const char *name, int master)
200 : {
201 : struct community_list *list;
202 : struct community_list_master *cm;
203 :
204 0 : if (!name)
205 0 : return NULL;
206 :
207 0 : cm = community_list_master_lookup (ch, master);
208 0 : if (!cm)
209 0 : return NULL;
210 :
211 0 : for (list = cm->num.head; list; list = list->next)
212 0 : if (strcmp (list->name, name) == 0)
213 0 : return list;
214 0 : for (list = cm->str.head; list; list = list->next)
215 0 : if (strcmp (list->name, name) == 0)
216 0 : return list;
217 :
218 0 : return NULL;
219 : }
220 :
221 : static struct community_list *
222 0 : community_list_get (struct community_list_handler *ch,
223 : const char *name, int master)
224 : {
225 : struct community_list *list;
226 :
227 0 : list = community_list_lookup (ch, name, master);
228 0 : if (!list)
229 0 : list = community_list_insert (ch, name, master);
230 0 : return list;
231 : }
232 :
233 : static void
234 0 : community_list_delete (struct community_list *list)
235 : {
236 : struct community_list_list *clist;
237 : struct community_entry *entry, *next;
238 :
239 0 : for (entry = list->head; entry; entry = next)
240 : {
241 0 : next = entry->next;
242 0 : community_entry_free (entry);
243 : }
244 :
245 0 : clist = list->parent;
246 :
247 0 : if (list->next)
248 0 : list->next->prev = list->prev;
249 : else
250 0 : clist->tail = list->prev;
251 :
252 0 : if (list->prev)
253 0 : list->prev->next = list->next;
254 : else
255 0 : clist->head = list->next;
256 :
257 0 : community_list_free (list);
258 0 : }
259 :
260 : static int
261 0 : community_list_empty_p (struct community_list *list)
262 : {
263 0 : return (list->head == NULL && list->tail == NULL) ? 1 : 0;
264 : }
265 :
266 : /* Add community-list entry to the list. */
267 : static void
268 0 : community_list_entry_add (struct community_list *list,
269 : struct community_entry *entry)
270 : {
271 0 : entry->next = NULL;
272 0 : entry->prev = list->tail;
273 :
274 0 : if (list->tail)
275 0 : list->tail->next = entry;
276 : else
277 0 : list->head = entry;
278 0 : list->tail = entry;
279 0 : }
280 :
281 : /* Delete community-list entry from the list. */
282 : static void
283 0 : community_list_entry_delete (struct community_list *list,
284 : struct community_entry *entry, int style)
285 : {
286 0 : if (entry->next)
287 0 : entry->next->prev = entry->prev;
288 : else
289 0 : list->tail = entry->prev;
290 :
291 0 : if (entry->prev)
292 0 : entry->prev->next = entry->next;
293 : else
294 0 : list->head = entry->next;
295 :
296 0 : community_entry_free (entry);
297 :
298 0 : if (community_list_empty_p (list))
299 0 : community_list_delete (list);
300 0 : }
301 :
302 : /* Lookup community-list entry from the list. */
303 : static struct community_entry *
304 0 : community_list_entry_lookup (struct community_list *list, const void *arg,
305 : int direct)
306 : {
307 : struct community_entry *entry;
308 :
309 0 : for (entry = list->head; entry; entry = entry->next)
310 : {
311 0 : switch (entry->style)
312 : {
313 : case COMMUNITY_LIST_STANDARD:
314 0 : if (community_cmp (entry->u.com, arg))
315 0 : return entry;
316 0 : break;
317 : case EXTCOMMUNITY_LIST_STANDARD:
318 0 : if (ecommunity_cmp (entry->u.ecom, arg))
319 0 : return entry;
320 0 : break;
321 : case COMMUNITY_LIST_EXPANDED:
322 : case EXTCOMMUNITY_LIST_EXPANDED:
323 0 : if (strcmp (entry->config, arg) == 0)
324 0 : return entry;
325 0 : break;
326 : default:
327 0 : break;
328 : }
329 : }
330 0 : return NULL;
331 : }
332 :
333 : /* Internal function to perform regular expression match for community
334 : attribute. */
335 : static int
336 0 : community_regexp_match (struct community *com, regex_t * reg)
337 : {
338 : const char *str;
339 :
340 : /* When there is no communities attribute it is treated as empty
341 : string. */
342 0 : if (com == NULL || com->size == 0)
343 0 : str = "";
344 : else
345 0 : str = community_str (com);
346 :
347 : /* Regular expression match. */
348 0 : if (regexec (reg, str, 0, NULL, 0) == 0)
349 0 : return 1;
350 :
351 : /* No match. */
352 0 : return 0;
353 : }
354 :
355 : static int
356 0 : ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
357 : {
358 : const char *str;
359 :
360 : /* When there is no communities attribute it is treated as empty
361 : string. */
362 0 : if (ecom == NULL || ecom->size == 0)
363 0 : str = "";
364 : else
365 0 : str = ecommunity_str (ecom);
366 :
367 : /* Regular expression match. */
368 0 : if (regexec (reg, str, 0, NULL, 0) == 0)
369 0 : return 1;
370 :
371 : /* No match. */
372 0 : return 0;
373 : }
374 :
375 : /* Delete community attribute using regular expression match. Return
376 : modified communites attribute. */
377 : static struct community *
378 0 : community_regexp_delete (struct community *com, regex_t * reg)
379 : {
380 : int i;
381 : u_int32_t comval;
382 : /* Maximum is "65535:65535" + '\0'. */
383 : char c[12];
384 : const char *str;
385 :
386 0 : if (!com)
387 0 : return NULL;
388 :
389 0 : i = 0;
390 0 : while (i < com->size)
391 : {
392 0 : memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
393 0 : comval = ntohl (comval);
394 :
395 0 : switch (comval)
396 : {
397 : case COMMUNITY_INTERNET:
398 0 : str = "internet";
399 0 : break;
400 : case COMMUNITY_NO_EXPORT:
401 0 : str = "no-export";
402 0 : break;
403 : case COMMUNITY_NO_ADVERTISE:
404 0 : str = "no-advertise";
405 0 : break;
406 : case COMMUNITY_LOCAL_AS:
407 0 : str = "local-AS";
408 0 : break;
409 : default:
410 0 : sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF);
411 0 : str = c;
412 0 : break;
413 : }
414 :
415 0 : if (regexec (reg, str, 0, NULL, 0) == 0)
416 0 : community_del_val (com, com_nthval (com, i));
417 : else
418 0 : i++;
419 : }
420 0 : return com;
421 : }
422 :
423 : /* When given community attribute matches to the community-list return
424 : 1 else return 0. */
425 : int
426 0 : community_list_match (struct community *com, struct community_list *list)
427 : {
428 : struct community_entry *entry;
429 :
430 0 : for (entry = list->head; entry; entry = entry->next)
431 : {
432 0 : if (entry->any)
433 0 : return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
434 :
435 0 : if (entry->style == COMMUNITY_LIST_STANDARD)
436 : {
437 0 : if (community_include (entry->u.com, COMMUNITY_INTERNET))
438 0 : return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
439 :
440 0 : if (community_match (com, entry->u.com))
441 0 : return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
442 : }
443 0 : else if (entry->style == COMMUNITY_LIST_EXPANDED)
444 : {
445 0 : if (community_regexp_match (com, entry->reg))
446 0 : return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
447 : }
448 : }
449 0 : return 0;
450 : }
451 :
452 : int
453 0 : ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
454 : {
455 : struct community_entry *entry;
456 :
457 0 : for (entry = list->head; entry; entry = entry->next)
458 : {
459 0 : if (entry->any)
460 0 : return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
461 :
462 0 : if (entry->style == EXTCOMMUNITY_LIST_STANDARD)
463 : {
464 0 : if (ecommunity_match (ecom, entry->u.ecom))
465 0 : return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
466 : }
467 0 : else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED)
468 : {
469 0 : if (ecommunity_regexp_match (ecom, entry->reg))
470 0 : return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
471 : }
472 : }
473 0 : return 0;
474 : }
475 :
476 : /* Perform exact matching. In case of expanded community-list, do
477 : same thing as community_list_match(). */
478 : int
479 0 : community_list_exact_match (struct community *com,
480 : struct community_list *list)
481 : {
482 : struct community_entry *entry;
483 :
484 0 : for (entry = list->head; entry; entry = entry->next)
485 : {
486 0 : if (entry->any)
487 0 : return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
488 :
489 0 : if (entry->style == COMMUNITY_LIST_STANDARD)
490 : {
491 0 : if (community_include (entry->u.com, COMMUNITY_INTERNET))
492 0 : return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
493 :
494 0 : if (community_cmp (com, entry->u.com))
495 0 : return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
496 : }
497 0 : else if (entry->style == COMMUNITY_LIST_EXPANDED)
498 : {
499 0 : if (community_regexp_match (com, entry->reg))
500 0 : return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
501 : }
502 : }
503 0 : return 0;
504 : }
505 :
506 : /* Delete all permitted communities in the list from com. */
507 : struct community *
508 0 : community_list_match_delete (struct community *com,
509 : struct community_list *list)
510 : {
511 : struct community_entry *entry;
512 :
513 0 : for (entry = list->head; entry; entry = entry->next)
514 : {
515 0 : if (entry->any)
516 : {
517 0 : if (entry->direct == COMMUNITY_PERMIT)
518 : {
519 : /* This is a tricky part. Currently only
520 : * route_set_community_delete() uses this function. In the
521 : * function com->size is zero, it free the community
522 : * structure.
523 : */
524 0 : com->size = 0;
525 : }
526 0 : return com;
527 : }
528 :
529 0 : if ((entry->style == COMMUNITY_LIST_STANDARD)
530 0 : && (community_include (entry->u.com, COMMUNITY_INTERNET)
531 0 : || community_match (com, entry->u.com) ))
532 : {
533 0 : if (entry->direct == COMMUNITY_PERMIT)
534 0 : community_delete (com, entry->u.com);
535 : else
536 0 : break;
537 : }
538 0 : else if ((entry->style == COMMUNITY_LIST_EXPANDED)
539 0 : && community_regexp_match (com, entry->reg))
540 : {
541 0 : if (entry->direct == COMMUNITY_PERMIT)
542 0 : community_regexp_delete (com, entry->reg);
543 : else
544 0 : break;
545 : }
546 : }
547 0 : return com;
548 : }
549 :
550 : /* To avoid duplicated entry in the community-list, this function
551 : compares specified entry to existing entry. */
552 : static int
553 0 : community_list_dup_check (struct community_list *list,
554 : struct community_entry *new)
555 : {
556 : struct community_entry *entry;
557 :
558 0 : for (entry = list->head; entry; entry = entry->next)
559 : {
560 0 : if (entry->style != new->style)
561 0 : continue;
562 :
563 0 : if (entry->direct != new->direct)
564 0 : continue;
565 :
566 0 : if (entry->any != new->any)
567 0 : continue;
568 :
569 0 : if (entry->any)
570 0 : return 1;
571 :
572 0 : switch (entry->style)
573 : {
574 : case COMMUNITY_LIST_STANDARD:
575 0 : if (community_cmp (entry->u.com, new->u.com))
576 0 : return 1;
577 0 : break;
578 : case EXTCOMMUNITY_LIST_STANDARD:
579 0 : if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
580 0 : return 1;
581 0 : break;
582 : case COMMUNITY_LIST_EXPANDED:
583 : case EXTCOMMUNITY_LIST_EXPANDED:
584 0 : if (strcmp (entry->config, new->config) == 0)
585 0 : return 1;
586 0 : break;
587 : default:
588 0 : break;
589 : }
590 : }
591 0 : return 0;
592 : }
593 :
594 : /* Set community-list. */
595 : int
596 0 : community_list_set (struct community_list_handler *ch,
597 : const char *name, const char *str, int direct, int style)
598 : {
599 0 : struct community_entry *entry = NULL;
600 : struct community_list *list;
601 0 : struct community *com = NULL;
602 0 : regex_t *regex = NULL;
603 :
604 : /* Get community list. */
605 0 : list = community_list_get (ch, name, COMMUNITY_LIST_MASTER);
606 :
607 : /* When community-list already has entry, new entry should have same
608 : style. If you want to have mixed style community-list, you can
609 : comment out this check. */
610 0 : if (!community_list_empty_p (list))
611 : {
612 : struct community_entry *first;
613 :
614 0 : first = list->head;
615 :
616 0 : if (style != first->style)
617 : {
618 0 : return (first->style == COMMUNITY_LIST_STANDARD
619 : ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
620 0 : : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
621 : }
622 : }
623 :
624 0 : if (str)
625 : {
626 0 : if (style == COMMUNITY_LIST_STANDARD)
627 0 : com = community_str2com (str);
628 : else
629 0 : regex = bgp_regcomp (str);
630 :
631 0 : if (! com && ! regex)
632 0 : return COMMUNITY_LIST_ERR_MALFORMED_VAL;
633 : }
634 :
635 0 : entry = community_entry_new ();
636 0 : entry->direct = direct;
637 0 : entry->style = style;
638 0 : entry->any = (str ? 0 : 1);
639 0 : entry->u.com = com;
640 0 : entry->reg = regex;
641 0 : entry->config = (regex ? XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
642 :
643 : /* Do not put duplicated community entry. */
644 0 : if (community_list_dup_check (list, entry))
645 0 : community_entry_free (entry);
646 : else
647 0 : community_list_entry_add (list, entry);
648 :
649 0 : return 0;
650 : }
651 :
652 : /* Unset community-list. When str is NULL, delete all of
653 : community-list entry belongs to the specified name. */
654 : int
655 0 : community_list_unset (struct community_list_handler *ch,
656 : const char *name, const char *str,
657 : int direct, int style)
658 : {
659 0 : struct community_entry *entry = NULL;
660 : struct community_list *list;
661 0 : struct community *com = NULL;
662 0 : regex_t *regex = NULL;
663 :
664 : /* Lookup community list. */
665 0 : list = community_list_lookup (ch, name, COMMUNITY_LIST_MASTER);
666 0 : if (list == NULL)
667 0 : return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
668 :
669 : /* Delete all of entry belongs to this community-list. */
670 0 : if (!str)
671 : {
672 0 : community_list_delete (list);
673 0 : return 0;
674 : }
675 :
676 0 : if (style == COMMUNITY_LIST_STANDARD)
677 0 : com = community_str2com (str);
678 : else
679 0 : regex = bgp_regcomp (str);
680 :
681 0 : if (! com && ! regex)
682 0 : return COMMUNITY_LIST_ERR_MALFORMED_VAL;
683 :
684 0 : if (com)
685 0 : entry = community_list_entry_lookup (list, com, direct);
686 : else
687 0 : entry = community_list_entry_lookup (list, str, direct);
688 :
689 0 : if (com)
690 0 : community_free (com);
691 0 : if (regex)
692 0 : bgp_regex_free (regex);
693 :
694 0 : if (!entry)
695 0 : return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
696 :
697 0 : community_list_entry_delete (list, entry, style);
698 :
699 0 : return 0;
700 : }
701 :
702 : /* Set extcommunity-list. */
703 : int
704 0 : extcommunity_list_set (struct community_list_handler *ch,
705 : const char *name, const char *str,
706 : int direct, int style)
707 : {
708 0 : struct community_entry *entry = NULL;
709 : struct community_list *list;
710 0 : struct ecommunity *ecom = NULL;
711 0 : regex_t *regex = NULL;
712 :
713 0 : entry = NULL;
714 :
715 : /* Get community list. */
716 0 : list = community_list_get (ch, name, EXTCOMMUNITY_LIST_MASTER);
717 :
718 : /* When community-list already has entry, new entry should have same
719 : style. If you want to have mixed style community-list, you can
720 : comment out this check. */
721 0 : if (!community_list_empty_p (list))
722 : {
723 : struct community_entry *first;
724 :
725 0 : first = list->head;
726 :
727 0 : if (style != first->style)
728 : {
729 0 : return (first->style == EXTCOMMUNITY_LIST_STANDARD
730 : ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
731 0 : : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
732 : }
733 : }
734 :
735 0 : if (str)
736 : {
737 0 : if (style == EXTCOMMUNITY_LIST_STANDARD)
738 0 : ecom = ecommunity_str2com (str, 0, 1);
739 : else
740 0 : regex = bgp_regcomp (str);
741 :
742 0 : if (! ecom && ! regex)
743 0 : return COMMUNITY_LIST_ERR_MALFORMED_VAL;
744 : }
745 :
746 0 : if (ecom)
747 0 : ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
748 :
749 0 : entry = community_entry_new ();
750 0 : entry->direct = direct;
751 0 : entry->style = style;
752 0 : entry->any = (str ? 0 : 1);
753 0 : if (ecom)
754 0 : entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST);
755 0 : else if (regex)
756 0 : entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
757 : else
758 0 : entry->config = NULL;
759 0 : entry->u.ecom = ecom;
760 0 : entry->reg = regex;
761 :
762 : /* Do not put duplicated community entry. */
763 0 : if (community_list_dup_check (list, entry))
764 0 : community_entry_free (entry);
765 : else
766 0 : community_list_entry_add (list, entry);
767 :
768 0 : return 0;
769 : }
770 :
771 : /* Unset extcommunity-list. When str is NULL, delete all of
772 : extcommunity-list entry belongs to the specified name. */
773 : int
774 0 : extcommunity_list_unset (struct community_list_handler *ch,
775 : const char *name, const char *str,
776 : int direct, int style)
777 : {
778 0 : struct community_entry *entry = NULL;
779 : struct community_list *list;
780 0 : struct ecommunity *ecom = NULL;
781 0 : regex_t *regex = NULL;
782 :
783 : /* Lookup extcommunity list. */
784 0 : list = community_list_lookup (ch, name, EXTCOMMUNITY_LIST_MASTER);
785 0 : if (list == NULL)
786 0 : return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
787 :
788 : /* Delete all of entry belongs to this extcommunity-list. */
789 0 : if (!str)
790 : {
791 0 : community_list_delete (list);
792 0 : return 0;
793 : }
794 :
795 0 : if (style == EXTCOMMUNITY_LIST_STANDARD)
796 0 : ecom = ecommunity_str2com (str, 0, 1);
797 : else
798 0 : regex = bgp_regcomp (str);
799 :
800 0 : if (! ecom && ! regex)
801 0 : return COMMUNITY_LIST_ERR_MALFORMED_VAL;
802 :
803 0 : if (ecom)
804 0 : entry = community_list_entry_lookup (list, ecom, direct);
805 : else
806 0 : entry = community_list_entry_lookup (list, str, direct);
807 :
808 0 : if (ecom)
809 0 : ecommunity_free (&ecom);
810 0 : if (regex)
811 0 : bgp_regex_free (regex);
812 :
813 0 : if (!entry)
814 0 : return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
815 :
816 0 : community_list_entry_delete (list, entry, style);
817 :
818 0 : return 0;
819 : }
820 :
821 : /* Initializa community-list. Return community-list handler. */
822 : struct community_list_handler *
823 0 : community_list_init (void)
824 : {
825 : struct community_list_handler *ch;
826 0 : ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER,
827 : sizeof (struct community_list_handler));
828 0 : return ch;
829 : }
830 :
831 : /* Terminate community-list. */
832 : void
833 0 : community_list_terminate (struct community_list_handler *ch)
834 : {
835 : struct community_list_master *cm;
836 : struct community_list *list;
837 :
838 0 : cm = &ch->community_list;
839 0 : while ((list = cm->num.head) != NULL)
840 0 : community_list_delete (list);
841 0 : while ((list = cm->str.head) != NULL)
842 0 : community_list_delete (list);
843 :
844 0 : cm = &ch->extcommunity_list;
845 0 : while ((list = cm->num.head) != NULL)
846 0 : community_list_delete (list);
847 0 : while ((list = cm->str.head) != NULL)
848 0 : community_list_delete (list);
849 :
850 0 : XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch);
851 0 : }
|