Annotation of embedaddon/quagga/bgpd/bgp_clist.c, revision 1.1.1.2

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>