]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_clist.c
bgpd, lib: Use bool instead of uint8_t for community/prefix-list "any"
[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"
3571a6a2 29#include "jhash.h"
5bd66e2d 30#include "frrstr.h"
718e3744 31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_community.h"
34#include "bgpd/bgp_ecommunity.h"
57d187bc 35#include "bgpd/bgp_lcommunity.h"
718e3744 36#include "bgpd/bgp_aspath.h"
37#include "bgpd/bgp_regex.h"
38#include "bgpd/bgp_clist.h"
6b0655a2 39
2f8cc0e5
DA
40/* Calculate new sequential number. */
41static int64_t bgp_clist_new_seq_get(struct community_list *list)
42{
43 int64_t maxseq;
44 int64_t newseq;
45 struct community_entry *entry;
46
1bb379bf 47 maxseq = 0;
2f8cc0e5
DA
48
49 for (entry = list->head; entry; entry = entry->next) {
50 if (maxseq < entry->seq)
51 maxseq = entry->seq;
52 }
53
54 newseq = ((maxseq / 5) * 5) + 5;
55
56 return (newseq > UINT_MAX) ? UINT_MAX : newseq;
57}
58
59/* Return community-list entry which has same seq number. */
60static struct community_entry *bgp_clist_seq_check(struct community_list *list,
61 int64_t seq)
62{
63 struct community_entry *entry;
64
65 for (entry = list->head; entry; entry = entry->next)
66 if (entry->seq == seq)
67 return entry;
68 return NULL;
69}
70
d8b87afe 71static uint32_t bgp_clist_hash_key_community_list(const void *data)
3571a6a2 72{
d8b87afe 73 struct community_list *cl = (struct community_list *) data;
3571a6a2 74
e237b0d2
DS
75 if (cl->name_hash)
76 return cl->name_hash;
77
78 cl->name_hash = bgp_clist_hash_key(cl->name);
79 return cl->name_hash;
3571a6a2
DS
80}
81
82static bool bgp_clist_hash_cmp_community_list(const void *a1, const void *a2)
83{
84 const struct community_list *cl1 = a1;
85 const struct community_list *cl2 = a2;
86
e237b0d2
DS
87 if (cl1->name_hash != cl2->name_hash)
88 return false;
89
3571a6a2
DS
90 if (strcmp(cl1->name, cl2->name) == 0)
91 return true;
92
93 return false;
94}
95
718e3744 96/* Lookup master structure for community-list or
97 extcommunity-list. */
98struct community_list_master *
d62a17ae 99community_list_master_lookup(struct community_list_handler *ch, int master)
718e3744 100{
d62a17ae 101 if (ch)
102 switch (master) {
103 case COMMUNITY_LIST_MASTER:
104 return &ch->community_list;
105 case EXTCOMMUNITY_LIST_MASTER:
106 return &ch->extcommunity_list;
107 case LARGE_COMMUNITY_LIST_MASTER:
108 return &ch->lcommunity_list;
109 }
110 return NULL;
718e3744 111}
112
113/* Allocate a new community list entry. */
d62a17ae 114static struct community_entry *community_entry_new(void)
718e3744 115{
d62a17ae 116 return XCALLOC(MTYPE_COMMUNITY_LIST_ENTRY,
117 sizeof(struct community_entry));
718e3744 118}
119
120/* Free community list entry. */
d62a17ae 121static void community_entry_free(struct community_entry *entry)
718e3744 122{
d62a17ae 123 switch (entry->style) {
124 case COMMUNITY_LIST_STANDARD:
125 if (entry->u.com)
3c1f53de 126 community_free(&entry->u.com);
d62a17ae 127 break;
128 case LARGE_COMMUNITY_LIST_STANDARD:
129 if (entry->u.lcom)
130 lcommunity_free(&entry->u.lcom);
131 break;
132 case EXTCOMMUNITY_LIST_STANDARD:
133 /* In case of standard extcommunity-list, configuration string
134 is made by ecommunity_ecom2str(). */
0a22ddfb 135 XFREE(MTYPE_ECOMMUNITY_STR, entry->config);
d62a17ae 136 if (entry->u.ecom)
137 ecommunity_free(&entry->u.ecom);
138 break;
139 case COMMUNITY_LIST_EXPANDED:
140 case EXTCOMMUNITY_LIST_EXPANDED:
141 case LARGE_COMMUNITY_LIST_EXPANDED:
0a22ddfb 142 XFREE(MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
d62a17ae 143 if (entry->reg)
144 bgp_regex_free(entry->reg);
145 default:
146 break;
147 }
148 XFREE(MTYPE_COMMUNITY_LIST_ENTRY, entry);
718e3744 149}
150
151/* Allocate a new community-list. */
d62a17ae 152static struct community_list *community_list_new(void)
718e3744 153{
d62a17ae 154 return XCALLOC(MTYPE_COMMUNITY_LIST, sizeof(struct community_list));
718e3744 155}
156
157/* Free community-list. */
d62a17ae 158static void community_list_free(struct community_list *list)
718e3744 159{
0a22ddfb 160 XFREE(MTYPE_COMMUNITY_LIST_NAME, list->name);
d62a17ae 161 XFREE(MTYPE_COMMUNITY_LIST, list);
718e3744 162}
163
94f2b392 164static struct community_list *
d62a17ae 165community_list_insert(struct community_list_handler *ch, const char *name,
166 int master)
718e3744 167{
d62a17ae 168 size_t i;
169 long number;
170 struct community_list *new;
171 struct community_list *point;
172 struct community_list_list *list;
173 struct community_list_master *cm;
174
175 /* Lookup community-list master. */
176 cm = community_list_master_lookup(ch, master);
177 if (!cm)
178 return NULL;
179
180 /* Allocate new community_list and copy given name. */
181 new = community_list_new();
182 new->name = XSTRDUP(MTYPE_COMMUNITY_LIST_NAME, name);
e237b0d2 183 new->name_hash = bgp_clist_hash_key_community_list(new);
d62a17ae 184
3571a6a2
DS
185 /* Save for later */
186 hash_get(cm->hash, new, hash_alloc_intern);
187
d62a17ae 188 /* If name is made by all digit character. We treat it as
189 number. */
190 for (number = 0, i = 0; i < strlen(name); i++) {
fefa5e0f 191 if (isdigit((unsigned char)name[i]))
d62a17ae 192 number = (number * 10) + (name[i] - '0');
193 else
194 break;
195 }
718e3744 196
d62a17ae 197 /* In case of name is all digit character */
198 if (i == strlen(name)) {
199 new->sort = COMMUNITY_LIST_NUMBER;
718e3744 200
d62a17ae 201 /* Set access_list to number list. */
202 list = &cm->num;
718e3744 203
d62a17ae 204 for (point = list->head; point; point = point->next)
205 if (atol(point->name) >= number)
206 break;
207 } else {
208 new->sort = COMMUNITY_LIST_STRING;
718e3744 209
d62a17ae 210 /* Set access_list to string list. */
211 list = &cm->str;
718e3744 212
d62a17ae 213 /* Set point to insertion point. */
214 for (point = list->head; point; point = point->next)
215 if (strcmp(point->name, name) >= 0)
216 break;
217 }
718e3744 218
d62a17ae 219 /* Link to upper list. */
220 new->parent = list;
718e3744 221
d62a17ae 222 /* In case of this is the first element of master. */
223 if (list->head == NULL) {
224 list->head = list->tail = new;
225 return new;
226 }
718e3744 227
d62a17ae 228 /* In case of insertion is made at the tail of access_list. */
229 if (point == NULL) {
230 new->prev = list->tail;
231 list->tail->next = new;
232 list->tail = new;
233 return new;
234 }
718e3744 235
d62a17ae 236 /* In case of insertion is made at the head of access_list. */
237 if (point == list->head) {
238 new->next = list->head;
239 list->head->prev = new;
240 list->head = new;
241 return new;
242 }
718e3744 243
d62a17ae 244 /* Insertion is made at middle of the access_list. */
245 new->next = point;
246 new->prev = point->prev;
718e3744 247
d62a17ae 248 if (point->prev)
249 point->prev->next = new;
250 point->prev = new;
718e3744 251
d62a17ae 252 return new;
718e3744 253}
254
d62a17ae 255struct community_list *community_list_lookup(struct community_list_handler *ch,
e237b0d2
DS
256 const char *name,
257 uint32_t name_hash,
258 int master)
718e3744 259{
3571a6a2 260 struct community_list lookup;
d62a17ae 261 struct community_list_master *cm;
718e3744 262
d62a17ae 263 if (!name)
264 return NULL;
718e3744 265
d62a17ae 266 cm = community_list_master_lookup(ch, master);
267 if (!cm)
268 return NULL;
718e3744 269
3571a6a2 270 lookup.name = (char *)name;
e237b0d2 271 lookup.name_hash = name_hash;
3571a6a2 272 return hash_get(cm->hash, &lookup, NULL);
718e3744 273}
274
94f2b392 275static struct community_list *
d62a17ae 276community_list_get(struct community_list_handler *ch, const char *name,
277 int master)
718e3744 278{
d62a17ae 279 struct community_list *list;
718e3744 280
e237b0d2 281 list = community_list_lookup(ch, name, 0, master);
d62a17ae 282 if (!list)
283 list = community_list_insert(ch, name, master);
284 return list;
718e3744 285}
286
3571a6a2
DS
287static void community_list_delete(struct community_list_master *cm,
288 struct community_list *list)
718e3744 289{
d62a17ae 290 struct community_list_list *clist;
291 struct community_entry *entry, *next;
718e3744 292
d62a17ae 293 for (entry = list->head; entry; entry = next) {
294 next = entry->next;
295 community_entry_free(entry);
296 }
718e3744 297
d62a17ae 298 clist = list->parent;
718e3744 299
d62a17ae 300 if (list->next)
301 list->next->prev = list->prev;
302 else
303 clist->tail = list->prev;
718e3744 304
d62a17ae 305 if (list->prev)
306 list->prev->next = list->next;
307 else
308 clist->head = list->next;
718e3744 309
3571a6a2 310 hash_release(cm->hash, list);
d62a17ae 311 community_list_free(list);
718e3744 312}
313
88f1c947 314static bool community_list_empty_p(struct community_list *list)
718e3744 315{
88f1c947 316 return list->head == NULL && list->tail == NULL;
718e3744 317}
6b0655a2 318
718e3744 319/* Delete community-list entry from the list. */
3571a6a2
DS
320static void community_list_entry_delete(struct community_list_master *cm,
321 struct community_list *list,
3f54c705 322 struct community_entry *entry)
718e3744 323{
d62a17ae 324 if (entry->next)
325 entry->next->prev = entry->prev;
326 else
327 list->tail = entry->prev;
718e3744 328
d62a17ae 329 if (entry->prev)
330 entry->prev->next = entry->next;
331 else
332 list->head = entry->next;
718e3744 333
d62a17ae 334 community_entry_free(entry);
718e3744 335
d62a17ae 336 if (community_list_empty_p(list))
3571a6a2 337 community_list_delete(cm, list);
718e3744 338}
339
2f8cc0e5
DA
340/* Add community-list entry to the list. */
341static void community_list_entry_add(struct community_list *list,
342 struct community_entry *entry,
343 struct community_list_handler *ch,
344 int master)
345{
346 struct community_list_master *cm = NULL;
347 struct community_entry *replace;
348 struct community_entry *point;
349
350 cm = community_list_master_lookup(ch, master);
351
352 /* Automatic assignment of seq no. */
353 if (entry->seq == COMMUNITY_SEQ_NUMBER_AUTO)
354 entry->seq = bgp_clist_new_seq_get(list);
355
356 if (list->tail && entry->seq > list->tail->seq)
357 point = NULL;
358 else {
359 replace = bgp_clist_seq_check(list, entry->seq);
360 if (replace)
361 community_list_entry_delete(cm, list, entry);
362
363 /* Check insert point. */
364 for (point = list->head; point; point = point->next)
365 if (point->seq >= entry->seq)
366 break;
367 }
368
369 /* In case of this is the first element of the list. */
370 entry->next = point;
371
372 if (point) {
373 if (point->prev)
374 point->prev->next = entry;
375 else
376 list->head = entry;
377
378 entry->prev = point->prev;
379 point->prev = entry;
380 } else {
381 if (list->tail)
382 list->tail->next = entry;
383 else
384 list->head = entry;
385
386 entry->prev = list->tail;
387 list->tail = entry;
388 }
389}
390
718e3744 391/* Lookup community-list entry from the list. */
392static struct community_entry *
d62a17ae 393community_list_entry_lookup(struct community_list *list, const void *arg,
394 int direct)
718e3744 395{
d62a17ae 396 struct community_entry *entry;
397
398 for (entry = list->head; entry; entry = entry->next) {
399 switch (entry->style) {
400 case COMMUNITY_LIST_STANDARD:
401 if (entry->direct == direct
402 && community_cmp(entry->u.com, arg))
403 return entry;
404 break;
405 case EXTCOMMUNITY_LIST_STANDARD:
406 if (entry->direct == direct
407 && ecommunity_cmp(entry->u.ecom, arg))
408 return entry;
409 break;
410 case LARGE_COMMUNITY_LIST_STANDARD:
411 if (entry->direct == direct
412 && lcommunity_cmp(entry->u.lcom, arg))
413 return entry;
414 break;
415 case COMMUNITY_LIST_EXPANDED:
416 case EXTCOMMUNITY_LIST_EXPANDED:
417 case LARGE_COMMUNITY_LIST_EXPANDED:
418 if (entry->direct == direct
419 && strcmp(entry->config, arg) == 0)
420 return entry;
421 break;
422 default:
423 break;
424 }
425 }
426 return NULL;
718e3744 427}
6b0655a2 428
d62a17ae 429static char *community_str_get(struct community *com, int i)
5cbea288 430{
d7c0a89a
QY
431 uint32_t comval;
432 uint16_t as;
433 uint16_t val;
d62a17ae 434 char *str;
d62a17ae 435
d7c0a89a 436 memcpy(&comval, com_nthval(com, i), sizeof(uint32_t));
d62a17ae 437 comval = ntohl(comval);
438
439 switch (comval) {
440 case COMMUNITY_INTERNET:
aeab4a80 441 str = XSTRDUP(MTYPE_COMMUNITY_STR, "internet");
d62a17ae 442 break;
aa861c10 443 case COMMUNITY_GSHUT:
aeab4a80 444 str = XSTRDUP(MTYPE_COMMUNITY_STR, "graceful-shutdown");
aa861c10
C
445 break;
446 case COMMUNITY_ACCEPT_OWN:
aeab4a80 447 str = XSTRDUP(MTYPE_COMMUNITY_STR, "accept-own");
aa861c10
C
448 break;
449 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4:
aeab4a80
QY
450 str = XSTRDUP(MTYPE_COMMUNITY_STR,
451 "route-filter-translated-v4");
aa861c10
C
452 break;
453 case COMMUNITY_ROUTE_FILTER_v4:
aeab4a80 454 str = XSTRDUP(MTYPE_COMMUNITY_STR, "route-filter-v4");
aa861c10
C
455 break;
456 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6:
aeab4a80
QY
457 str = XSTRDUP(MTYPE_COMMUNITY_STR,
458 "route-filter-translated-v6");
aa861c10
C
459 break;
460 case COMMUNITY_ROUTE_FILTER_v6:
aeab4a80 461 str = XSTRDUP(MTYPE_COMMUNITY_STR, "route-filter-v6");
aa861c10
C
462 break;
463 case COMMUNITY_LLGR_STALE:
aeab4a80 464 str = XSTRDUP(MTYPE_COMMUNITY_STR, "llgr-stale");
aa861c10
C
465 break;
466 case COMMUNITY_NO_LLGR:
aeab4a80 467 str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-llgr");
aa861c10
C
468 break;
469 case COMMUNITY_ACCEPT_OWN_NEXTHOP:
aeab4a80 470 str = XSTRDUP(MTYPE_COMMUNITY_STR, "accept-own-nexthop");
aa861c10
C
471 break;
472 case COMMUNITY_BLACKHOLE:
aeab4a80 473 str = XSTRDUP(MTYPE_COMMUNITY_STR, "blackhole");
aa861c10 474 break;
d62a17ae 475 case COMMUNITY_NO_EXPORT:
aeab4a80 476 str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-export");
d62a17ae 477 break;
478 case COMMUNITY_NO_ADVERTISE:
aeab4a80 479 str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-advertise");
d62a17ae 480 break;
481 case COMMUNITY_LOCAL_AS:
aeab4a80 482 str = XSTRDUP(MTYPE_COMMUNITY_STR, "local-AS");
d62a17ae 483 break;
aa861c10 484 case COMMUNITY_NO_PEER:
aeab4a80 485 str = XSTRDUP(MTYPE_COMMUNITY_STR, "no-peer");
7f323236 486 break;
809d6365 487 default:
aeab4a80 488 str = XSTRDUP(MTYPE_COMMUNITY_STR, "65536:65535");
d62a17ae 489 as = (comval >> 16) & 0xFFFF;
490 val = comval & 0xFFFF;
aeab4a80 491 snprintf(str, strlen(str), "%u:%d", as, val);
d62a17ae 492 break;
493 }
5cbea288 494
d62a17ae 495 return str;
5cbea288
DS
496}
497
498/* Internal function to perform regular expression match for
2acb4ac2 499 * a single community. */
88f1c947 500static bool community_regexp_include(regex_t *reg, struct community *com, int i)
5cbea288 501{
d62a17ae 502 char *str;
503 int rv;
5cbea288 504
d62a17ae 505 /* When there is no communities attribute it is treated as empty string.
506 */
507 if (com == NULL || com->size == 0)
508 str = XSTRDUP(MTYPE_COMMUNITY_STR, "");
509 else
510 str = community_str_get(com, i);
5cbea288 511
d62a17ae 512 /* Regular expression match. */
513 rv = regexec(reg, str, 0, NULL, 0);
b84ee83b 514
d62a17ae 515 XFREE(MTYPE_COMMUNITY_STR, str);
b84ee83b 516
88f1c947 517 return rv == 0;
5cbea288
DS
518}
519
718e3744 520/* Internal function to perform regular expression match for community
521 attribute. */
88f1c947 522static bool community_regexp_match(struct community *com, regex_t *reg)
718e3744 523{
d62a17ae 524 const char *str;
718e3744 525
d62a17ae 526 /* When there is no communities attribute it is treated as empty
527 string. */
528 if (com == NULL || com->size == 0)
529 str = "";
530 else
a69ea8ae 531 str = community_str(com, false);
718e3744 532
d62a17ae 533 /* Regular expression match. */
534 if (regexec(reg, str, 0, NULL, 0) == 0)
88f1c947 535 return true;
718e3744 536
d62a17ae 537 /* No match. */
88f1c947 538 return false;
718e3744 539}
540
d62a17ae 541static char *lcommunity_str_get(struct lcommunity *lcom, int i)
57d187bc 542{
d62a17ae 543 struct lcommunity_val lcomval;
d7c0a89a
QY
544 uint32_t globaladmin;
545 uint32_t localdata1;
546 uint32_t localdata2;
d62a17ae 547 char *str;
1be1693e 548 const uint8_t *ptr;
d62a17ae 549 char *pnt;
550
ff9104a2 551 ptr = lcom->val + (i * LCOMMUNITY_SIZE);
d62a17ae 552
553 memcpy(&lcomval, ptr, LCOMMUNITY_SIZE);
554
555 /* Allocate memory. 48 bytes taken off bgp_lcommunity.c */
556 str = pnt = XMALLOC(MTYPE_LCOMMUNITY_STR, 48);
557
d7c0a89a 558 ptr = (uint8_t *)lcomval.val;
937652c6
DL
559 ptr = ptr_get_be32(ptr, &globaladmin);
560 ptr = ptr_get_be32(ptr, &localdata1);
561 ptr = ptr_get_be32(ptr, &localdata2);
562 (void)ptr; /* consume value */
d62a17ae 563
564 sprintf(pnt, "%u:%u:%u", globaladmin, localdata1, localdata2);
565 pnt += strlen(pnt);
566 *pnt = '\0';
567
568 return str;
57d187bc
JS
569}
570
571/* Internal function to perform regular expression match for
2acb4ac2 572 * a single community. */
88f1c947
DA
573static bool lcommunity_regexp_include(regex_t *reg, struct lcommunity *lcom,
574 int i)
57d187bc 575{
d62a17ae 576 char *str;
577
578 /* When there is no communities attribute it is treated as empty string.
579 */
580 if (lcom == NULL || lcom->size == 0)
581 str = XSTRDUP(MTYPE_LCOMMUNITY_STR, "");
582 else
583 str = lcommunity_str_get(lcom, i);
584
585 /* Regular expression match. */
586 if (regexec(reg, str, 0, NULL, 0) == 0) {
587 XFREE(MTYPE_LCOMMUNITY_STR, str);
88f1c947 588 return true;
d62a17ae 589 }
57d187bc 590
d62a17ae 591 XFREE(MTYPE_LCOMMUNITY_STR, str);
592 /* No match. */
88f1c947 593 return false;
57d187bc
JS
594}
595
88f1c947 596static bool lcommunity_regexp_match(struct lcommunity *com, regex_t *reg)
57d187bc 597{
d62a17ae 598 const char *str;
57d187bc 599
d62a17ae 600 /* When there is no communities attribute it is treated as empty
601 string. */
602 if (com == NULL || com->size == 0)
603 str = "";
604 else
8d9b8ed9 605 str = lcommunity_str(com, false);
57d187bc 606
d62a17ae 607 /* Regular expression match. */
608 if (regexec(reg, str, 0, NULL, 0) == 0)
88f1c947 609 return true;
57d187bc 610
d62a17ae 611 /* No match. */
88f1c947 612 return false;
57d187bc
JS
613}
614
615
88f1c947 616static bool ecommunity_regexp_match(struct ecommunity *ecom, regex_t *reg)
8708b74f 617{
d62a17ae 618 const char *str;
8708b74f 619
d62a17ae 620 /* When there is no communities attribute it is treated as empty
621 string. */
622 if (ecom == NULL || ecom->size == 0)
623 str = "";
624 else
625 str = ecommunity_str(ecom);
8708b74f 626
d62a17ae 627 /* Regular expression match. */
628 if (regexec(reg, str, 0, NULL, 0) == 0)
88f1c947 629 return true;
8708b74f 630
d62a17ae 631 /* No match. */
88f1c947 632 return false;
8708b74f 633}
634
ffd0c037 635#if 0
718e3744 636/* Delete community attribute using regular expression match. Return
637 modified communites attribute. */
638static struct community *
8708b74f 639community_regexp_delete (struct community *com, regex_t * reg)
718e3744 640{
aa861c10
C
641 int i;
642 uint32_t comval;
643 /* Maximum is "65535:65535" + '\0'. */
644 char c[12];
645 const char *str;
646
647 if (!com)
648 return NULL;
649
650 i = 0;
651 while (i < com->size)
652 {
0d6f7fd6 653 memcpy (&comval, com_nthval (com, i), sizeof(uint32_t));
aa861c10
C
654 comval = ntohl (comval);
655
656 switch (comval) {
657 case COMMUNITY_INTERNET:
658 str = "internet";
659 break;
660 case COMMUNITY_ACCEPT_OWN:
661 str = "accept-own";
662 break;
663 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4:
664 str = "route-filter-translated-v4";
665 break;
666 case COMMUNITY_ROUTE_FILTER_v4:
667 str = "route-filter-v4";
668 break;
669 case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6:
670 str = "route-filter-translated-v6";
671 break;
672 case COMMUNITY_ROUTE_FILTER_v6:
673 str = "route-filter-v6";
674 break;
675 case COMMUNITY_LLGR_STALE:
676 str = "llgr-stale";
677 break;
678 case COMMUNITY_NO_LLGR:
679 str = "no-llgr";
680 break;
681 case COMMUNITY_ACCEPT_OWN_NEXTHOP:
682 str = "accept-own-nexthop";
683 break;
684 case COMMUNITY_BLACKHOLE:
685 str = "blackhole";
686 break;
687 case COMMUNITY_NO_EXPORT:
688 str = "no-export";
689 break;
690 case COMMUNITY_NO_ADVERTISE:
691 str = "no-advertise";
692 break;
693 case COMMUNITY_LOCAL_AS:
694 str = "local-AS";
695 break;
696 case COMMUNITY_NO_PEER:
697 str = "no-peer";
698 break;
699 default:
700 sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF,
701 comval & 0xFFFF);
702 str = c;
703 break;
704 }
705
706 if (regexec (reg, str, 0, NULL, 0) == 0)
707 community_del_val (com, com_nthval (com, i));
708 else
709 i++;
710 }
711 return com;
718e3744 712}
ffd0c037 713#endif
718e3744 714
715/* When given community attribute matches to the community-list return
716 1 else return 0. */
88f1c947 717bool community_list_match(struct community *com, struct community_list *list)
718e3744 718{
d62a17ae 719 struct community_entry *entry;
720
721 for (entry = list->head; entry; entry = entry->next) {
722 if (entry->any)
88f1c947 723 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 724
725 if (entry->style == COMMUNITY_LIST_STANDARD) {
726 if (community_include(entry->u.com, COMMUNITY_INTERNET))
88f1c947 727 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 728
729 if (community_match(com, entry->u.com))
88f1c947 730 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 731 } else if (entry->style == COMMUNITY_LIST_EXPANDED) {
732 if (community_regexp_match(com, entry->reg))
88f1c947 733 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 734 }
735 }
88f1c947 736 return false;
8708b74f 737}
738
88f1c947 739bool lcommunity_list_match(struct lcommunity *lcom, struct community_list *list)
57d187bc 740{
d62a17ae 741 struct community_entry *entry;
742
743 for (entry = list->head; entry; entry = entry->next) {
744 if (entry->any)
88f1c947 745 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 746
747 if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) {
748 if (lcommunity_match(lcom, entry->u.lcom))
88f1c947 749 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 750 } else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) {
751 if (lcommunity_regexp_match(lcom, entry->reg))
88f1c947 752 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 753 }
754 }
88f1c947 755 return false;
57d187bc
JS
756}
757
f8463998 758
759/* Perform exact matching. In case of expanded large-community-list, do
760 * same thing as lcommunity_list_match().
761 */
88f1c947
DA
762bool lcommunity_list_exact_match(struct lcommunity *lcom,
763 struct community_list *list)
f8463998 764{
765 struct community_entry *entry;
766
767 for (entry = list->head; entry; entry = entry->next) {
768 if (entry->any)
88f1c947 769 return entry->direct == COMMUNITY_PERMIT;
f8463998 770
771 if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) {
772 if (lcommunity_cmp(lcom, entry->u.com))
88f1c947 773 return entry->direct == COMMUNITY_PERMIT;
f8463998 774 } else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) {
775 if (lcommunity_regexp_match(lcom, entry->reg))
88f1c947 776 return entry->direct == COMMUNITY_PERMIT;
f8463998 777 }
778 }
88f1c947 779 return false;
f8463998 780}
781
88f1c947 782bool ecommunity_list_match(struct ecommunity *ecom, struct community_list *list)
8708b74f 783{
d62a17ae 784 struct community_entry *entry;
785
786 for (entry = list->head; entry; entry = entry->next) {
787 if (entry->any)
88f1c947 788 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 789
790 if (entry->style == EXTCOMMUNITY_LIST_STANDARD) {
791 if (ecommunity_match(ecom, entry->u.ecom))
88f1c947 792 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 793 } else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED) {
794 if (ecommunity_regexp_match(ecom, entry->reg))
88f1c947 795 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 796 }
797 }
88f1c947 798 return false;
718e3744 799}
800
801/* Perform exact matching. In case of expanded community-list, do
802 same thing as community_list_match(). */
88f1c947
DA
803bool community_list_exact_match(struct community *com,
804 struct community_list *list)
718e3744 805{
d62a17ae 806 struct community_entry *entry;
807
808 for (entry = list->head; entry; entry = entry->next) {
809 if (entry->any)
88f1c947 810 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 811
812 if (entry->style == COMMUNITY_LIST_STANDARD) {
813 if (community_include(entry->u.com, COMMUNITY_INTERNET))
88f1c947 814 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 815
816 if (community_cmp(com, entry->u.com))
88f1c947 817 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 818 } else if (entry->style == COMMUNITY_LIST_EXPANDED) {
819 if (community_regexp_match(com, entry->reg))
88f1c947 820 return entry->direct == COMMUNITY_PERMIT;
d62a17ae 821 }
822 }
88f1c947 823 return false;
718e3744 824}
825
8708b74f 826/* Delete all permitted communities in the list from com. */
d62a17ae 827struct community *community_list_match_delete(struct community *com,
828 struct community_list *list)
718e3744 829{
d62a17ae 830 struct community_entry *entry;
d7c0a89a
QY
831 uint32_t val;
832 uint32_t com_index_to_delete[com->size];
d62a17ae 833 int delete_index = 0;
834 int i;
835
836 /* Loop over each community value and evaluate each against the
837 * community-list. If we need to delete a community value add its index
ceead39c 838 * to com_index_to_delete.
d62a17ae 839 */
840 for (i = 0; i < com->size; i++) {
841 val = community_val_get(com, i);
842
843 for (entry = list->head; entry; entry = entry->next) {
844 if (entry->any) {
845 if (entry->direct == COMMUNITY_PERMIT) {
846 com_index_to_delete[delete_index] = i;
847 delete_index++;
848 }
849 break;
850 }
851
852 else if ((entry->style == COMMUNITY_LIST_STANDARD)
853 && (community_include(entry->u.com,
854 COMMUNITY_INTERNET)
855 || community_include(entry->u.com, val))) {
856 if (entry->direct == COMMUNITY_PERMIT) {
857 com_index_to_delete[delete_index] = i;
858 delete_index++;
859 }
860 break;
861 }
862
863 else if ((entry->style == COMMUNITY_LIST_EXPANDED)
864 && community_regexp_include(entry->reg, com,
865 i)) {
866 if (entry->direct == COMMUNITY_PERMIT) {
867 com_index_to_delete[delete_index] = i;
868 delete_index++;
869 }
870 break;
871 }
872 }
873 }
5cbea288 874
d62a17ae 875 /* Delete all of the communities we flagged for deletion */
876 for (i = delete_index - 1; i >= 0; i--) {
877 val = community_val_get(com, com_index_to_delete[i]);
0743b61d 878 val = htonl(val);
d62a17ae 879 community_del_val(com, &val);
880 }
5cbea288 881
d62a17ae 882 return com;
718e3744 883}
884
885/* To avoid duplicated entry in the community-list, this function
886 compares specified entry to existing entry. */
88f1c947
DA
887static bool community_list_dup_check(struct community_list *list,
888 struct community_entry *new)
718e3744 889{
d62a17ae 890 struct community_entry *entry;
891
892 for (entry = list->head; entry; entry = entry->next) {
893 if (entry->style != new->style)
894 continue;
895
896 if (entry->direct != new->direct)
897 continue;
898
899 if (entry->any != new->any)
900 continue;
901
902 if (entry->any)
88f1c947 903 return true;
d62a17ae 904
905 switch (entry->style) {
906 case COMMUNITY_LIST_STANDARD:
907 if (community_cmp(entry->u.com, new->u.com))
88f1c947 908 return true;
d62a17ae 909 break;
910 case LARGE_COMMUNITY_LIST_STANDARD:
911 if (lcommunity_cmp(entry->u.lcom, new->u.lcom))
88f1c947 912 return true;
d62a17ae 913 break;
914 case EXTCOMMUNITY_LIST_STANDARD:
915 if (ecommunity_cmp(entry->u.ecom, new->u.ecom))
88f1c947 916 return true;
d62a17ae 917 break;
918 case COMMUNITY_LIST_EXPANDED:
919 case EXTCOMMUNITY_LIST_EXPANDED:
920 case LARGE_COMMUNITY_LIST_EXPANDED:
921 if (strcmp(entry->config, new->config) == 0)
88f1c947 922 return true;
d62a17ae 923 break;
924 default:
925 break;
926 }
927 }
88f1c947 928 return false;
718e3744 929}
6b0655a2 930
718e3744 931/* Set community-list. */
d62a17ae 932int community_list_set(struct community_list_handler *ch, const char *name,
2f8cc0e5 933 const char *str, const char *seq, int direct, int style)
718e3744 934{
d62a17ae 935 struct community_entry *entry = NULL;
936 struct community_list *list;
937 struct community *com = NULL;
938 regex_t *regex = NULL;
2f8cc0e5
DA
939 int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
940
941 if (seq)
942 seqnum = (int64_t)atol(seq);
d62a17ae 943
944 /* Get community list. */
945 list = community_list_get(ch, name, COMMUNITY_LIST_MASTER);
946
947 /* When community-list already has entry, new entry should have same
948 style. If you want to have mixed style community-list, you can
949 comment out this check. */
950 if (!community_list_empty_p(list)) {
951 struct community_entry *first;
952
953 first = list->head;
954
955 if (style != first->style) {
956 return (first->style == COMMUNITY_LIST_STANDARD
957 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
958 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
959 }
fee6e4e4 960 }
718e3744 961
d62a17ae 962 if (str) {
963 if (style == COMMUNITY_LIST_STANDARD)
964 com = community_str2com(str);
965 else
966 regex = bgp_regcomp(str);
8708b74f 967
d62a17ae 968 if (!com && !regex)
969 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
970 }
718e3744 971
d62a17ae 972 entry = community_entry_new();
973 entry->direct = direct;
974 entry->style = style;
d3f6c580 975 entry->any = (str ? false : true);
d62a17ae 976 entry->u.com = com;
977 entry->reg = regex;
2f8cc0e5 978 entry->seq = seqnum;
d62a17ae 979 entry->config =
980 (regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
981
982 /* Do not put duplicated community entry. */
983 if (community_list_dup_check(list, entry))
984 community_entry_free(entry);
985 else {
2f8cc0e5
DA
986 community_list_entry_add(list, entry, ch,
987 COMMUNITY_LIST_MASTER);
d62a17ae 988 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_ADDED);
989 }
718e3744 990
d62a17ae 991 return 0;
718e3744 992}
993
813d4307 994/* Unset community-list */
d62a17ae 995int community_list_unset(struct community_list_handler *ch, const char *name,
2f8cc0e5
DA
996 const char *str, const char *seq, int direct,
997 int style)
718e3744 998{
3571a6a2 999 struct community_list_master *cm = NULL;
d62a17ae 1000 struct community_entry *entry = NULL;
1001 struct community_list *list;
1002 struct community *com = NULL;
1003
1004 /* Lookup community list. */
e237b0d2 1005 list = community_list_lookup(ch, name, 0, COMMUNITY_LIST_MASTER);
d62a17ae 1006 if (list == NULL)
1007 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
1008
3571a6a2 1009 cm = community_list_master_lookup(ch, COMMUNITY_LIST_MASTER);
d62a17ae 1010 /* Delete all of entry belongs to this community-list. */
7298a8e1 1011 if (!str) {
3571a6a2 1012 community_list_delete(cm, list);
d62a17ae 1013 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
1014 return 0;
1015 }
718e3744 1016
7298a8e1
QY
1017 if (style == COMMUNITY_LIST_STANDARD)
1018 com = community_str2com(str);
718e3744 1019
d62a17ae 1020 if (com) {
1021 entry = community_list_entry_lookup(list, com, direct);
3c1f53de 1022 community_free(&com);
d62a17ae 1023 } else
1024 entry = community_list_entry_lookup(list, str, direct);
fee6e4e4 1025
d62a17ae 1026 if (!entry)
1027 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
718e3744 1028
3571a6a2 1029 community_list_entry_delete(cm, list, entry);
d62a17ae 1030 route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED);
718e3744 1031
d62a17ae 1032 return 0;
718e3744 1033}
1034
57d187bc 1035/* Delete all permitted large communities in the list from com. */
d62a17ae 1036struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
1037 struct community_list *list)
57d187bc 1038{
d62a17ae 1039 struct community_entry *entry;
d7c0a89a
QY
1040 uint32_t com_index_to_delete[lcom->size];
1041 uint8_t *ptr;
d62a17ae 1042 int delete_index = 0;
1043 int i;
1044
1045 /* Loop over each lcommunity value and evaluate each against the
1046 * community-list. If we need to delete a community value add its index
ceead39c 1047 * to com_index_to_delete.
d62a17ae 1048 */
d62a17ae 1049 for (i = 0; i < lcom->size; i++) {
534fc195 1050 ptr = lcom->val + (i * LCOMMUNITY_SIZE);
d62a17ae 1051 for (entry = list->head; entry; entry = entry->next) {
1052 if (entry->any) {
1053 if (entry->direct == COMMUNITY_PERMIT) {
1054 com_index_to_delete[delete_index] = i;
1055 delete_index++;
1056 }
1057 break;
1058 }
1059
1060 else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
1061 && lcommunity_include(entry->u.lcom, ptr)) {
1062 if (entry->direct == COMMUNITY_PERMIT) {
1063 com_index_to_delete[delete_index] = i;
1064 delete_index++;
1065 }
1066 break;
1067 }
1068
cde8d696 1069 else if ((entry->style == LARGE_COMMUNITY_LIST_EXPANDED)
d62a17ae 1070 && lcommunity_regexp_include(entry->reg, lcom,
1071 i)) {
1072 if (entry->direct == COMMUNITY_PERMIT) {
1073 com_index_to_delete[delete_index] = i;
1074 delete_index++;
1075 }
1076 break;
1077 }
1078 }
1079 }
57d187bc 1080
d62a17ae 1081 /* Delete all of the communities we flagged for deletion */
d62a17ae 1082 for (i = delete_index - 1; i >= 0; i--) {
0a7dce9b 1083 ptr = lcom->val + (com_index_to_delete[i] * LCOMMUNITY_SIZE);
d62a17ae 1084 lcommunity_del_val(lcom, ptr);
1085 }
57d187bc 1086
d62a17ae 1087 return lcom;
57d187bc
JS
1088}
1089
5bd66e2d 1090/* Helper to check if every octet do not exceed UINT_MAX */
88f1c947 1091static bool lcommunity_list_valid(const char *community)
5bd66e2d 1092{
bc2c9ae6
DA
1093 int octets;
1094 char **splits, **communities;
1095 int num, num_communities;
5bd66e2d 1096
bc2c9ae6 1097 frrstr_split(community, " ", &communities, &num_communities);
5bd66e2d 1098
bc2c9ae6
DA
1099 for (int j = 0; j < num_communities; j++) {
1100 octets = 0;
1101 frrstr_split(communities[j], ":", &splits, &num);
1102
1103 for (int i = 0; i < num; i++) {
1104 if (strtoul(splits[i], NULL, 10) > UINT_MAX)
1105 return false;
5bd66e2d 1106
bc2c9ae6
DA
1107 if (strlen(splits[i]) == 0)
1108 return false;
1109
1110 octets++;
1111 XFREE(MTYPE_TMP, splits[i]);
1112 }
1113 XFREE(MTYPE_TMP, splits);
1114
1115 if (octets < 3)
88f1c947 1116 return false;
5bd66e2d 1117
bc2c9ae6 1118 XFREE(MTYPE_TMP, communities[j]);
5bd66e2d 1119 }
bc2c9ae6 1120 XFREE(MTYPE_TMP, communities);
5bd66e2d 1121
88f1c947 1122 return true;
5bd66e2d
DA
1123}
1124
57d187bc 1125/* Set lcommunity-list. */
d62a17ae 1126int lcommunity_list_set(struct community_list_handler *ch, const char *name,
2f8cc0e5 1127 const char *str, const char *seq, int direct, int style)
57d187bc 1128{
d62a17ae 1129 struct community_entry *entry = NULL;
1130 struct community_list *list;
1131 struct lcommunity *lcom = NULL;
1132 regex_t *regex = NULL;
2f8cc0e5
DA
1133 int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
1134
1135 if (seq)
1136 seqnum = (int64_t)atol(seq);
d62a17ae 1137
1138 /* Get community list. */
1139 list = community_list_get(ch, name, LARGE_COMMUNITY_LIST_MASTER);
1140
1141 /* When community-list already has entry, new entry should have same
1142 style. If you want to have mixed style community-list, you can
1143 comment out this check. */
1144 if (!community_list_empty_p(list)) {
1145 struct community_entry *first;
1146
1147 first = list->head;
1148
1149 if (style != first->style) {
1150 return (first->style == COMMUNITY_LIST_STANDARD
1151 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
1152 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
1153 }
1154 }
57d187bc 1155
d62a17ae 1156 if (str) {
5bd66e2d
DA
1157 if (!lcommunity_list_valid(str))
1158 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
1159
d62a17ae 1160 if (style == LARGE_COMMUNITY_LIST_STANDARD)
1161 lcom = lcommunity_str2com(str);
1162 else
1163 regex = bgp_regcomp(str);
57d187bc 1164
d62a17ae 1165 if (!lcom && !regex)
1166 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
1167 }
57d187bc 1168
d62a17ae 1169 entry = community_entry_new();
1170 entry->direct = direct;
1171 entry->style = style;
d3f6c580 1172 entry->any = (str ? false : true);
d62a17ae 1173 entry->u.lcom = lcom;
1174 entry->reg = regex;
2f8cc0e5 1175 entry->seq = seqnum;
8d9b8ed9
PM
1176 entry->config =
1177 (regex ? XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL);
d62a17ae 1178
1179 /* Do not put duplicated community entry. */
1180 if (community_list_dup_check(list, entry))
1181 community_entry_free(entry);
35f6f850 1182 else {
2f8cc0e5
DA
1183 community_list_entry_add(list, entry, ch,
1184 LARGE_COMMUNITY_LIST_MASTER);
35f6f850 1185 route_map_notify_dependencies(name, RMAP_EVENT_LLIST_ADDED);
1186 }
d62a17ae 1187
1188 return 0;
57d187bc
JS
1189}
1190
1191/* Unset community-list. When str is NULL, delete all of
1192 community-list entry belongs to the specified name. */
d62a17ae 1193int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
2f8cc0e5
DA
1194 const char *str, const char *seq, int direct,
1195 int style)
57d187bc 1196{
3571a6a2 1197 struct community_list_master *cm = NULL;
d62a17ae 1198 struct community_entry *entry = NULL;
1199 struct community_list *list;
1200 struct lcommunity *lcom = NULL;
1201 regex_t *regex = NULL;
1202
1203 /* Lookup community list. */
e237b0d2 1204 list = community_list_lookup(ch, name, 0, LARGE_COMMUNITY_LIST_MASTER);
d62a17ae 1205 if (list == NULL)
1206 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
1207
3571a6a2 1208 cm = community_list_master_lookup(ch, LARGE_COMMUNITY_LIST_MASTER);
d62a17ae 1209 /* Delete all of entry belongs to this community-list. */
1210 if (!str) {
3571a6a2 1211 community_list_delete(cm, list);
35f6f850 1212 route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED);
d62a17ae 1213 return 0;
1214 }
57d187bc 1215
d62a17ae 1216 if (style == LARGE_COMMUNITY_LIST_STANDARD)
1217 lcom = lcommunity_str2com(str);
1218 else
1219 regex = bgp_regcomp(str);
57d187bc 1220
d62a17ae 1221 if (!lcom && !regex)
1222 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
57d187bc 1223
d62a17ae 1224 if (lcom)
1225 entry = community_list_entry_lookup(list, lcom, direct);
1226 else
1227 entry = community_list_entry_lookup(list, str, direct);
57d187bc 1228
d62a17ae 1229 if (lcom)
1230 lcommunity_free(&lcom);
1231 if (regex)
1232 bgp_regex_free(regex);
57d187bc 1233
d62a17ae 1234 if (!entry)
1235 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
57d187bc 1236
3571a6a2 1237 community_list_entry_delete(cm, list, entry);
35f6f850 1238 route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED);
57d187bc 1239
d62a17ae 1240 return 0;
57d187bc
JS
1241}
1242
718e3744 1243/* Set extcommunity-list. */
d62a17ae 1244int extcommunity_list_set(struct community_list_handler *ch, const char *name,
2f8cc0e5
DA
1245 const char *str, const char *seq, int direct,
1246 int style)
718e3744 1247{
d62a17ae 1248 struct community_entry *entry = NULL;
1249 struct community_list *list;
1250 struct ecommunity *ecom = NULL;
1251 regex_t *regex = NULL;
2f8cc0e5
DA
1252 int64_t seqnum = COMMUNITY_SEQ_NUMBER_AUTO;
1253
1254 if (seq)
1255 seqnum = (int64_t)atol(seq);
718e3744 1256
fa301630 1257 if (str == NULL)
1258 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
1259
d62a17ae 1260 /* Get community list. */
1261 list = community_list_get(ch, name, EXTCOMMUNITY_LIST_MASTER);
718e3744 1262
d62a17ae 1263 /* When community-list already has entry, new entry should have same
1264 style. If you want to have mixed style community-list, you can
1265 comment out this check. */
1266 if (!community_list_empty_p(list)) {
1267 struct community_entry *first;
718e3744 1268
d62a17ae 1269 first = list->head;
718e3744 1270
d62a17ae 1271 if (style != first->style) {
1272 return (first->style == EXTCOMMUNITY_LIST_STANDARD
1273 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
1274 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
1275 }
fee6e4e4 1276 }
718e3744 1277
d62a17ae 1278 if (style == EXTCOMMUNITY_LIST_STANDARD)
1279 ecom = ecommunity_str2com(str, 0, 1);
1280 else
1281 regex = bgp_regcomp(str);
1282
1283 if (!ecom && !regex)
1284 return COMMUNITY_LIST_ERR_MALFORMED_VAL;
1285
1286 if (ecom)
1287 ecom->str =
1288 ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
1289
1290 entry = community_entry_new();
1291 entry->direct = direct;
1292 entry->style = style;
d3f6c580 1293 entry->any = false;
d62a17ae 1294 if (ecom)
1295 entry->config = ecommunity_ecom2str(
1296 ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
1297 else if (regex)
1298 entry->config = XSTRDUP(MTYPE_COMMUNITY_LIST_CONFIG, str);
1299
1300 entry->u.ecom = ecom;
1301 entry->reg = regex;
2f8cc0e5 1302 entry->seq = seqnum;
d62a17ae 1303
1304 /* Do not put duplicated community entry. */
1305 if (community_list_dup_check(list, entry))
1306 community_entry_free(entry);
1307 else {
2f8cc0e5
DA
1308 community_list_entry_add(list, entry, ch,
1309 EXTCOMMUNITY_LIST_MASTER);
d62a17ae 1310 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_ADDED);
1311 }
718e3744 1312
d62a17ae 1313 return 0;
718e3744 1314}
1315
7298a8e1
QY
1316/* Unset extcommunity-list.
1317 *
1318 * When str is NULL, delete all extcommunity-list entries belonging to the
1319 * specified name.
1320 */
d62a17ae 1321int extcommunity_list_unset(struct community_list_handler *ch, const char *name,
2f8cc0e5
DA
1322 const char *str, const char *seq, int direct,
1323 int style)
718e3744 1324{
3571a6a2 1325 struct community_list_master *cm = NULL;
d62a17ae 1326 struct community_entry *entry = NULL;
1327 struct community_list *list;
1328 struct ecommunity *ecom = NULL;
1329
1330 /* Lookup extcommunity list. */
e237b0d2 1331 list = community_list_lookup(ch, name, 0, EXTCOMMUNITY_LIST_MASTER);
d62a17ae 1332 if (list == NULL)
1333 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
1334
3571a6a2 1335 cm = community_list_master_lookup(ch, EXTCOMMUNITY_LIST_MASTER);
d62a17ae 1336 /* Delete all of entry belongs to this extcommunity-list. */
7298a8e1 1337 if (!str) {
3571a6a2 1338 community_list_delete(cm, list);
d62a17ae 1339 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
1340 return 0;
1341 }
718e3744 1342
7298a8e1
QY
1343 if (style == EXTCOMMUNITY_LIST_STANDARD)
1344 ecom = ecommunity_str2com(str, 0, 1);
718e3744 1345
d62a17ae 1346 if (ecom) {
1347 entry = community_list_entry_lookup(list, ecom, direct);
1348 ecommunity_free(&ecom);
1349 } else
1350 entry = community_list_entry_lookup(list, str, direct);
fee6e4e4 1351
d62a17ae 1352 if (!entry)
1353 return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
718e3744 1354
3571a6a2 1355 community_list_entry_delete(cm, list, entry);
d62a17ae 1356 route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED);
718e3744 1357
d62a17ae 1358 return 0;
718e3744 1359}
1360
1361/* Initializa community-list. Return community-list handler. */
d62a17ae 1362struct community_list_handler *community_list_init(void)
718e3744 1363{
d62a17ae 1364 struct community_list_handler *ch;
1365 ch = XCALLOC(MTYPE_COMMUNITY_LIST_HANDLER,
1366 sizeof(struct community_list_handler));
3571a6a2
DS
1367
1368 ch->community_list.hash =
1369 hash_create_size(4, bgp_clist_hash_key_community_list,
1370 bgp_clist_hash_cmp_community_list,
1371 "Community List Number Quick Lookup");
1372
1373 ch->extcommunity_list.hash =
1374 hash_create_size(4, bgp_clist_hash_key_community_list,
1375 bgp_clist_hash_cmp_community_list,
1376 "Extended Community List Quick Lookup");
1377
1378 ch->lcommunity_list.hash =
1379 hash_create_size(4, bgp_clist_hash_key_community_list,
1380 bgp_clist_hash_cmp_community_list,
1381 "Large Community List Quick Lookup");
1382
d62a17ae 1383 return ch;
718e3744 1384}
1385
1386/* Terminate community-list. */
d62a17ae 1387void community_list_terminate(struct community_list_handler *ch)
718e3744 1388{
d62a17ae 1389 struct community_list_master *cm;
1390 struct community_list *list;
1391
1392 cm = &ch->community_list;
1393 while ((list = cm->num.head) != NULL)
3571a6a2 1394 community_list_delete(cm, list);
d62a17ae 1395 while ((list = cm->str.head) != NULL)
3571a6a2
DS
1396 community_list_delete(cm, list);
1397 hash_free(cm->hash);
d62a17ae 1398
1399 cm = &ch->lcommunity_list;
1400 while ((list = cm->num.head) != NULL)
3571a6a2 1401 community_list_delete(cm, list);
d62a17ae 1402 while ((list = cm->str.head) != NULL)
3571a6a2
DS
1403 community_list_delete(cm, list);
1404 hash_free(cm->hash);
d62a17ae 1405
1406 cm = &ch->extcommunity_list;
1407 while ((list = cm->num.head) != NULL)
3571a6a2 1408 community_list_delete(cm, list);
d62a17ae 1409 while ((list = cm->str.head) != NULL)
3571a6a2
DS
1410 community_list_delete(cm, list);
1411 hash_free(cm->hash);
d62a17ae 1412
1413 XFREE(MTYPE_COMMUNITY_LIST_HANDLER, ch);
718e3744 1414}