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