Annotation of embedaddon/quagga/bgpd/bgp_clist.c, revision 1.1.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>