File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / bgpd / bgp_clist.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:10 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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: #include "filter.h"
   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"
   34: 
   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: }
  266: 
  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: }
  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: 
  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;
  553:   u_int32_t val;
  554:   u_int32_t com_index_to_delete[com->size];
  555:   int delete_index = 0;
  556:   int i;
  557: 
  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++)
  563:     {
  564:       val = community_val_get (com, i);
  565: 
  566:       for (entry = list->head; entry; entry = entry->next)
  567:         {
  568:           if (entry->any)
  569:             {
  570:               if (entry->direct == COMMUNITY_PERMIT)
  571:                 {
  572:                   com_index_to_delete[delete_index] = i;
  573:                   delete_index++;
  574:                 }
  575:               break;
  576:             }
  577: 
  578:           else if ((entry->style == COMMUNITY_LIST_STANDARD)
  579:                    && (community_include (entry->u.com, COMMUNITY_INTERNET)
  580:                        || community_include (entry->u.com, val) ))
  581:             {
  582:               if (entry->direct == COMMUNITY_PERMIT)
  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);
  608:     }
  609: 
  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: }
  656: 
  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>