1/* BGP community-list and extcommunity-list. 2 Copyright (C) 1999 Kunihiro Ishiguro 3 4This file is part of GNU Zebra. 5 6GNU Zebra is free software; you can redistribute it and/or modify it 7under the terms of the GNU General Public License as published by the 8Free Software Foundation; either version 2, or (at your option) any 9later version. 10 11GNU Zebra is distributed in the hope that it will be useful, but 12WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with GNU Zebra; see the file COPYING. If not, write to the Free 18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 1902111-1307, USA. */ 20 21#include <zebra.h> 22 23#include "command.h" 24#include "prefix.h" 25#include "memory.h" 26 27#include "bgpd/bgpd.h" 28#include "bgpd/bgp_community.h" 29#include "bgpd/bgp_ecommunity.h" 30#include "bgpd/bgp_aspath.h" 31#include "bgpd/bgp_regex.h" 32#include "bgpd/bgp_clist.h" 33 34/* Lookup master structure for community-list or 35 extcommunity-list. */ 36struct community_list_master * 37community_list_master_lookup (struct community_list_handler *ch, int style) 38{ 39 if (ch) 40 switch (style) 41 { 42 case COMMUNITY_LIST_STANDARD: 43 case COMMUNITY_LIST_EXPANDED: 44 case COMMUNITY_LIST_AUTO: 45 return &ch->community_list; 46 break; 47 case EXTCOMMUNITY_LIST_STANDARD: 48 case EXTCOMMUNITY_LIST_EXPANDED: 49 case EXTCOMMUNITY_LIST_AUTO: 50 return &ch->extcommunity_list; 51 } 52 return NULL; 53} 54 55/* Allocate a new community list entry. */ 56struct community_entry * 57community_entry_new () 58{ 59 struct community_entry *new; 60 61 new = XMALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry)); 62 memset (new, 0, sizeof (struct community_entry)); 63 return new; 64} 65 66/* Free community list entry. */ 67void 68community_entry_free (struct community_entry *entry) 69{ 70 switch (entry->style) 71 { 72 case COMMUNITY_LIST_STANDARD: 73 if (entry->u.com) 74 community_free (entry->u.com); 75 break; 76 case EXTCOMMUNITY_LIST_STANDARD: 77 if (entry->u.ecom) 78 ecommunity_free (entry->u.ecom); 79 break; 80 case COMMUNITY_LIST_EXPANDED: 81 case EXTCOMMUNITY_LIST_EXPANDED: 82 if (entry->config) 83 XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config); 84 if (entry->reg) 85 bgp_regex_free (entry->reg); 86 default: 87 break; 88 } 89 XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry); 90} 91 92/* Allocate a new community-list. */ 93struct community_list * 94community_list_new () 95{ 96 struct community_list *new; 97 98 new = XMALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list)); 99 memset (new, 0, sizeof (struct community_list)); 100 return new; 101} 102 103/* Free community-list. */ 104void 105community_list_free (struct community_list *list) 106{ 107 if (list->name) 108 XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name); 109 XFREE (MTYPE_COMMUNITY_LIST, list); 110} 111 112struct community_list * 113community_list_insert (struct community_list_handler *ch, 114 char *name, int style) 115{ 116 int i; 117 long number; 118 struct community_list *new; 119 struct community_list *point; 120 struct community_list_list *list; 121 struct community_list_master *cm; 122 123 /* Lookup community-list master. */ 124 cm = community_list_master_lookup (ch, style); 125 if (! cm) 126 return NULL; 127 128 /* Allocate new community_list and copy given name. */ 129 new = community_list_new (); 130 new->name = XSTRDUP (MTYPE_COMMUNITY_LIST_NAME, name); 131 132 /* If name is made by all digit character. We treat it as 133 number. */ 134 for (number = 0, i = 0; i < strlen (name); i++) 135 { 136 if (isdigit ((int) name[i])) 137 number = (number * 10) + (name[i] - '0'); 138 else 139 break; 140 } 141 142 /* In case of name is all digit character */ 143 if (i == strlen (name)) 144 { 145 new->sort = COMMUNITY_LIST_NUMBER; 146 147 /* Set access_list to number list. */ 148 list = &cm->num; 149 150 for (point = list->head; point; point = point->next) 151 if (atol (point->name) >= number) 152 break; 153 } 154 else 155 { 156 new->sort = COMMUNITY_LIST_STRING; 157 158 /* Set access_list to string list. */ 159 list = &cm->str; 160 161 /* Set point to insertion point. */ 162 for (point = list->head; point; point = point->next) 163 if (strcmp (point->name, name) >= 0) 164 break; 165 } 166 167 /* Link to upper list. */ 168 new->parent = list; 169 170 /* In case of this is the first element of master. */ 171 if (list->head == NULL) 172 { 173 list->head = list->tail = new; 174 return new; 175 } 176 177 /* In case of insertion is made at the tail of access_list. */ 178 if (point == NULL) 179 { 180 new->prev = list->tail; 181 list->tail->next = new; 182 list->tail = new; 183 return new; 184 } 185 186 /* In case of insertion is made at the head of access_list. */ 187 if (point == list->head) 188 { 189 new->next = list->head; 190 list->head->prev = new; 191 list->head = new; 192 return new; 193 } 194 195 /* Insertion is made at middle of the access_list. */ 196 new->next = point; 197 new->prev = point->prev; 198 199 if (point->prev) 200 point->prev->next = new; 201 point->prev = new; 202 203 return new; 204} 205 206struct community_list * 207community_list_lookup (struct community_list_handler *ch, 208 char *name, int style) 209{ 210 struct community_list *list; 211 struct community_list_master *cm; 212 213 if (! name) 214 return NULL; 215 216 cm = community_list_master_lookup (ch, style); 217 if (! cm) 218 return NULL; 219 220 for (list = cm->num.head; list; list = list->next) 221 if (strcmp (list->name, name) == 0) 222 return list; 223 for (list = cm->str.head; list; list = list->next) 224 if (strcmp (list->name, name) == 0) 225 return list; 226 227 return NULL; 228} 229 230struct community_list * 231community_list_get (struct community_list_handler *ch, char *name, int style) 232{ 233 struct community_list *list; 234 235 list = community_list_lookup (ch, name, style); 236 if (! list) 237 list = community_list_insert (ch, name, style); 238 return list; 239} 240 241void 242community_list_delete (struct community_list *list) 243{ 244 struct community_list_list *clist; 245 struct community_entry *entry, *next; 246 247 for (entry = list->head; entry; entry = next) 248 { 249 next = entry->next; 250 community_entry_free (entry); 251 } 252 253 clist = list->parent; 254 255 if (list->next) 256 list->next->prev = list->prev; 257 else 258 clist->tail = list->prev; 259 260 if (list->prev) 261 list->prev->next = list->next; 262 else 263 clist->head = list->next; 264 265 community_list_free (list); 266} 267 268int 269community_list_empty_p (struct community_list *list) 270{ 271 return (list->head == NULL && list->tail == NULL) ? 1 : 0; 272} 273 274/* Add community-list entry to the list. */ 275static void 276community_list_entry_add (struct community_list *list, 277 struct community_entry *entry) 278{ 279 entry->next = NULL; 280 entry->prev = list->tail; 281 282 if (list->tail) 283 list->tail->next = entry; 284 else 285 list->head = entry; 286 list->tail = entry; 287} 288 289/* Delete community-list entry from the list. */ 290static void 291community_list_entry_delete (struct community_list *list, 292 struct community_entry *entry, int style) 293{ 294 if (entry->next) 295 entry->next->prev = entry->prev; 296 else 297 list->tail = entry->prev; 298 299 if (entry->prev) 300 entry->prev->next = entry->next; 301 else 302 list->head = entry->next; 303 304 community_entry_free (entry); 305 306 if (community_list_empty_p (list)) 307 community_list_delete (list); 308} 309 310/* Lookup community-list entry from the list. */ 311static struct community_entry * 312community_list_entry_lookup (struct community_list *list, void *arg, 313 int direct) 314{ 315 struct community_entry *entry; 316 317 for (entry = list->head; entry; entry = entry->next) 318 { 319 switch (entry->style) 320 { 321 case COMMUNITY_LIST_STANDARD: 322 if (community_cmp (entry->u.com, arg)) 323 return entry; 324 break; 325 case EXTCOMMUNITY_LIST_STANDARD: 326 if (ecommunity_cmp (entry->u.ecom, arg)) 327 return entry; 328 break; 329 case COMMUNITY_LIST_EXPANDED: 330 case EXTCOMMUNITY_LIST_EXPANDED: 331 if (strcmp (entry->config, arg) == 0) 332 return entry; 333 break; 334 default: 335 break; 336 } 337 } 338 return NULL; 339} 340 341/* Internal function to perform regular expression match for community 342 attribute. */ 343static int 344community_regexp_match (struct community *com, regex_t *reg) 345{ 346 char *str; 347 348 /* When there is no communities attribute it is treated as empty 349 string. */ 350 if (com == NULL || com->size == 0) 351 str = ""; 352 else 353 str = community_str (com); 354 355 /* Regular expression match. */ 356 if (regexec (reg, str, 0, NULL, 0) == 0) 357 return 1; 358 359 /* No match. */ 360 return 0; 361} 362 363/* Delete community attribute using regular expression match. Return 364 modified communites attribute. */ 365static struct community * 366community_regexp_delete (struct community *com, regex_t *reg) 367{ 368 int i; 369 u_int32_t comval; 370 /* Maximum is "65535:65535" + '\0'. */ 371 char c[12]; 372 char *str; 373 374 if (! com) 375 return NULL; 376 377 i = 0; 378 while (i < com->size) 379 { 380 memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); 381 comval = ntohl (comval); 382 383 switch (comval) 384 { 385 case COMMUNITY_INTERNET: 386 str = "internet"; 387 break; 388 case COMMUNITY_NO_EXPORT: 389 str = "no-export"; 390 break; 391 case COMMUNITY_NO_ADVERTISE: 392 str = "no-advertise"; 393 break; 394 case COMMUNITY_LOCAL_AS: 395 str = "local-AS"; 396 break; 397 default: 398 sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF); 399 str = c; 400 break; 401 } 402 403 if (regexec (reg, str, 0, NULL, 0) == 0) 404 community_del_val (com, com_nthval (com, i)); 405 else 406 i++; 407 } 408 return com; 409} 410 411/* When given community attribute matches to the community-list return 412 1 else return 0. */ 413int 414community_list_match (struct community *com, struct community_list *list) 415{ 416 struct community_entry *entry; 417 418 for (entry = list->head; entry; entry = entry->next) 419 { 420 if (entry->any) 421 return entry->direct == COMMUNITY_PERMIT ? 1 : 0; 422 423 if (entry->style == COMMUNITY_LIST_STANDARD) 424 { 425 if (community_include (entry->u.com, COMMUNITY_INTERNET)) 426 return entry->direct == COMMUNITY_PERMIT ? 1 : 0; 427 428 if (community_match (com, entry->u.com)) 429 return entry->direct == COMMUNITY_PERMIT ? 1 : 0; 430 } 431 else if (entry->style == COMMUNITY_LIST_EXPANDED) 432 { 433 if (community_regexp_match (com, entry->reg)) 434 return entry->direct == COMMUNITY_PERMIT ? 1 : 0; 435 } 436 } 437 return 0; 438} 439 440/* Perform exact matching. In case of expanded community-list, do 441 same thing as community_list_match(). */ 442int 443community_list_exact_match (struct community *com, struct community_list *list) 444{ 445 struct community_entry *entry; 446 447 for (entry = list->head; entry; entry = entry->next) 448 { 449 if (entry->any) 450 return entry->direct == COMMUNITY_PERMIT ? 1 : 0; 451 452 if (entry->style == COMMUNITY_LIST_STANDARD) 453 { 454 if (community_include (entry->u.com, COMMUNITY_INTERNET)) 455 return entry->direct == COMMUNITY_PERMIT ? 1 : 0; 456 457 if (community_cmp (com, entry->u.com)) 458 return entry->direct == COMMUNITY_PERMIT ? 1 : 0; 459 } 460 else if (entry->style == COMMUNITY_LIST_EXPANDED) 461 { 462 if (community_regexp_match (com, entry->reg)) 463 return entry->direct == COMMUNITY_PERMIT ? 1 : 0; 464 } 465 } 466 return 0; 467} 468 469/* Delete all permitted communities in the list from com1 */ 470struct community * 471community_list_match_delete (struct community *com, 472 struct community_list *list) 473{ 474 struct community_entry *entry; 475 476 for (entry = list->head; entry; entry = entry->next) 477 { 478 if (entry->any && entry->direct == COMMUNITY_PERMIT) 479 { 480 /* This is a tricky part. Currently only 481 route_set_community_delete() uses this function. In the 482 function com->size is zero, it free the community 483 structure. */ 484 com->size = 0; 485 return com; 486 } 487 488 if (entry->style == COMMUNITY_LIST_STANDARD) 489 { 490 if (entry->direct == COMMUNITY_PERMIT) 491 community_delete (com, entry->u.com); 492 } 493 else if (entry->style == COMMUNITY_LIST_EXPANDED) 494 { 495 if (entry->direct == COMMUNITY_PERMIT) 496 community_regexp_delete (com, entry->reg); 497 } 498 } 499 return com; 500} 501 502/* To avoid duplicated entry in the community-list, this function 503 compares specified entry to existing entry. */ 504int 505community_list_dup_check (struct community_list *list, 506 struct community_entry *new) 507{ 508 struct community_entry *entry; 509 510 for (entry = list->head; entry; entry = entry->next) 511 { 512 if (entry->style != new->style) 513 continue; 514 515 if (entry->direct != new->direct) 516 continue; 517 518 if (entry->any != new->any) 519 continue; 520 521 if (entry->any) 522 return 1; 523 524 switch (entry->style) 525 { 526 case COMMUNITY_LIST_STANDARD: 527 if (community_cmp (entry->u.com, new->u.com)) 528 return 1; 529 break; 530 case EXTCOMMUNITY_LIST_STANDARD: 531 if (ecommunity_cmp (entry->u.ecom, new->u.ecom)) 532 return 1; 533 break; 534 case COMMUNITY_LIST_EXPANDED: 535 case EXTCOMMUNITY_LIST_EXPANDED: 536 if (strcmp (entry->config, new->config) == 0) 537 return 1; 538 break; 539 default: 540 break; 541 } 542 } 543 return 0; 544} 545 546/* Set community-list. */ 547int 548community_list_set (struct community_list_handler *ch, 549 char *name, char *str, int direct, int style) 550{ 551 struct community_entry *entry; 552 struct community_list *list; 553 struct community *com; 554 regex_t *regex; 555 556 entry = NULL; 557 558 /* Get community list. */ 559 list = community_list_get (ch, name, style); 560 561 /* When community-list already has entry, new entry should have same 562 style. If you want to have mixed style community-list, you can 563 comment out this check. */ 564 if (! community_list_empty_p (list)) 565 { 566 struct community_entry *first; 567 568 first = list->head; 569 570 if (style == COMMUNITY_LIST_AUTO) 571 style = first->style; 572 else if (style != first->style) 573 { 574 return (first->style == COMMUNITY_LIST_STANDARD 575 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT 576 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); 577 } 578 } 579 580 /* When str is NULL, it is matches any. */ 581 if (! str) 582 { 583 entry = community_entry_new (); 584 entry->direct = direct; 585 entry->any = 1; 586 if (style == COMMUNITY_LIST_AUTO) 587 entry->style = COMMUNITY_LIST_STANDARD; 588 else 589 entry->style = style; 590 } 591 else 592 { 593 /* Standard community-list parse. String must be converted into 594 community structure without problem. */ 595 if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO) 596 { 597 com = community_str2com (str); 598 if (com) 599 { 600 entry = community_entry_new (); 601 entry->u.com = com; 602 entry->direct = direct; 603 entry->style = COMMUNITY_LIST_STANDARD; 604 } 605 else if (style == COMMUNITY_LIST_STANDARD) 606 return COMMUNITY_LIST_ERR_MALFORMED_VAL; 607 608 /* We can't convert string into communities value. When 609 community-list type is auto, fall dawn to regular expression 610 match. */ 611 } 612 613 /* Expanded community-list parse. String may include regular 614 expression. */ 615 if (! entry && (style == COMMUNITY_LIST_EXPANDED 616 || style == COMMUNITY_LIST_AUTO)) 617 { 618 regex = bgp_regcomp (str); 619 if (regex) 620 { 621 entry = community_entry_new (); 622 entry->reg = regex; 623 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str); 624 entry->direct = direct; 625 entry->style = COMMUNITY_LIST_EXPANDED; 626 } 627 else 628 return COMMUNITY_LIST_ERR_MALFORMED_VAL; 629 } 630 } 631 632 /* Do not put duplicated community entry. */ 633 if (community_list_dup_check (list, entry)) 634 community_entry_free (entry); 635 else 636 community_list_entry_add (list, entry); 637 638 return 0; 639} 640 641/* Unset community-list. When str is NULL, delete all of 642 community-list entry belongs to the specified name. */ 643int 644community_list_unset (struct community_list_handler *ch, 645 char *name, char *str, int direct, int style) 646{ 647 struct community_entry *entry; 648 struct community_list *list; 649 struct community *com; 650 regex_t *regex; 651 652 entry = NULL; 653 654 /* Lookup community list. */ 655 list = community_list_lookup (ch, name, style); 656 if (list == NULL) 657 return COMMUNITY_LIST_ERR_CANT_FIND_LIST; 658 659 /* Delete all of entry belongs to this community-list. */ 660 if (! str) 661 { 662 community_list_delete (list); 663 return 0; 664 } 665 666 /* Community list string is specified. Lookup entry from community 667 list. */ 668 if (style == COMMUNITY_LIST_STANDARD || style == COMMUNITY_LIST_AUTO) 669 { 670 com = community_str2com (str); 671 if (com) 672 { 673 entry = community_list_entry_lookup (list, com, direct); 674 community_free (com); 675 } 676 else if (style == COMMUNITY_LIST_STANDARD) 677 return COMMUNITY_LIST_ERR_MALFORMED_VAL; 678 679 /* If we can't convert string into community and community-list 680 type is auto, fall dawn to expanded community-list. */ 681 } 682 683 /* Expanded community-list parse. String may include regular 684 expression. */ 685 if (! entry 686 && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO)) 687 { 688 regex = bgp_regcomp (str); 689 if (regex) 690 { 691 entry = community_list_entry_lookup (list, str, direct); 692 bgp_regex_free (regex); 693 } 694 else 695 return COMMUNITY_LIST_ERR_MALFORMED_VAL; 696 } 697 698 if (! entry) 699 return COMMUNITY_LIST_ERR_CANT_FIND_LIST; 700 701 community_list_entry_delete (list, entry, style); 702 703 return 0; 704} 705 706/* Set extcommunity-list. */ 707int 708extcommunity_list_set (struct community_list_handler *ch, 709 char *name, char *str, int direct, int style) 710{ 711 struct community_entry *entry; 712 struct community_list *list; 713 struct ecommunity *ecom; 714 regex_t *regex; 715 716 entry = NULL; 717 718 /* Get community list. */ 719 list = community_list_get (ch, name, style); 720 721 /* When community-list already has entry, new entry should have same 722 style. If you want to have mixed style community-list, you can 723 comment out this check. */ 724 if (! community_list_empty_p (list)) 725 { 726 struct community_entry *first; 727 728 first = list->head; 729 730 if (style == EXTCOMMUNITY_LIST_AUTO) 731 style = first->style; 732 else if (style != first->style) 733 { 734 return (first->style == EXTCOMMUNITY_LIST_STANDARD 735 ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT 736 : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); 737 } 738 } 739 740 /* When str is NULL, it is matches any. */ 741 if (! str) 742 { 743 entry = community_entry_new (); 744 entry->direct = direct; 745 entry->any = 1; 746 if (style == EXTCOMMUNITY_LIST_AUTO) 747 entry->style = EXTCOMMUNITY_LIST_STANDARD; 748 else 749 entry->style = style; 750 } 751 else 752 { 753 /* Standard extcommunity-list parse. String is converted into 754 ecommunity structure. */ 755 if (style == EXTCOMMUNITY_LIST_STANDARD 756 || style == EXTCOMMUNITY_LIST_AUTO) 757 { 758 /* Type is unknown. String includes keyword. */ 759 ecom = ecommunity_str2com (str, 0, 1); 760 if (ecom) 761 { 762 entry = community_entry_new (); 763 entry->config 764 = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST); 765 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY); 766 entry->u.ecom = ecom; 767 entry->direct = direct; 768 entry->style = EXTCOMMUNITY_LIST_STANDARD; 769 } 770 else if (style == EXTCOMMUNITY_LIST_STANDARD) 771 return COMMUNITY_LIST_ERR_MALFORMED_VAL; 772 773 /* We can't convert string into communities value. When 774 community-list type is auto, fall dawn to regular expression 775 match. */ 776 } 777 778 /* Expanded extcommunity-list parse. String may include regular 779 expression. */ 780 if (! entry && (style == EXTCOMMUNITY_LIST_EXPANDED 781 || style == EXTCOMMUNITY_LIST_AUTO)) 782 { 783 regex = bgp_regcomp (str); 784 if (regex) 785 { 786 entry = community_entry_new (); 787 entry->reg = regex; 788 entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str); 789 entry->direct = direct; 790 entry->style = EXTCOMMUNITY_LIST_EXPANDED; 791 } 792 else 793 return COMMUNITY_LIST_ERR_MALFORMED_VAL; 794 } 795 } 796 797 /* Do not put duplicated community entry. */ 798 if (community_list_dup_check (list, entry)) 799 community_entry_free (entry); 800 else 801 community_list_entry_add (list, entry); 802 803 return 0; 804} 805 806/* Unset extcommunity-list. When str is NULL, delete all of 807 extcommunity-list entry belongs to the specified name. */ 808int 809extcommunity_list_unset (struct community_list_handler *ch, 810 char *name, char *str, int direct, int style) 811{ 812 struct community_entry *entry; 813 struct community_list *list; 814 struct ecommunity *ecom = NULL; 815 regex_t *regex; 816 817 entry = NULL; 818 819 /* Lookup extcommunity list. */ 820 list = community_list_lookup (ch, name, style); 821 if (list == NULL) 822 return COMMUNITY_LIST_ERR_CANT_FIND_LIST; 823 824 /* Delete all of entry belongs to this extcommunity-list. */ 825 if (! str) 826 { 827 community_list_delete (list); 828 return 0; 829 } 830 831 /* Community list string is specified. Lookup entry from community 832 list. */ 833 if (style == EXTCOMMUNITY_LIST_STANDARD || style == EXTCOMMUNITY_LIST_AUTO) 834 { 835 ecom = ecommunity_str2com (str, 0, 1); 836 if (ecom) 837 { 838 entry = community_list_entry_lookup (list, ecom, direct); 839 ecommunity_free (ecom); 840 } 841 else if (style == COMMUNITY_LIST_STANDARD) 842 return COMMUNITY_LIST_ERR_MALFORMED_VAL; 843 844 /* If we can't convert string into community and community-list 845 type is auto, fall dawn to expanded community-list. */ 846 } 847 848 /* Expanded community-list parse. String may include regular 849 expression. */ 850 if (! entry 851 && (style == COMMUNITY_LIST_EXPANDED || style == COMMUNITY_LIST_AUTO)) 852 { 853 regex = bgp_regcomp (str); 854 if (regex) 855 { 856 entry = community_list_entry_lookup (list, str, direct); 857 bgp_regex_free (regex); 858 } 859 else 860 return COMMUNITY_LIST_ERR_MALFORMED_VAL; 861 } 862 863 if (! entry) 864 return COMMUNITY_LIST_ERR_CANT_FIND_LIST; 865 866 community_list_entry_delete (list, entry, style); 867 868 return 0; 869} 870 871/* Initializa community-list. Return community-list handler. */ 872struct community_list_handler * 873community_list_init () 874{ 875 struct community_list_handler *ch; 876 ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER, 877 sizeof (struct community_list_handler)); 878 return ch; 879} 880 881/* Terminate community-list. */ 882void 883community_list_terminate (struct community_list_handler *ch) 884{ 885 struct community_list_master *cm; 886 struct community_list *list; 887 888 cm = &ch->community_list; 889 while ((list = cm->num.head) != NULL) 890 community_list_delete (list); 891 while ((list = cm->str.head) != NULL) 892 community_list_delete (list); 893 894 cm = &ch->extcommunity_list; 895 while ((list = cm->num.head) != NULL) 896 community_list_delete (list); 897 while ((list = cm->str.head) != NULL) 898 community_list_delete (list); 899 900 XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch); 901} 902