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>