LCOV - code coverage report
Current view: top level - bgpd - bgp_clist.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 382 0.0 %
Date: 2015-11-19 Functions: 0 27 0.0 %

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

Generated by: LCOV version 1.10