]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_clist.c
bgpd: Fixed typo in comment
[mirror_frr.git] / bgpd / bgp_clist.c
CommitLineData
718e3744 1/* BGP community-list and extcommunity-list.
896014f4
DL
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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
718e3744 20
21#include <zebra.h>
22
23#include "command.h"
24#include "prefix.h"
25#include "memory.h"
3f9c7369 26#include "queue.h"
039f3a34 27#include "filter.h"
718e3744 28
29#include "bgpd/bgpd.h"
30#include "bgpd/bgp_community.h"
31#include "bgpd/bgp_ecommunity.h"
57d187bc 32#include "bgpd/bgp_lcommunity.h"
718e3744 33#include "bgpd/bgp_aspath.h"
34#include "bgpd/bgp_regex.h"
35#include "bgpd/bgp_clist.h"
6b0655a2 36
718e3744 37/* Lookup master structure for community-list or
38 extcommunity-list. */
39struct community_list_master *
d62a17ae 40community_list_master_lookup(struct community_list_handler *ch, int master)
718e3744 41{
d62a17ae 42 if (ch)
43 switch (master) {
44 case COMMUNITY_LIST_MASTER:
45 return &ch->community_list;
46 case EXTCOMMUNITY_LIST_MASTER:
47 return &ch->extcommunity_list;
48 case LARGE_COMMUNITY_LIST_MASTER:
49 return &ch->lcommunity_list;
50 }
51 return NULL;
718e3744 52}
53
54/* Allocate a new community list entry. */
d62a17ae 55static struct community_entry *community_entry_new(void)
718e3744 56{
d62a17ae 57 return XCALLOC(MTYPE_COMMUNITY_LIST_ENTRY,
58 sizeof(struct community_entry));
718e3744 59}
60
61/* Free community list entry. */
d62a17ae 62static void community_entry_free(struct community_entry *entry)
718e3744 63{
d62a17ae 64 switch (entry->style) {
65 case COMMUNITY_LIST_STANDARD:
66 if (entry->u.com)
67 community_free(entry->u.com);
68 break;
69 case LARGE_COMMUNITY_LIST_STANDARD:
70 if (entry->u.lcom)
71 lcommunity_free(&entry->u.lcom);
72 break;
73 case EXTCOMMUNITY_LIST_STANDARD:
74 /* In case of standard extcommunity-list, configuration string
75 is made by ecommunity_ecom2str(). */
76 if (entry->config)
77 XFREE(MTYPE_ECOMMUNITY_STR, entry->config);
78 if (entry->u.ecom)
79 ecommunity_free(&entry->u.ecom);
80 break;
81 case COMMUNITY_LIST_EXPANDED:
82 case EXTCOMMUNITY_LIST_EXPANDED:
83 case LARGE_COMMUNITY_LIST_EXPANDED:
84 if (entry->config)
85 XFREE(MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
86 if (entry->reg)
87 bgp_regex_free(entry->reg);
88 default:
89 break;
90 }
91 XFREE(MTYPE_COMMUNITY_LIST_ENTRY, entry);
718e3744 92}
93
94/* Allocate a new community-list. */
d62a17ae 95static struct community_list *community_list_new(void)
718e3744 96{
d62a17ae 97 return XCALLOC(MTYPE_COMMUNITY_LIST, sizeof(struct community_list));
718e3744 98}
99
100/* Free community-list. */
d62a17ae 101static void community_list_free(struct community_list *list)
718e3744 102{
d62a17ae 103 if (list->name)
104 XFREE(MTYPE_COMMUNITY_LIST_NAME, list->name);
105 XFREE(MTYPE_COMMUNITY_LIST, list);
718e3744 106}
107
94f2b392 108static struct community_list *
d62a17ae 109community_list_insert(struct community_list_handler *ch, const char *name,
110 int master)
718e3744 111{
d62a17ae 112 size_t i;
113 long number;
114 struct community_list *new;
115 struct community_list *point;
116 struct community_list_list *list;
117 struct community_list_master *cm;
118
119 /* Lookup community-list master. */
120 cm = community_list_master_lookup(ch, master);
121 if (!cm)
122 return NULL;
123
124 /* Allocate new community_list and copy given name. */
125 new = community_list_new();
126 new->name = XSTRDUP(MTYPE_COMMUNITY_LIST_NAME, name);
127
128 /* If name is made by all digit character. We treat it as
129 number. */
130 for (number = 0, i = 0; i < strlen(name); i++) {
131 if (isdigit((int)name[i]))
132 number = (number * 10) + (name[i] - '0');
133 else
134 break;
135 }
718e3744 136
d62a17ae 137 /* In case of name is all digit character */
138 if (i == strlen(name)) {
139 new->sort = COMMUNITY_LIST_NUMBER;
718e3744 140
d62a17ae 141 /* Set access_list to number list. */
142 list = &cm->num;
718e3744 143
d62a17ae 144 for (point = list->head; point; point = point->next)
145 if (atol(point->name) >= number)
146 break;
147 } else {
148 new->sort = COMMUNITY_LIST_STRING;
718e3744 149
d62a17ae 150 /* Set access_list to string list. */
151 list = &cm->str;
718e3744 152
d62a17ae 153 /* Set point to insertion point. */
154 for (point = list->head; point; point = point->next)
155 if (strcmp(point->name, name) >= 0)
156 break;
157 }
718e3744 158
d62a17ae 159 /* Link to upper list. */
160 new->parent = list;
718e3744 161
d62a17ae 162 /* In case of this is the first element of master. */
163 if (list->head == NULL) {
164 list->head = list->tail = new;
165 return new;
166 }
718e3744 167
d62a17ae 168 /* In case of insertion is made at the tail of access_list. */
169 if (point == NULL) {
170 new->prev = list->tail;
171 list->tail->next = new;
172 list->tail = new;
173 return new;
174 }
718e3744 175
d62a17ae 176 /* In case of insertion is made at the head of access_list. */
177 if (point == list->head) {
178 new->next = list->head;
179 list->head->prev = new;
180 list->head = new;
181 return new;
182 }
718e3744 183
d62a17ae 184 /* Insertion is made at middle of the access_list. */
185 new->next = point;
186 new->prev = point->prev;
718e3744 187
d62a17ae 188 if (point->prev)
189 point->prev->next = new;
190 point->prev = new;
718e3744 191
d62a17ae 192 return new;
718e3744 193}
194
d62a17ae 195struct community_list *community_list_lookup(struct community_list_handler *ch,
196 const char *name, int master)
718e3744 197{
d62a17ae 198 struct community_list *list;
199 struct community_list_master *cm;
718e3744 200
d62a17ae 201 if (!name)
202 return NULL;
718e3744 203
d62a17ae 204 cm = community_list_master_lookup(ch, master);
205 if (!cm)
206 return NULL;
718e3744 207
d62a17ae 208 for (list = cm->num.head; list; list = list->next)
209 if (strcmp(list->name, name) == 0)
210 return list;
211 for (list = cm->str.head; list; list = list->next)
212 if (strcmp(list->name, name) == 0)
213 return list;
718e3744 214
d62a17ae 215 return NULL;
718e3744 216}
217
94f2b392 218static struct community_list *
d62a17ae 219community_list_get(struct community_list_handler *ch, const char *name,
220 int master)
718e3744 221{
d62a17ae 222 struct community_list *list;
718e3744 223
d62a17ae 224 list = community_list_lookup(ch, name, master);
225 if (!list)
226 list = community_list_insert(ch, name, master);
227 return list;
718e3744 228}
229
d62a17ae 230static void community_list_delete(struct community_list *list)
718e3744 231{
d62a17ae 232 struct community_list_list *clist;
233 struct community_entry *entry, *next;
718e3744 234
d62a17ae 235 for (entry = list->head; entry; entry = next) {
236 next = entry->next;
237 community_entry_free(entry);
238 }
718e3744 239
d62a17ae 240 clist = list->parent;
718e3744 241
d62a17ae 242 if (list->next)
243 list->next->prev = list->prev;
244 else
245 clist->tail = list->prev;
718e3744 246
d62a17ae 247 if (list->prev)
248 list->prev->next = list->next;
249 else
250 clist->head = list->next;
718e3744 251
d62a17ae 252 community_list_free(list);
718e3744 253}
254
d62a17ae 255static int community_list_empty_p(struct community_list *list)
718e3744 256{
d62a17ae 257 return (list->head == NULL && list->tail == NULL) ? 1 : 0;
718e3744 258}
6b0655a2 259
718e3744 260/* Add community-list entry to the list. */
d62a17ae 261static void community_list_entry_add(struct community_list *list,
262 struct community_entry *entry)
718e3744 263{
d62a17ae 264 entry->next = NULL;
265 entry->prev = list->tail;
266
267 if (list->tail)
268 list->tail->next = entry;
269 else
270 list->head = entry;
271 list->tail = entry;
718e3744 272}
273
274/* Delete community-list entry from the list. */
d62a17ae 275static void community_list_entry_delete(struct community_list *list,
276 struct community_entry *entry,
277 int style)
718e3744 278{
d62a17ae 279 if (entry->next)
280 entry->next->prev = entry->prev;
281 else
282 list->tail = entry->prev;
718e3744 283
d62a17ae 284 if (entry->prev)
285 entry->prev->next = entry->next;
286 else
287 list->head = entry->next;
718e3744 288
d62a17ae 289 community_entry_free(entry);
718e3744 290
d62a17ae 291 if (community_list_empty_p(list))
292 community_list_delete(list);
718e3744 293}
294
295/* Lookup community-list entry from the list. */
296static struct community_entry *
d62a17ae 297community_list_entry_lookup(struct community_list *list, const void *arg,
298 int direct)
718e3744 299{
d62a17ae 300 struct community_entry *entry;
301
302 for (entry = list->head; entry; entry = entry->next) {
303 switch (entry->style) {
304 case COMMUNITY_LIST_STANDARD:
305 if (entry->direct == direct
306 && community_cmp(entry->u.com, arg))
307 return entry;
308 break;
309 case EXTCOMMUNITY_LIST_STANDARD:
310 if (entry->direct == direct
311 && ecommunity_cmp(entry->u.ecom, arg))
312 return entry;
313 break;
314 case LARGE_COMMUNITY_LIST_STANDARD:
315 if (entry->direct == direct
316 && lcommunity_cmp(entry->u.lcom, arg))
317 return entry;
318 break;
319 case COMMUNITY_LIST_EXPANDED:
320 case EXTCOMMUNITY_LIST_EXPANDED:
321 case LARGE_COMMUNITY_LIST_EXPANDED:
322 if (entry->direct == direct
323 && strcmp(entry->config, arg) == 0)
324 return entry;
325 break;
326 default:
327 break;
328 }
329 }
330 return NULL;
718e3744 331}
6b0655a2 332
d62a17ae 333static char *community_str_get(struct community *com, int i)
5cbea288 334{
d62a17ae 335 int len;
336 u_int32_t comval;
337 u_int16_t as;
338 u_int16_t val;
339 char *str;
340 char *pnt;
341
342 memcpy(&comval, com_nthval(com, i), sizeof(u_int32_t));
343 comval = ntohl(comval);
344
345 switch (comval) {
346 case COMMUNITY_INTERNET:
347 len = strlen(" internet");
348 break;
349 case COMMUNITY_NO_EXPORT:
350 len = strlen(" no-export");
351 break;
352 case COMMUNITY_NO_ADVERTISE:
353 len = strlen(" no-advertise");
354 break;
355 case COMMUNITY_LOCAL_AS:
356 len = strlen(" local-AS");
357 break;
358 default:
359 len = strlen(" 65536:65535");
360 break;
361 }
5cbea288 362
d62a17ae 363 /* Allocate memory. */
364 str = pnt = XMALLOC(MTYPE_COMMUNITY_STR, len);
365
366 switch (comval) {
367 case COMMUNITY_INTERNET:
368 strcpy(pnt, "internet");
369 pnt += strlen("internet");
370 break;
371 case COMMUNITY_NO_EXPORT:
372 strcpy(pnt, "no-export");
373 pnt += strlen("no-export");
374 break;
375 case COMMUNITY_NO_ADVERTISE:
376 strcpy(pnt, "no-advertise");
377 pnt += strlen("no-advertise");
378 break;
379 case COMMUNITY_LOCAL_AS:
380 strcpy(pnt, "local-AS");
381 pnt += strlen("local-AS");
382 break;
383 default:
384 as = (comval >> 16) & 0xFFFF;
385 val = comval & 0xFFFF;
386 sprintf(pnt, "%u:%d", as, val);
387 pnt += strlen(pnt);
388 break;
389 }
5cbea288 390
d62a17ae 391 *pnt = '\0';
5cbea288 392
d62a17ae 393 return str;
5cbea288
DS
394}
395
396/* Internal function to perform regular expression match for
2acb4ac2 397 * a single community. */
d62a17ae 398static int community_regexp_include(regex_t *reg, struct community *com, int i)
5cbea288 399{
d62a17ae 400 char *str;
401 int rv;
5cbea288 402
d62a17ae 403 /* When there is no communities attribute it is treated as empty string.
404 */
405 if (com == NULL || com->size == 0)
406 str = XSTRDUP(MTYPE_COMMUNITY_STR, "");
407 else
408 str = community_str_get(com, i);
5cbea288 409
d62a17ae 410 /* Regular expression match. */
411 rv = regexec(reg, str, 0, NULL, 0);
b84ee83b 412
d62a17ae 413 XFREE(MTYPE_COMMUNITY_STR, str);
b84ee83b 414
d62a17ae 415 if (rv == 0)
416 return 1;
5cbea288 417
d62a17ae 418 /* No match. */
419 return 0;
5cbea288
DS
420}
421
718e3744 422/* Internal function to perform regular expression match for community
423 attribute. */
d62a17ae 424static int community_regexp_match(struct community *com, regex_t *reg)
718e3744 425{
d62a17ae 426 const char *str;
718e3744 427
d62a17ae 428 /* When there is no communities attribute it is treated as empty
429 string. */
430 if (com == NULL || com->size == 0)
431 str = "";
432 else
433 str = community_str(com);
718e3744 434
d62a17ae 435 /* Regular expression match. */
436 if (regexec(reg, str, 0, NULL, 0) == 0)
437 return 1;
718e3744 438
d62a17ae 439 /* No match. */
440 return 0;
718e3744 441}
442
d62a17ae 443static char *lcommunity_str_get(struct lcommunity *lcom, int i)
57d187bc 444{
d62a17ae 445 struct lcommunity_val lcomval;
446 u_int32_t globaladmin;
447 u_int32_t localdata1;
448 u_int32_t localdata2;
449 char *str;
450 u_char *ptr;
451 char *pnt;
452
453 ptr = lcom->val;
454 ptr += (i * LCOMMUNITY_SIZE);
455
456 memcpy(&lcomval, ptr, LCOMMUNITY_SIZE);
457
458 /* Allocate memory. 48 bytes taken off bgp_lcommunity.c */
459 str = pnt = XMALLOC(MTYPE_LCOMMUNITY_STR, 48);
460
461 ptr = (u_char *)lcomval.val;
462 globaladmin = (*ptr++ << 24);
463 globaladmin |= (*ptr++ << 16);
464 globaladmin |= (*ptr++ << 8);
465 globaladmin |= (*ptr++);
466
467 localdata1 = (*ptr++ << 24);
468 localdata1 |= (*ptr++ << 16);
469 localdata1 |= (*ptr++ << 8);
470 localdata1 |= (*ptr++);
471
472 localdata2 = (*ptr++ << 24);
473 localdata2 |= (*ptr++ << 16);
474 localdata2 |= (*ptr++ << 8);
475 localdata2 |= (*ptr++);
476
477 sprintf(pnt, "%u:%u:%u", globaladmin, localdata1, localdata2);
478 pnt += strlen(pnt);
479 *pnt = '\0';
480
481 return str;
57d187bc
JS
482}
483
484/* Internal function to perform regular expression match for
2acb4ac2 485 * a single community. */
d62a17ae 486static int lcommunity_regexp_include(regex_t *reg, struct lcommunity *lcom,
487 int i)
57d187bc 488{
d62a17ae 489 char *str;
490
491 /* When there is no communities attribute it is treated as empty string.
492 */
493 if (lcom == NULL || lcom->size == 0)
494 str = XSTRDUP(MTYPE_LCOMMUNITY_STR, "");
495 else
496 str = lcommunity_str_get(lcom, i);
497
498 /* Regular expression match. */
499 if (regexec(reg, str, 0, NULL, 0) == 0) {
500 XFREE(MTYPE_LCOMMUNITY_STR, str);
501 return 1;
502 }
57d187bc 503
d62a17ae 504 XFREE(MTYPE_LCOMMUNITY_STR, str);
505 /* No match. */
506 return 0;
57d187bc
JS
507}
508
d62a17ae 509static int lcommunity_regexp_match(struct lcommunity *com, regex_t *reg)
57d187bc 510{
d62a17ae 511 const char *str;
57d187bc 512
d62a17ae 513 /* When there is no communities attribute it is treated as empty
514 string. */
515 if (com == NULL || com->size == 0)
516 str = "";
517 else
518 str = lcommunity_str(com);
57d187bc 519
d62a17ae 520 /* Regular expression match. */
521 if (regexec(reg, str, 0, NULL, 0) == 0)
522 return 1;
57d187bc 523
d62a17ae 524 /* No match. */
525 return 0;
57d187bc
JS
526}
527
528
d62a17ae 529static int ecommunity_regexp_match(struct ecommunity *ecom, regex_t *reg)
8708b74f 530{
d62a17ae 531 const char *str;
8708b74f 532
d62a17ae 533 /* When there is no communities attribute it is treated as empty
534 string. */
535 if (ecom == NULL || ecom->size == 0)
536 str = "";
537 else
538 str = ecommunity_str(ecom);
8708b74f 539
d62a17ae 540 /* Regular expression match. */
541 if (regexec(reg, str, 0, NULL, 0) == 0)
542 return 1;
8708b74f 543
d62a17ae 544 /* No match. */
545 return 0;
8708b74f 546}
547
ffd0c037 548#if 0
718e3744 549/* Delete community attribute using regular expression match. Return
550 modified communites attribute. */
551static struct community *
8708b74f 552community_regexp_delete (struct community *com, regex_t * reg)
718e3744 553{
554 int i;
555 u_int32_t comval;
556 /* Maximum is "65535:65535" + '\0'. */
557 char c[12];
fd79ac91 558 const char *str;
718e3744 559
8708b74f 560 if (!com)
718e3744 561 return NULL;
562
563 i = 0;
564 while (i < com->size)
565 {
566 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
567 comval = ntohl (comval);
568
569 switch (comval)
8708b74f 570 {
571 case COMMUNITY_INTERNET:
572 str = "internet";
573 break;
574 case COMMUNITY_NO_EXPORT:
575 str = "no-export";
576 break;
577 case COMMUNITY_NO_ADVERTISE:
578 str = "no-advertise";
579 break;
580 case COMMUNITY_LOCAL_AS:
581 str = "local-AS";
582 break;
583 default:
584 sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF);
585 str = c;
586 break;
587 }
718e3744 588
589 if (regexec (reg, str, 0, NULL, 0) == 0)
8708b74f 590 community_del_val (com, com_nthval (com, i));
718e3744 591 else
8708b74f 592 i++;
718e3744 593 }
594 return com;
595}
ffd0c037 596#endif
718e3744 597
598/* When given community attribute matches to the community-list return
599 1 else return 0. */
d62a17ae 600int community_list_match(struct community *com, struct community_list *list)
718e3744 601{
d62a17ae 602 struct community_entry *entry;
603
604 for (entry = list->head; entry; entry = entry->next) {
605 if (entry->any)
606 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
607
608 if (entry->style == COMMUNITY_LIST_STANDARD) {
609 if (community_include(entry->u.com, COMMUNITY_INTERNET))
610 return entry->direct == COMMUNITY_PERMIT ? 1
611 : 0;
612
613 if (community_match(com, entry->u.com))
614 return entry->direct == COMMUNITY_PERMIT ? 1
615 : 0;
616 } else if (entry->style == COMMUNITY_LIST_EXPANDED) {
617 if (community_regexp_match(com, entry->reg))
618 return entry->direct == COMMUNITY_PERMIT ? 1
619 : 0;
620 }
621 }
622 return 0;
8708b74f 623}
624
d62a17ae 625int lcommunity_list_match(struct lcommunity *lcom, struct community_list *list)
57d187bc 626{
d62a17ae 627 struct community_entry *entry;
628
629 for (entry = list->head; entry; entry = entry->next) {
630 if (entry->any)
631 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
632
633 if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) {
634 if (lcommunity_match(lcom, entry->u.lcom))
635 return entry->direct == COMMUNITY_PERMIT ? 1
636 : 0;
637 } else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) {
638 if (lcommunity_regexp_match(lcom, entry->reg))
639 return entry->direct == COMMUNITY_PERMIT ? 1
640 : 0;
641 }
642 }
643 return 0;
57d187bc
JS
644}
645
d62a17ae 646int ecommunity_list_match(struct ecommunity *ecom, struct community_list *list)
8708b74f 647{
d62a17ae 648 struct community_entry *entry;
649
650 for (entry = list->head; entry; entry = entry->next) {
651 if (entry->any)
652 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
653
654 if (entry->style == EXTCOMMUNITY_LIST_STANDARD) {
655 if (ecommunity_match(ecom, entry->u.ecom))
656 return entry->direct == COMMUNITY_PERMIT ? 1
657 : 0;
658 } else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED) {
659 if (ecommunity_regexp_match(ecom, entry->reg))
660 return entry->direct == COMMUNITY_PERMIT ? 1
661 : 0;
662 }
663 }
664 return 0;
718e3744 665}
666
667/* Perform exact matching. In case of expanded community-list, do
668 same thing as community_list_match(). */
d62a17ae 669int community_list_exact_match(struct community *com,
670 struct community_list *list)
718e3744 671{
d62a17ae 672 struct community_entry *entry;
673
674 for (entry = list->head; entry; entry = entry->next) {
675 if (entry->any)
676 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
677
678 if (entry->style == COMMUNITY_LIST_STANDARD) {
679 if (community_include(entry->u.com, COMMUNITY_INTERNET))
680 return entry->direct == COMMUNITY_PERMIT ? 1
681 : 0;
682
683 if (community_cmp(com, entry->u.com))
684 return entry->direct == COMMUNITY_PERMIT ? 1
685 : 0;
686 } else if (entry->style == COMMUNITY_LIST_EXPANDED) {
687 if (community_regexp_match(com, entry->reg))
688 return entry->direct == COMMUNITY_PERMIT ? 1
689 : 0;
690 }
691 }
692 return 0;
718e3744 693}
694
8708b74f 695/* Delete all permitted communities in the list from com. */
d62a17ae 696struct community *community_list_match_delete(struct community *com,
697 struct community_list *list)
718e3744 698{
d62a17ae 699 struct community_entry *entry;
700 u_int32_t val;
701 u_int32_t com_index_to_delete[com->size];
702 int delete_index = 0;
703 int i;
704
705 /* Loop over each community value and evaluate each against the
706 * community-list. If we need to delete a community value add its index
707 * to
708 * com_index_to_delete.
709 */
710 for (i = 0; i < com->size; i++) {
711 val = community_val_get(com, i);
712
713 for (entry = list->head; entry; entry = entry->next) {
714 if (entry->any) {
715 if (entry->direct == COMMUNITY_PERMIT) {
716 com_index_to_delete[delete_index] = i;
717 delete_index++;
718 }
719 break;
720 }
721
722 else if ((entry->style == COMMUNITY_LIST_STANDARD)
723 && (community_include(entry->u.com,
724 COMMUNITY_INTERNET)
725 || community_include(entry->u.com, val))) {
726 if (entry->direct == COMMUNITY_PERMIT) {
727 com_index_to_delete[delete_index] = i;
728 delete_index++;
729 }
730 break;
731 }
732
733 else if ((entry->style == COMMUNITY_LIST_EXPANDED)
734 && community_regexp_include(entry->reg, com,
735 i)) {
736 if (entry->direct == COMMUNITY_PERMIT) {
737 com_index_to_delete[delete_index] = i;
738 delete_index++;
739 }
740 break;
741 }
742 }
743 }
5cbea288 744
d62a17ae 745 /* Delete all of the communities we flagged for deletion */
746 for (i = delete_index - 1; i >= 0; i--) {
747 val = community_val_get(com, com_index_to_delete[i]);
748 community_del_val(com, &val);
749 }
5cbea288 750
d62a17ae 751 return com;
718e3744 752}
753
754/* To avoid duplicated entry in the community-list, this function
755 compares specified entry to existing entry. */
d62a17ae 756static int community_list_dup_check(struct community_list *list,
757 struct community_entry *new)
718e3744 758{
d62a17ae 759 struct community_entry *entry;
760
761 for (entry = list->head; entry; entry = entry->next) {
762 if (entry->style != new->style)
763 continue;
764
765 if (entry->direct != new->direct)
766 continue;
767
768 if (entry->any != new->any)
769 continue;
770
771 if (entry->any)
772 return 1;
773
774 switch (entry->style) {
775 case COMMUNITY_LIST_STANDARD:
776 if (community_cmp(entry->u.com, new->u.com))
777 return 1;
778 break;
779 case LARGE_COMMUNITY_LIST_STANDARD:
780 if (lcommunity_cmp(entry->u.lcom, new->u.lcom))
781 return 1;
782 break;
783 case EXTCOMMUNITY_LIST_STANDARD:
784 if (ecommunity_cmp(entry->u.ecom, new->u.ecom))
785 return 1;
786 break;
787 case COMMUNITY_LIST_EXPANDED:
788 case EXTCOMMUNITY_LIST_EXPANDED:
789 case LARGE_COMMUNITY_LIST_EXPANDED:
790 if (strcmp(entry->config, new->config) == 0)
791 return 1;
792 break;
793 default:
794 break;
795 }
796 }
797 return 0;
718e3744 798}
6b0655a2 799
718e3744 800/* Set community-list. */
d62a17ae 801int community_list_set(struct community_list_handler *ch, const char *name,
802 const char *str, int direct, int style)
718e3744 803{
d62a17ae 804 struct community_entry *entry = NULL;
805 struct community_list *list;
806 struct community *com = NULL;
807 regex_t *regex = NULL;
808
809 /* Get community list. */
810 list = community_list_get(ch, name, COMMUNITY_LIST_MASTER);
811
812 /* When community-list already has entry, new entry should have same
813 style. If you want to have mixed style community-list, you can
814 comment out this check. */
815 if (!community_list_empty_p(list)) {
816 struct community_entry *first;
817
818 first = list->head;
819
820 if (style != first->style) {
821 return (first->style == COMMUNITY_LIST_STANDARD
822 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
823 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
824 }
fee6e4e4 825 }
718e3744 826
d62a17ae 827 if (str) {
828 if (style == COMMUNITY_LIST_STANDARD)
829 com = community_str2com(str);
830 else
831 regex = bgp_regcomp(str);
8708b74f 832
d62a17ae 833 if (!com && !regex)
834 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
835 }
718e3744 836
d62a17ae 837 entry = community_entry_new();
838 entry->direct = direct;
839 entry->style = style;
840 entry->any = (str ? 0 : 1);
841 entry->u.com = com;
842 entry->reg = regex;
843 entry->config =
844 (regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
845
846 /* Do not put duplicated community entry. */
847 if (community_list_dup_check(list, entry))
848 community_entry_free(entry);
849 else {
850 community_list_entry_add(list, entry);
851 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_ADDED);
852 }
718e3744 853
d62a17ae 854 return 0;
718e3744 855}
856
813d4307 857/* Unset community-list */
d62a17ae 858int community_list_unset(struct community_list_handler *ch, const char *name,
859 const char *str, int direct, int style, int delete_all)
718e3744 860{
d62a17ae 861 struct community_entry *entry = NULL;
862 struct community_list *list;
863 struct community *com = NULL;
864
865 /* Lookup community list. */
866 list = community_list_lookup(ch, name, COMMUNITY_LIST_MASTER);
867 if (list == NULL)
868 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
869
870 /* Delete all of entry belongs to this community-list. */
871 if (delete_all) {
872 community_list_delete(list);
873 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
874 return 0;
875 }
718e3744 876
d62a17ae 877 if (style == COMMUNITY_LIST_STANDARD) {
878 if (str)
879 com = community_str2com(str);
880 }
718e3744 881
d62a17ae 882 if (com) {
883 entry = community_list_entry_lookup(list, com, direct);
884 community_free(com);
885 } else
886 entry = community_list_entry_lookup(list, str, direct);
fee6e4e4 887
d62a17ae 888 if (!entry)
889 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
718e3744 890
d62a17ae 891 community_list_entry_delete(list, entry, style);
892 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
718e3744 893
d62a17ae 894 return 0;
718e3744 895}
896
57d187bc 897/* Delete all permitted large communities in the list from com. */
d62a17ae 898struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
899 struct community_list *list)
57d187bc 900{
d62a17ae 901 struct community_entry *entry;
902 u_int32_t com_index_to_delete[lcom->size];
903 u_char *ptr;
904 int delete_index = 0;
905 int i;
906
907 /* Loop over each lcommunity value and evaluate each against the
908 * community-list. If we need to delete a community value add its index
909 * to
910 * com_index_to_delete.
911 */
912 ptr = lcom->val;
913 for (i = 0; i < lcom->size; i++) {
914 ptr += (i * LCOMMUNITY_SIZE);
915 for (entry = list->head; entry; entry = entry->next) {
916 if (entry->any) {
917 if (entry->direct == COMMUNITY_PERMIT) {
918 com_index_to_delete[delete_index] = i;
919 delete_index++;
920 }
921 break;
922 }
923
924 else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
925 && lcommunity_include(entry->u.lcom, ptr)) {
926 if (entry->direct == COMMUNITY_PERMIT) {
927 com_index_to_delete[delete_index] = i;
928 delete_index++;
929 }
930 break;
931 }
932
cde8d696 933 else if ((entry->style == LARGE_COMMUNITY_LIST_EXPANDED)
d62a17ae 934 && lcommunity_regexp_include(entry->reg, lcom,
935 i)) {
936 if (entry->direct == COMMUNITY_PERMIT) {
937 com_index_to_delete[delete_index] = i;
938 delete_index++;
939 }
940 break;
941 }
942 }
943 }
57d187bc 944
d62a17ae 945 /* Delete all of the communities we flagged for deletion */
946 ptr = lcom->val;
947 for (i = delete_index - 1; i >= 0; i--) {
948 ptr += (com_index_to_delete[i] * LCOMMUNITY_SIZE);
949 lcommunity_del_val(lcom, ptr);
950 }
57d187bc 951
d62a17ae 952 return lcom;
57d187bc
JS
953}
954
955/* Set lcommunity-list. */
d62a17ae 956int lcommunity_list_set(struct community_list_handler *ch, const char *name,
957 const char *str, int direct, int style)
57d187bc 958{
d62a17ae 959 struct community_entry *entry = NULL;
960 struct community_list *list;
961 struct lcommunity *lcom = NULL;
962 regex_t *regex = NULL;
963
964 /* Get community list. */
965 list = community_list_get(ch, name, LARGE_COMMUNITY_LIST_MASTER);
966
967 /* When community-list already has entry, new entry should have same
968 style. If you want to have mixed style community-list, you can
969 comment out this check. */
970 if (!community_list_empty_p(list)) {
971 struct community_entry *first;
972
973 first = list->head;
974
975 if (style != first->style) {
976 return (first->style == COMMUNITY_LIST_STANDARD
977 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
978 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
979 }
980 }
57d187bc 981
d62a17ae 982 if (str) {
983 if (style == LARGE_COMMUNITY_LIST_STANDARD)
984 lcom = lcommunity_str2com(str);
985 else
986 regex = bgp_regcomp(str);
57d187bc 987
d62a17ae 988 if (!lcom && !regex)
989 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
990 }
57d187bc 991
d62a17ae 992 entry = community_entry_new();
993 entry->direct = direct;
994 entry->style = style;
995 entry->any = (str ? 0 : 1);
996 entry->u.lcom = lcom;
997 entry->reg = regex;
998 if (lcom)
999 entry->config = lcommunity_lcom2str(
1000 lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST);
1001 else if (regex)
1002 entry->config = XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str);
1003 else
1004 entry->config = NULL;
1005
1006 /* Do not put duplicated community entry. */
1007 if (community_list_dup_check(list, entry))
1008 community_entry_free(entry);
1009 else
1010 community_list_entry_add(list, entry);
1011
1012 return 0;
57d187bc
JS
1013}
1014
1015/* Unset community-list. When str is NULL, delete all of
1016 community-list entry belongs to the specified name. */
d62a17ae 1017int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
1018 const char *str, int direct, int style)
57d187bc 1019{
d62a17ae 1020 struct community_entry *entry = NULL;
1021 struct community_list *list;
1022 struct lcommunity *lcom = NULL;
1023 regex_t *regex = NULL;
1024
1025 /* Lookup community list. */
1026 list = community_list_lookup(ch, name, LARGE_COMMUNITY_LIST_MASTER);
1027 if (list == NULL)
1028 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
1029
1030 /* Delete all of entry belongs to this community-list. */
1031 if (!str) {
1032 community_list_delete(list);
1033 return 0;
1034 }
57d187bc 1035
d62a17ae 1036 if (style == LARGE_COMMUNITY_LIST_STANDARD)
1037 lcom = lcommunity_str2com(str);
1038 else
1039 regex = bgp_regcomp(str);
57d187bc 1040
d62a17ae 1041 if (!lcom && !regex)
1042 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
57d187bc 1043
d62a17ae 1044 if (lcom)
1045 entry = community_list_entry_lookup(list, lcom, direct);
1046 else
1047 entry = community_list_entry_lookup(list, str, direct);
57d187bc 1048
d62a17ae 1049 if (lcom)
1050 lcommunity_free(&lcom);
1051 if (regex)
1052 bgp_regex_free(regex);
57d187bc 1053
d62a17ae 1054 if (!entry)
1055 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
57d187bc 1056
d62a17ae 1057 community_list_entry_delete(list, entry, style);
57d187bc 1058
d62a17ae 1059 return 0;
57d187bc
JS
1060}
1061
718e3744 1062/* Set extcommunity-list. */
d62a17ae 1063int extcommunity_list_set(struct community_list_handler *ch, const char *name,
1064 const char *str, int direct, int style)
718e3744 1065{
d62a17ae 1066 struct community_entry *entry = NULL;
1067 struct community_list *list;
1068 struct ecommunity *ecom = NULL;
1069 regex_t *regex = NULL;
718e3744 1070
d62a17ae 1071 entry = NULL;
718e3744 1072
d62a17ae 1073 /* Get community list. */
1074 list = community_list_get(ch, name, EXTCOMMUNITY_LIST_MASTER);
718e3744 1075
d62a17ae 1076 /* When community-list already has entry, new entry should have same
1077 style. If you want to have mixed style community-list, you can
1078 comment out this check. */
1079 if (!community_list_empty_p(list)) {
1080 struct community_entry *first;
718e3744 1081
d62a17ae 1082 first = list->head;
718e3744 1083
d62a17ae 1084 if (style != first->style) {
1085 return (first->style == EXTCOMMUNITY_LIST_STANDARD
1086 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
1087 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
1088 }
fee6e4e4 1089 }
718e3744 1090
d62a17ae 1091 if (style == EXTCOMMUNITY_LIST_STANDARD)
1092 ecom = ecommunity_str2com(str, 0, 1);
1093 else
1094 regex = bgp_regcomp(str);
1095
1096 if (!ecom && !regex)
1097 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
1098
1099 if (ecom)
1100 ecom->str =
1101 ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
1102
1103 entry = community_entry_new();
1104 entry->direct = direct;
1105 entry->style = style;
1106 entry->any = (str ? 0 : 1);
1107 if (ecom)
1108 entry->config = ecommunity_ecom2str(
1109 ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
1110 else if (regex)
1111 entry->config = XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str);
1112
1113 entry->u.ecom = ecom;
1114 entry->reg = regex;
1115
1116 /* Do not put duplicated community entry. */
1117 if (community_list_dup_check(list, entry))
1118 community_entry_free(entry);
1119 else {
1120 community_list_entry_add(list, entry);
1121 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_ADDED);
1122 }
718e3744 1123
d62a17ae 1124 return 0;
718e3744 1125}
1126
1127/* Unset extcommunity-list. When str is NULL, delete all of
1128 extcommunity-list entry belongs to the specified name. */
d62a17ae 1129int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
1130 const char *str, int direct, int style,
1131 int delete_all)
718e3744 1132{
d62a17ae 1133 struct community_entry *entry = NULL;
1134 struct community_list *list;
1135 struct ecommunity *ecom = NULL;
1136
1137 /* Lookup extcommunity list. */
1138 list = community_list_lookup(ch, name, EXTCOMMUNITY_LIST_MASTER);
1139 if (list == NULL)
1140 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
1141
1142 /* Delete all of entry belongs to this extcommunity-list. */
1143 if (delete_all) {
1144 community_list_delete(list);
1145 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
1146 return 0;
1147 }
718e3744 1148
d62a17ae 1149 if (style == EXTCOMMUNITY_LIST_STANDARD) {
1150 if (str)
1151 ecom = ecommunity_str2com(str, 0, 1);
1152 }
718e3744 1153
d62a17ae 1154 if (ecom) {
1155 entry = community_list_entry_lookup(list, ecom, direct);
1156 ecommunity_free(&ecom);
1157 } else
1158 entry = community_list_entry_lookup(list, str, direct);
fee6e4e4 1159
d62a17ae 1160 if (!entry)
1161 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
718e3744 1162
d62a17ae 1163 community_list_entry_delete(list, entry, style);
1164 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
718e3744 1165
d62a17ae 1166 return 0;
718e3744 1167}
1168
1169/* Initializa community-list. Return community-list handler. */
d62a17ae 1170struct community_list_handler *community_list_init(void)
718e3744 1171{
d62a17ae 1172 struct community_list_handler *ch;
1173 ch = XCALLOC(MTYPE_COMMUNITY_LIST_HANDLER,
1174 sizeof(struct community_list_handler));
1175 return ch;
718e3744 1176}
1177
1178/* Terminate community-list. */
d62a17ae 1179void community_list_terminate(struct community_list_handler *ch)
718e3744 1180{
d62a17ae 1181 struct community_list_master *cm;
1182 struct community_list *list;
1183
1184 cm = &ch->community_list;
1185 while ((list = cm->num.head) != NULL)
1186 community_list_delete(list);
1187 while ((list = cm->str.head) != NULL)
1188 community_list_delete(list);
1189
1190 cm = &ch->lcommunity_list;
1191 while ((list = cm->num.head) != NULL)
1192 community_list_delete(list);
1193 while ((list = cm->str.head) != NULL)
1194 community_list_delete(list);
1195
1196 cm = &ch->extcommunity_list;
1197 while ((list = cm->num.head) != NULL)
1198 community_list_delete(list);
1199 while ((list = cm->str.head) != NULL)
1200 community_list_delete(list);
1201
1202 XFREE(MTYPE_COMMUNITY_LIST_HANDLER, ch);
718e3744 1203}