set community delete stops as soon as it hits a community-list entry with a deny

This commit is contained in:
Donald Sharp 2015-05-19 18:04:23 -07:00
parent 0a56c84405
commit 5cbea2885d
3 changed files with 141 additions and 30 deletions

View File

@ -331,6 +331,94 @@ community_list_entry_lookup (struct community_list *list, const void *arg,
return NULL;
}
static char *
community_str_get (struct community *com, int i)
{
int len;
u_int32_t comval;
u_int16_t as;
u_int16_t val;
char *str;
char *pnt;
memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t));
comval = ntohl (comval);
switch (comval)
{
case COMMUNITY_INTERNET:
len = strlen (" internet");
break;
case COMMUNITY_NO_EXPORT:
len = strlen (" no-export");
break;
case COMMUNITY_NO_ADVERTISE:
len = strlen (" no-advertise");
break;
case COMMUNITY_LOCAL_AS:
len = strlen (" local-AS");
break;
default:
len = strlen (" 65536:65535");
break;
}
/* Allocate memory. */
str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len);
switch (comval)
{
case COMMUNITY_INTERNET:
strcpy (pnt, "internet");
pnt += strlen ("internet");
break;
case COMMUNITY_NO_EXPORT:
strcpy (pnt, "no-export");
pnt += strlen ("no-export");
break;
case COMMUNITY_NO_ADVERTISE:
strcpy (pnt, "no-advertise");
pnt += strlen ("no-advertise");
break;
case COMMUNITY_LOCAL_AS:
strcpy (pnt, "local-AS");
pnt += strlen ("local-AS");
break;
default:
as = (comval >> 16) & 0xFFFF;
val = comval & 0xFFFF;
sprintf (pnt, "%u:%d", as, val);
pnt += strlen (pnt);
break;
}
*pnt = '\0';
return str;
}
/* Internal function to perform regular expression match for
* * a single community. */
static int
community_regexp_include (regex_t * reg, struct community *com, int i)
{
const char *str;
/* When there is no communities attribute it is treated as empty
* string. */
if (com == NULL || com->size == 0)
str = "";
else
str = community_str_get (com, i);
/* Regular expression match. */
if (regexec (reg, str, 0, NULL, 0) == 0)
return 1;
/* No match. */
return 0;
}
/* Internal function to perform regular expression match for community
attribute. */
static int
@ -510,41 +598,63 @@ community_list_match_delete (struct community *com,
struct community_list *list)
{
struct community_entry *entry;
u_int32_t val;
u_int32_t com_index_to_delete[com->size];
int delete_index = 0;
int i;
for (entry = list->head; entry; entry = entry->next)
/* Loop over each community value and evaluate each against the
* community-list. If we need to delete a community value add its index to
* com_index_to_delete.
*/
for (i = 0; i < com->size; i++)
{
if (entry->any)
{
if (entry->direct == COMMUNITY_PERMIT)
{
/* This is a tricky part. Currently only
* route_set_community_delete() uses this function. In the
* function com->size is zero, it free the community
* structure.
*/
com->size = 0;
}
return com;
}
val = community_val_get (com, i);
if ((entry->style == COMMUNITY_LIST_STANDARD)
&& (community_include (entry->u.com, COMMUNITY_INTERNET)
|| community_match (com, entry->u.com) ))
for (entry = list->head; entry; entry = entry->next)
{
if (entry->any)
{
if (entry->direct == COMMUNITY_PERMIT)
community_delete (com, entry->u.com);
else
break;
}
else if ((entry->style == COMMUNITY_LIST_EXPANDED)
&& community_regexp_match (com, entry->reg))
{
if (entry->direct == COMMUNITY_PERMIT)
community_regexp_delete (com, entry->reg);
else
break;
}
{
com_index_to_delete[delete_index] = i;
delete_index++;
}
break;
}
else if ((entry->style == COMMUNITY_LIST_STANDARD)
&& (community_include (entry->u.com, COMMUNITY_INTERNET)
|| community_include (entry->u.com, val) ))
{
if (entry->direct == COMMUNITY_PERMIT)
{
com_index_to_delete[delete_index] = i;
delete_index++;
}
break;
}
else if ((entry->style == COMMUNITY_LIST_EXPANDED)
&& community_regexp_include (entry->reg, com, i))
{
if (entry->direct == COMMUNITY_PERMIT)
{
com_index_to_delete[delete_index] = i;
delete_index++;
}
break;
}
}
}
/* Delete all of the communities we flagged for deletion */
for (i = delete_index-1; i >= 0; i--)
{
val = community_val_get (com, com_index_to_delete[i]);
community_del_val (com, &val);
}
return com;
}

View File

@ -144,7 +144,7 @@ community_include (struct community *com, u_int32_t val)
return 0;
}
static u_int32_t
u_int32_t
community_val_get (struct community *com, int i)
{
u_char *p;

View File

@ -70,5 +70,6 @@ extern int community_include (struct community *, u_int32_t);
extern void community_del_val (struct community *, u_int32_t *);
extern unsigned long community_count (void);
extern struct hash *community_hash (void);
extern u_int32_t community_val_get (struct community *com, int i);
#endif /* _QUAGGA_BGP_COMMUNITY_H */