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