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