]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_clist.c
Merge pull request #3214 from donaldsharp/ospf_crash
[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{
d7c0a89a
QY
335 uint32_t comval;
336 uint16_t as;
337 uint16_t val;
d62a17ae 338 char *str;
d62a17ae 339
d7c0a89a 340 memcpy(&comval, com_nthval(com, i), sizeof(uint32_t));
d62a17ae 341 comval = ntohl(comval);
342
343 switch (comval) {
344 case COMMUNITY_INTERNET:
aeab4a80 345 str = XSTRDUP(MTYPE_COMMUNITY_STR, "internet");
d62a17ae 346 break;
aa861c10 347 case COMMUNITY_GSHUT:
aeab4a80 348 str = XSTRDUP(MTYPE_COMMUNITY_STR, "graceful-shutdown");
aa861c10
C
349 break;
350 case COMMUNITY_ACCEPT_OWN:
aeab4a80 351 str = XSTRDUP(MTYPE_COMMUNITY_STR, "accept-own");
aa861c10
C
352 break;
353 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4:
aeab4a80
QY
354 str = XSTRDUP(MTYPE_COMMUNITY_STR,
355 "route-filter-translated-v4");
aa861c10
C
356 break;
357 case COMMUNITY_ROUTE_FILTER_v4:
aeab4a80 358 str = XSTRDUP(MTYPE_COMMUNITY_STR, "route-filter-v4");
aa861c10
C
359 break;
360 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6:
aeab4a80
QY
361 str = XSTRDUP(MTYPE_COMMUNITY_STR,
362 "route-filter-translated-v6");
aa861c10
C
363 break;
364 case COMMUNITY_ROUTE_FILTER_v6:
aeab4a80 365 str = XSTRDUP(MTYPE_COMMUNITY_STR, "route-filter-v6");
aa861c10
C
366 break;
367 case COMMUNITY_LLGR_STALE:
aeab4a80 368 str = XSTRDUP(MTYPE_COMMUNITY_STR, "llgr-stale");
aa861c10
C
369 break;
370 case COMMUNITY_NO_LLGR:
aeab4a80 371 str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-llgr");
aa861c10
C
372 break;
373 case COMMUNITY_ACCEPT_OWN_NEXTHOP:
aeab4a80 374 str = XSTRDUP(MTYPE_COMMUNITY_STR, "accept-own-nexthop");
aa861c10
C
375 break;
376 case COMMUNITY_BLACKHOLE:
aeab4a80 377 str = XSTRDUP(MTYPE_COMMUNITY_STR, "blackhole");
aa861c10 378 break;
d62a17ae 379 case COMMUNITY_NO_EXPORT:
aeab4a80 380 str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-export");
d62a17ae 381 break;
382 case COMMUNITY_NO_ADVERTISE:
aeab4a80 383 str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-advertise");
d62a17ae 384 break;
385 case COMMUNITY_LOCAL_AS:
aeab4a80 386 str = XSTRDUP(MTYPE_COMMUNITY_STR, "local-AS");
d62a17ae 387 break;
aa861c10 388 case COMMUNITY_NO_PEER:
aeab4a80 389 str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-peer");
7f323236 390 break;
809d6365 391 default:
aeab4a80 392 str = XSTRDUP(MTYPE_COMMUNITY_STR, "65536:65535");
d62a17ae 393 as = (comval >> 16) & 0xFFFF;
394 val = comval & 0xFFFF;
aeab4a80 395 snprintf(str, strlen(str), "%u:%d", as, val);
d62a17ae 396 break;
397 }
5cbea288 398
d62a17ae 399 return str;
5cbea288
DS
400}
401
402/* Internal function to perform regular expression match for
2acb4ac2 403 * a single community. */
d62a17ae 404static int community_regexp_include(regex_t *reg, struct community *com, int i)
5cbea288 405{
d62a17ae 406 char *str;
407 int rv;
5cbea288 408
d62a17ae 409 /* When there is no communities attribute it is treated as empty string.
410 */
411 if (com == NULL || com->size == 0)
412 str = XSTRDUP(MTYPE_COMMUNITY_STR, "");
413 else
414 str = community_str_get(com, i);
5cbea288 415
d62a17ae 416 /* Regular expression match. */
417 rv = regexec(reg, str, 0, NULL, 0);
b84ee83b 418
d62a17ae 419 XFREE(MTYPE_COMMUNITY_STR, str);
b84ee83b 420
d62a17ae 421 if (rv == 0)
422 return 1;
5cbea288 423
d62a17ae 424 /* No match. */
425 return 0;
5cbea288
DS
426}
427
718e3744 428/* Internal function to perform regular expression match for community
429 attribute. */
d62a17ae 430static int community_regexp_match(struct community *com, regex_t *reg)
718e3744 431{
d62a17ae 432 const char *str;
718e3744 433
d62a17ae 434 /* When there is no communities attribute it is treated as empty
435 string. */
436 if (com == NULL || com->size == 0)
437 str = "";
438 else
a69ea8ae 439 str = community_str(com, false);
718e3744 440
d62a17ae 441 /* Regular expression match. */
442 if (regexec(reg, str, 0, NULL, 0) == 0)
443 return 1;
718e3744 444
d62a17ae 445 /* No match. */
446 return 0;
718e3744 447}
448
d62a17ae 449static char *lcommunity_str_get(struct lcommunity *lcom, int i)
57d187bc 450{
d62a17ae 451 struct lcommunity_val lcomval;
d7c0a89a
QY
452 uint32_t globaladmin;
453 uint32_t localdata1;
454 uint32_t localdata2;
d62a17ae 455 char *str;
d7c0a89a 456 uint8_t *ptr;
d62a17ae 457 char *pnt;
458
ff9104a2 459 ptr = lcom->val + (i * LCOMMUNITY_SIZE);
d62a17ae 460
461 memcpy(&lcomval, ptr, LCOMMUNITY_SIZE);
462
463 /* Allocate memory. 48 bytes taken off bgp_lcommunity.c */
464 str = pnt = XMALLOC(MTYPE_LCOMMUNITY_STR, 48);
465
d7c0a89a 466 ptr = (uint8_t *)lcomval.val;
937652c6
DL
467 ptr = ptr_get_be32(ptr, &globaladmin);
468 ptr = ptr_get_be32(ptr, &localdata1);
469 ptr = ptr_get_be32(ptr, &localdata2);
470 (void)ptr; /* consume value */
d62a17ae 471
472 sprintf(pnt, "%u:%u:%u", globaladmin, localdata1, localdata2);
473 pnt += strlen(pnt);
474 *pnt = '\0';
475
476 return str;
57d187bc
JS
477}
478
479/* Internal function to perform regular expression match for
2acb4ac2 480 * a single community. */
d62a17ae 481static int lcommunity_regexp_include(regex_t *reg, struct lcommunity *lcom,
482 int i)
57d187bc 483{
d62a17ae 484 char *str;
485
486 /* When there is no communities attribute it is treated as empty string.
487 */
488 if (lcom == NULL || lcom->size == 0)
489 str = XSTRDUP(MTYPE_LCOMMUNITY_STR, "");
490 else
491 str = lcommunity_str_get(lcom, i);
492
493 /* Regular expression match. */
494 if (regexec(reg, str, 0, NULL, 0) == 0) {
495 XFREE(MTYPE_LCOMMUNITY_STR, str);
496 return 1;
497 }
57d187bc 498
d62a17ae 499 XFREE(MTYPE_LCOMMUNITY_STR, str);
500 /* No match. */
501 return 0;
57d187bc
JS
502}
503
d62a17ae 504static int lcommunity_regexp_match(struct lcommunity *com, regex_t *reg)
57d187bc 505{
d62a17ae 506 const char *str;
57d187bc 507
d62a17ae 508 /* When there is no communities attribute it is treated as empty
509 string. */
510 if (com == NULL || com->size == 0)
511 str = "";
512 else
8d9b8ed9 513 str = lcommunity_str(com, false);
57d187bc 514
d62a17ae 515 /* Regular expression match. */
516 if (regexec(reg, str, 0, NULL, 0) == 0)
517 return 1;
57d187bc 518
d62a17ae 519 /* No match. */
520 return 0;
57d187bc
JS
521}
522
523
d62a17ae 524static int ecommunity_regexp_match(struct ecommunity *ecom, regex_t *reg)
8708b74f 525{
d62a17ae 526 const char *str;
8708b74f 527
d62a17ae 528 /* When there is no communities attribute it is treated as empty
529 string. */
530 if (ecom == NULL || ecom->size == 0)
531 str = "";
532 else
533 str = ecommunity_str(ecom);
8708b74f 534
d62a17ae 535 /* Regular expression match. */
536 if (regexec(reg, str, 0, NULL, 0) == 0)
537 return 1;
8708b74f 538
d62a17ae 539 /* No match. */
540 return 0;
8708b74f 541}
542
ffd0c037 543#if 0
718e3744 544/* Delete community attribute using regular expression match. Return
545 modified communites attribute. */
546static struct community *
8708b74f 547community_regexp_delete (struct community *com, regex_t * reg)
718e3744 548{
aa861c10
C
549 int i;
550 uint32_t comval;
551 /* Maximum is "65535:65535" + '\0'. */
552 char c[12];
553 const char *str;
554
555 if (!com)
556 return NULL;
557
558 i = 0;
559 while (i < com->size)
560 {
561 memcpy (&comval, com_nthval (com, i), sizeof (uint32_t));
562 comval = ntohl (comval);
563
564 switch (comval) {
565 case COMMUNITY_INTERNET:
566 str = "internet";
567 break;
568 case COMMUNITY_ACCEPT_OWN:
569 str = "accept-own";
570 break;
571 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4:
572 str = "route-filter-translated-v4";
573 break;
574 case COMMUNITY_ROUTE_FILTER_v4:
575 str = "route-filter-v4";
576 break;
577 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6:
578 str = "route-filter-translated-v6";
579 break;
580 case COMMUNITY_ROUTE_FILTER_v6:
581 str = "route-filter-v6";
582 break;
583 case COMMUNITY_LLGR_STALE:
584 str = "llgr-stale";
585 break;
586 case COMMUNITY_NO_LLGR:
587 str = "no-llgr";
588 break;
589 case COMMUNITY_ACCEPT_OWN_NEXTHOP:
590 str = "accept-own-nexthop";
591 break;
592 case COMMUNITY_BLACKHOLE:
593 str = "blackhole";
594 break;
595 case COMMUNITY_NO_EXPORT:
596 str = "no-export";
597 break;
598 case COMMUNITY_NO_ADVERTISE:
599 str = "no-advertise";
600 break;
601 case COMMUNITY_LOCAL_AS:
602 str = "local-AS";
603 break;
604 case COMMUNITY_NO_PEER:
605 str = "no-peer";
606 break;
607 default:
608 sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF,
609 comval & 0xFFFF);
610 str = c;
611 break;
612 }
613
614 if (regexec (reg, str, 0, NULL, 0) == 0)
615 community_del_val (com, com_nthval (com, i));
616 else
617 i++;
618 }
619 return com;
718e3744 620}
ffd0c037 621#endif
718e3744 622
623/* When given community attribute matches to the community-list return
624 1 else return 0. */
d62a17ae 625int community_list_match(struct community *com, struct community_list *list)
718e3744 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 == COMMUNITY_LIST_STANDARD) {
634 if (community_include(entry->u.com, COMMUNITY_INTERNET))
635 return entry->direct == COMMUNITY_PERMIT ? 1
636 : 0;
637
638 if (community_match(com, entry->u.com))
639 return entry->direct == COMMUNITY_PERMIT ? 1
640 : 0;
641 } else if (entry->style == COMMUNITY_LIST_EXPANDED) {
642 if (community_regexp_match(com, entry->reg))
643 return entry->direct == COMMUNITY_PERMIT ? 1
644 : 0;
645 }
646 }
647 return 0;
8708b74f 648}
649
d62a17ae 650int lcommunity_list_match(struct lcommunity *lcom, struct community_list *list)
57d187bc 651{
d62a17ae 652 struct community_entry *entry;
653
654 for (entry = list->head; entry; entry = entry->next) {
655 if (entry->any)
656 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
657
658 if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) {
659 if (lcommunity_match(lcom, entry->u.lcom))
660 return entry->direct == COMMUNITY_PERMIT ? 1
661 : 0;
662 } else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) {
663 if (lcommunity_regexp_match(lcom, entry->reg))
664 return entry->direct == COMMUNITY_PERMIT ? 1
665 : 0;
666 }
667 }
668 return 0;
57d187bc
JS
669}
670
d62a17ae 671int ecommunity_list_match(struct ecommunity *ecom, struct community_list *list)
8708b74f 672{
d62a17ae 673 struct community_entry *entry;
674
675 for (entry = list->head; entry; entry = entry->next) {
676 if (entry->any)
677 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
678
679 if (entry->style == EXTCOMMUNITY_LIST_STANDARD) {
680 if (ecommunity_match(ecom, entry->u.ecom))
681 return entry->direct == COMMUNITY_PERMIT ? 1
682 : 0;
683 } else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED) {
684 if (ecommunity_regexp_match(ecom, entry->reg))
685 return entry->direct == COMMUNITY_PERMIT ? 1
686 : 0;
687 }
688 }
689 return 0;
718e3744 690}
691
692/* Perform exact matching. In case of expanded community-list, do
693 same thing as community_list_match(). */
d62a17ae 694int community_list_exact_match(struct community *com,
695 struct community_list *list)
718e3744 696{
d62a17ae 697 struct community_entry *entry;
698
699 for (entry = list->head; entry; entry = entry->next) {
700 if (entry->any)
701 return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
702
703 if (entry->style == COMMUNITY_LIST_STANDARD) {
704 if (community_include(entry->u.com, COMMUNITY_INTERNET))
705 return entry->direct == COMMUNITY_PERMIT ? 1
706 : 0;
707
708 if (community_cmp(com, entry->u.com))
709 return entry->direct == COMMUNITY_PERMIT ? 1
710 : 0;
711 } else if (entry->style == COMMUNITY_LIST_EXPANDED) {
712 if (community_regexp_match(com, entry->reg))
713 return entry->direct == COMMUNITY_PERMIT ? 1
714 : 0;
715 }
716 }
717 return 0;
718e3744 718}
719
8708b74f 720/* Delete all permitted communities in the list from com. */
d62a17ae 721struct community *community_list_match_delete(struct community *com,
722 struct community_list *list)
718e3744 723{
d62a17ae 724 struct community_entry *entry;
d7c0a89a
QY
725 uint32_t val;
726 uint32_t com_index_to_delete[com->size];
d62a17ae 727 int delete_index = 0;
728 int i;
729
730 /* Loop over each community value and evaluate each against the
731 * community-list. If we need to delete a community value add its index
ceead39c 732 * to com_index_to_delete.
d62a17ae 733 */
734 for (i = 0; i < com->size; i++) {
735 val = community_val_get(com, i);
736
737 for (entry = list->head; entry; entry = entry->next) {
738 if (entry->any) {
739 if (entry->direct == COMMUNITY_PERMIT) {
740 com_index_to_delete[delete_index] = i;
741 delete_index++;
742 }
743 break;
744 }
745
746 else if ((entry->style == COMMUNITY_LIST_STANDARD)
747 && (community_include(entry->u.com,
748 COMMUNITY_INTERNET)
749 || community_include(entry->u.com, val))) {
750 if (entry->direct == COMMUNITY_PERMIT) {
751 com_index_to_delete[delete_index] = i;
752 delete_index++;
753 }
754 break;
755 }
756
757 else if ((entry->style == COMMUNITY_LIST_EXPANDED)
758 && community_regexp_include(entry->reg, com,
759 i)) {
760 if (entry->direct == COMMUNITY_PERMIT) {
761 com_index_to_delete[delete_index] = i;
762 delete_index++;
763 }
764 break;
765 }
766 }
767 }
5cbea288 768
d62a17ae 769 /* Delete all of the communities we flagged for deletion */
770 for (i = delete_index - 1; i >= 0; i--) {
771 val = community_val_get(com, com_index_to_delete[i]);
772 community_del_val(com, &val);
773 }
5cbea288 774
d62a17ae 775 return com;
718e3744 776}
777
778/* To avoid duplicated entry in the community-list, this function
779 compares specified entry to existing entry. */
d62a17ae 780static int community_list_dup_check(struct community_list *list,
781 struct community_entry *new)
718e3744 782{
d62a17ae 783 struct community_entry *entry;
784
785 for (entry = list->head; entry; entry = entry->next) {
786 if (entry->style != new->style)
787 continue;
788
789 if (entry->direct != new->direct)
790 continue;
791
792 if (entry->any != new->any)
793 continue;
794
795 if (entry->any)
796 return 1;
797
798 switch (entry->style) {
799 case COMMUNITY_LIST_STANDARD:
800 if (community_cmp(entry->u.com, new->u.com))
801 return 1;
802 break;
803 case LARGE_COMMUNITY_LIST_STANDARD:
804 if (lcommunity_cmp(entry->u.lcom, new->u.lcom))
805 return 1;
806 break;
807 case EXTCOMMUNITY_LIST_STANDARD:
808 if (ecommunity_cmp(entry->u.ecom, new->u.ecom))
809 return 1;
810 break;
811 case COMMUNITY_LIST_EXPANDED:
812 case EXTCOMMUNITY_LIST_EXPANDED:
813 case LARGE_COMMUNITY_LIST_EXPANDED:
814 if (strcmp(entry->config, new->config) == 0)
815 return 1;
816 break;
817 default:
818 break;
819 }
820 }
821 return 0;
718e3744 822}
6b0655a2 823
718e3744 824/* Set community-list. */
d62a17ae 825int community_list_set(struct community_list_handler *ch, const char *name,
826 const char *str, int direct, int style)
718e3744 827{
d62a17ae 828 struct community_entry *entry = NULL;
829 struct community_list *list;
830 struct community *com = NULL;
831 regex_t *regex = NULL;
832
833 /* Get community list. */
834 list = community_list_get(ch, name, COMMUNITY_LIST_MASTER);
835
836 /* When community-list already has entry, new entry should have same
837 style. If you want to have mixed style community-list, you can
838 comment out this check. */
839 if (!community_list_empty_p(list)) {
840 struct community_entry *first;
841
842 first = list->head;
843
844 if (style != first->style) {
845 return (first->style == COMMUNITY_LIST_STANDARD
846 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
847 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
848 }
fee6e4e4 849 }
718e3744 850
d62a17ae 851 if (str) {
852 if (style == COMMUNITY_LIST_STANDARD)
853 com = community_str2com(str);
854 else
855 regex = bgp_regcomp(str);
8708b74f 856
d62a17ae 857 if (!com && !regex)
858 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
859 }
718e3744 860
d62a17ae 861 entry = community_entry_new();
862 entry->direct = direct;
863 entry->style = style;
864 entry->any = (str ? 0 : 1);
865 entry->u.com = com;
866 entry->reg = regex;
867 entry->config =
868 (regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
869
870 /* Do not put duplicated community entry. */
871 if (community_list_dup_check(list, entry))
872 community_entry_free(entry);
873 else {
874 community_list_entry_add(list, entry);
875 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_ADDED);
876 }
718e3744 877
d62a17ae 878 return 0;
718e3744 879}
880
813d4307 881/* Unset community-list */
d62a17ae 882int community_list_unset(struct community_list_handler *ch, const char *name,
7298a8e1 883 const char *str, int direct, int style)
718e3744 884{
d62a17ae 885 struct community_entry *entry = NULL;
886 struct community_list *list;
887 struct community *com = NULL;
888
889 /* Lookup community list. */
890 list = community_list_lookup(ch, name, COMMUNITY_LIST_MASTER);
891 if (list == NULL)
892 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
893
894 /* Delete all of entry belongs to this community-list. */
7298a8e1 895 if (!str) {
d62a17ae 896 community_list_delete(list);
897 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
898 return 0;
899 }
718e3744 900
7298a8e1
QY
901 if (style == COMMUNITY_LIST_STANDARD)
902 com = community_str2com(str);
718e3744 903
d62a17ae 904 if (com) {
905 entry = community_list_entry_lookup(list, com, direct);
906 community_free(com);
907 } else
908 entry = community_list_entry_lookup(list, str, direct);
fee6e4e4 909
d62a17ae 910 if (!entry)
911 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
718e3744 912
3f54c705 913 community_list_entry_delete(list, entry);
d62a17ae 914 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
718e3744 915
d62a17ae 916 return 0;
718e3744 917}
918
57d187bc 919/* Delete all permitted large communities in the list from com. */
d62a17ae 920struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
921 struct community_list *list)
57d187bc 922{
d62a17ae 923 struct community_entry *entry;
d7c0a89a
QY
924 uint32_t com_index_to_delete[lcom->size];
925 uint8_t *ptr;
d62a17ae 926 int delete_index = 0;
927 int i;
928
929 /* Loop over each lcommunity value and evaluate each against the
930 * community-list. If we need to delete a community value add its index
ceead39c 931 * to com_index_to_delete.
d62a17ae 932 */
d62a17ae 933 for (i = 0; i < lcom->size; i++) {
534fc195 934 ptr = lcom->val + (i * LCOMMUNITY_SIZE);
d62a17ae 935 for (entry = list->head; entry; entry = entry->next) {
936 if (entry->any) {
937 if (entry->direct == COMMUNITY_PERMIT) {
938 com_index_to_delete[delete_index] = i;
939 delete_index++;
940 }
941 break;
942 }
943
944 else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
945 && lcommunity_include(entry->u.lcom, ptr)) {
946 if (entry->direct == COMMUNITY_PERMIT) {
947 com_index_to_delete[delete_index] = i;
948 delete_index++;
949 }
950 break;
951 }
952
cde8d696 953 else if ((entry->style == LARGE_COMMUNITY_LIST_EXPANDED)
d62a17ae 954 && lcommunity_regexp_include(entry->reg, lcom,
955 i)) {
956 if (entry->direct == COMMUNITY_PERMIT) {
957 com_index_to_delete[delete_index] = i;
958 delete_index++;
959 }
960 break;
961 }
962 }
963 }
57d187bc 964
d62a17ae 965 /* Delete all of the communities we flagged for deletion */
d62a17ae 966 for (i = delete_index - 1; i >= 0; i--) {
0a7dce9b 967 ptr = lcom->val + (com_index_to_delete[i] * LCOMMUNITY_SIZE);
d62a17ae 968 lcommunity_del_val(lcom, ptr);
969 }
57d187bc 970
d62a17ae 971 return lcom;
57d187bc
JS
972}
973
974/* Set lcommunity-list. */
d62a17ae 975int lcommunity_list_set(struct community_list_handler *ch, const char *name,
976 const char *str, int direct, int style)
57d187bc 977{
d62a17ae 978 struct community_entry *entry = NULL;
979 struct community_list *list;
980 struct lcommunity *lcom = NULL;
981 regex_t *regex = NULL;
982
983 /* Get community list. */
984 list = community_list_get(ch, name, LARGE_COMMUNITY_LIST_MASTER);
985
986 /* When community-list already has entry, new entry should have same
987 style. If you want to have mixed style community-list, you can
988 comment out this check. */
989 if (!community_list_empty_p(list)) {
990 struct community_entry *first;
991
992 first = list->head;
993
994 if (style != first->style) {
995 return (first->style == COMMUNITY_LIST_STANDARD
996 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
997 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
998 }
999 }
57d187bc 1000
d62a17ae 1001 if (str) {
1002 if (style == LARGE_COMMUNITY_LIST_STANDARD)
1003 lcom = lcommunity_str2com(str);
1004 else
1005 regex = bgp_regcomp(str);
57d187bc 1006
d62a17ae 1007 if (!lcom && !regex)
1008 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
1009 }
57d187bc 1010
d62a17ae 1011 entry = community_entry_new();
1012 entry->direct = direct;
1013 entry->style = style;
1014 entry->any = (str ? 0 : 1);
1015 entry->u.lcom = lcom;
1016 entry->reg = regex;
8d9b8ed9
PM
1017 entry->config =
1018 (regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
d62a17ae 1019
1020 /* Do not put duplicated community entry. */
1021 if (community_list_dup_check(list, entry))
1022 community_entry_free(entry);
1023 else
1024 community_list_entry_add(list, entry);
1025
1026 return 0;
57d187bc
JS
1027}
1028
1029/* Unset community-list. When str is NULL, delete all of
1030 community-list entry belongs to the specified name. */
d62a17ae 1031int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
1032 const char *str, int direct, int style)
57d187bc 1033{
d62a17ae 1034 struct community_entry *entry = NULL;
1035 struct community_list *list;
1036 struct lcommunity *lcom = NULL;
1037 regex_t *regex = NULL;
1038
1039 /* Lookup community list. */
1040 list = community_list_lookup(ch, name, LARGE_COMMUNITY_LIST_MASTER);
1041 if (list == NULL)
1042 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
1043
1044 /* Delete all of entry belongs to this community-list. */
1045 if (!str) {
1046 community_list_delete(list);
1047 return 0;
1048 }
57d187bc 1049
d62a17ae 1050 if (style == LARGE_COMMUNITY_LIST_STANDARD)
1051 lcom = lcommunity_str2com(str);
1052 else
1053 regex = bgp_regcomp(str);
57d187bc 1054
d62a17ae 1055 if (!lcom && !regex)
1056 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
57d187bc 1057
d62a17ae 1058 if (lcom)
1059 entry = community_list_entry_lookup(list, lcom, direct);
1060 else
1061 entry = community_list_entry_lookup(list, str, direct);
57d187bc 1062
d62a17ae 1063 if (lcom)
1064 lcommunity_free(&lcom);
1065 if (regex)
1066 bgp_regex_free(regex);
57d187bc 1067
d62a17ae 1068 if (!entry)
1069 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
57d187bc 1070
3f54c705 1071 community_list_entry_delete(list, entry);
57d187bc 1072
d62a17ae 1073 return 0;
57d187bc
JS
1074}
1075
718e3744 1076/* Set extcommunity-list. */
d62a17ae 1077int extcommunity_list_set(struct community_list_handler *ch, const char *name,
1078 const char *str, int direct, int style)
718e3744 1079{
d62a17ae 1080 struct community_entry *entry = NULL;
1081 struct community_list *list;
1082 struct ecommunity *ecom = NULL;
1083 regex_t *regex = NULL;
718e3744 1084
fa301630 1085 if (str == NULL)
1086 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
1087
d62a17ae 1088 /* Get community list. */
1089 list = community_list_get(ch, name, EXTCOMMUNITY_LIST_MASTER);
718e3744 1090
d62a17ae 1091 /* When community-list already has entry, new entry should have same
1092 style. If you want to have mixed style community-list, you can
1093 comment out this check. */
1094 if (!community_list_empty_p(list)) {
1095 struct community_entry *first;
718e3744 1096
d62a17ae 1097 first = list->head;
718e3744 1098
d62a17ae 1099 if (style != first->style) {
1100 return (first->style == EXTCOMMUNITY_LIST_STANDARD
1101 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
1102 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
1103 }
fee6e4e4 1104 }
718e3744 1105
d62a17ae 1106 if (style == EXTCOMMUNITY_LIST_STANDARD)
1107 ecom = ecommunity_str2com(str, 0, 1);
1108 else
1109 regex = bgp_regcomp(str);
1110
1111 if (!ecom && !regex)
1112 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
1113
1114 if (ecom)
1115 ecom->str =
1116 ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
1117
1118 entry = community_entry_new();
1119 entry->direct = direct;
1120 entry->style = style;
fa301630 1121 entry->any = 0;
d62a17ae 1122 if (ecom)
1123 entry->config = ecommunity_ecom2str(
1124 ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
1125 else if (regex)
1126 entry->config = XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str);
1127
1128 entry->u.ecom = ecom;
1129 entry->reg = regex;
1130
1131 /* Do not put duplicated community entry. */
1132 if (community_list_dup_check(list, entry))
1133 community_entry_free(entry);
1134 else {
1135 community_list_entry_add(list, entry);
1136 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_ADDED);
1137 }
718e3744 1138
d62a17ae 1139 return 0;
718e3744 1140}
1141
7298a8e1
QY
1142/* Unset extcommunity-list.
1143 *
1144 * When str is NULL, delete all extcommunity-list entries belonging to the
1145 * specified name.
1146 */
d62a17ae 1147int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
7298a8e1 1148 const char *str, int direct, int style)
718e3744 1149{
d62a17ae 1150 struct community_entry *entry = NULL;
1151 struct community_list *list;
1152 struct ecommunity *ecom = NULL;
1153
1154 /* Lookup extcommunity list. */
1155 list = community_list_lookup(ch, name, EXTCOMMUNITY_LIST_MASTER);
1156 if (list == NULL)
1157 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
1158
1159 /* Delete all of entry belongs to this extcommunity-list. */
7298a8e1 1160 if (!str) {
d62a17ae 1161 community_list_delete(list);
1162 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
1163 return 0;
1164 }
718e3744 1165
7298a8e1
QY
1166 if (style == EXTCOMMUNITY_LIST_STANDARD)
1167 ecom = ecommunity_str2com(str, 0, 1);
718e3744 1168
d62a17ae 1169 if (ecom) {
1170 entry = community_list_entry_lookup(list, ecom, direct);
1171 ecommunity_free(&ecom);
1172 } else
1173 entry = community_list_entry_lookup(list, str, direct);
fee6e4e4 1174
d62a17ae 1175 if (!entry)
1176 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
718e3744 1177
3f54c705 1178 community_list_entry_delete(list, entry);
d62a17ae 1179 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
718e3744 1180
d62a17ae 1181 return 0;
718e3744 1182}
1183
1184/* Initializa community-list. Return community-list handler. */
d62a17ae 1185struct community_list_handler *community_list_init(void)
718e3744 1186{
d62a17ae 1187 struct community_list_handler *ch;
1188 ch = XCALLOC(MTYPE_COMMUNITY_LIST_HANDLER,
1189 sizeof(struct community_list_handler));
1190 return ch;
718e3744 1191}
1192
1193/* Terminate community-list. */
d62a17ae 1194void community_list_terminate(struct community_list_handler *ch)
718e3744 1195{
d62a17ae 1196 struct community_list_master *cm;
1197 struct community_list *list;
1198
1199 cm = &ch->community_list;
1200 while ((list = cm->num.head) != NULL)
1201 community_list_delete(list);
1202 while ((list = cm->str.head) != NULL)
1203 community_list_delete(list);
1204
1205 cm = &ch->lcommunity_list;
1206 while ((list = cm->num.head) != NULL)
1207 community_list_delete(list);
1208 while ((list = cm->str.head) != NULL)
1209 community_list_delete(list);
1210
1211 cm = &ch->extcommunity_list;
1212 while ((list = cm->num.head) != NULL)
1213 community_list_delete(list);
1214 while ((list = cm->str.head) != NULL)
1215 community_list_delete(list);
1216
1217 XFREE(MTYPE_COMMUNITY_LIST_HANDLER, ch);
718e3744 1218}