Support for BGP Large Communities

BGP Large Communities are a novel way to signal information between
networks. An example of a Large Community is: "2914:65400:38016". Large
BGP Communities are composed of three 4-byte integers, separated by a
colon. This is easy to remember and accommodates advanced routing
policies in relation to 4-Byte ASNs.

This feature was developed by:
Keyur Patel <keyur@arrcus.com> (Arrcus, Inc.),
Job Snijders <job@ntt.net> (NTT Communications),
David Lamparter <equinox@opensourcerouting.org>
and Donald Sharp <sharpd@cumulusnetworks.com>

Signed-off-by: Job Snijders <job@ntt.net>
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
Job Snijders 2016-11-15 19:00:39 +09:00 committed by Donald Sharp
parent 45680e7568
commit 57d187bc77
20 changed files with 2093 additions and 23 deletions

View file

@ -75,7 +75,8 @@ libbgp_a_SOURCES = \
bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \
bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_lcommunity.c \
bgp_mplsvpn.c bgp_nexthop.c \
bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC)
@ -85,7 +86,8 @@ noinst_HEADERS = \
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
bgp_ecommunity.h bgp_lcommunity.h \
bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \
bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \
$(BGP_VNC_RFAPI_HD)

View file

@ -42,6 +42,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_encap_types.h"
#if ENABLE_BGP_VNC
@ -76,6 +77,7 @@ static const struct message attr_str [] =
#if ENABLE_BGP_VNC
{ BGP_ATTR_VNC, "VNC" },
#endif
{ BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }
};
static const int attr_str_max = array_size(attr_str);
@ -670,6 +672,8 @@ attrhash_key_make (void *p)
if (extra)
{
if (extra->lcommunity)
MIX(lcommunity_hash_make (extra->lcommunity));
if (extra->ecommunity)
MIX(ecommunity_hash_make (extra->ecommunity));
if (extra->cluster)
@ -718,6 +722,7 @@ attrhash_cmp (const void *p1, const void *p2)
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
&& IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
&& ae1->ecommunity == ae2->ecommunity
&& ae1->lcommunity == ae2->lcommunity
&& ae1->cluster == ae2->cluster
&& ae1->transit == ae2->transit
&& (ae1->encap_tunneltype == ae2->encap_tunneltype)
@ -836,6 +841,13 @@ bgp_attr_intern (struct attr *attr)
attre->ecommunity->refcnt++;
}
if (attre->lcommunity)
{
if (! attre->lcommunity->refcnt)
attre->lcommunity = lcommunity_intern (attre->lcommunity);
else
attre->lcommunity->refcnt++;
}
if (attre->cluster)
{
if (! attre->cluster->refcnt)
@ -1026,6 +1038,10 @@ bgp_attr_unintern_sub (struct attr *attr)
if (attr->extra->ecommunity)
ecommunity_unintern (&attr->extra->ecommunity);
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
if (attr->extra->lcommunity)
lcommunity_unintern (&attr->extra->lcommunity);
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES));
if (attr->extra->cluster)
cluster_unintern (attr->extra->cluster);
@ -1096,6 +1112,8 @@ bgp_attr_flush (struct attr *attr)
if (attre->ecommunity && ! attre->ecommunity->refcnt)
ecommunity_free (&attre->ecommunity);
if (attre->lcommunity && ! attre->lcommunity->refcnt)
lcommunity_free (&attre->lcommunity);
if (attre->cluster && ! attre->cluster->refcnt)
{
cluster_free (attre->cluster);
@ -1254,6 +1272,7 @@ const u_int8_t attr_flags_values [] = {
[BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_LARGE_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
};
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
@ -2042,6 +2061,40 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
return BGP_ATTR_PARSE_PROCEED;
}
/* Large Community attribute. */
static bgp_attr_parse_ret_t
bgp_attr_large_community (struct bgp_attr_parser_args *args)
{
struct peer *const peer = args->peer;
struct attr *const attr = args->attr;
const bgp_size_t length = args->length;
/*
* Large community follows new attribute format.
*/
if (length == 0)
{
if (attr->extra)
attr->extra->lcommunity = NULL;
/* Empty extcomm doesn't seem to be invalid per se */
return BGP_ATTR_PARSE_PROCEED;
}
(bgp_attr_extra_get (attr))->lcommunity =
lcommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
/* XXX: fix ecommunity_parse to use stream API */
stream_forward_getp (peer->ibuf, length);
if (attr->extra && !attr->extra->lcommunity)
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
args->total);
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
return BGP_ATTR_PARSE_PROCEED;
}
/* Extended Community attribute. */
static bgp_attr_parse_ret_t
bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
@ -2063,7 +2116,7 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
/* XXX: fix ecommunity_parse to use stream API */
stream_forward_getp (peer->ibuf, length);
if (!attr->extra->ecommunity)
if (attr->extra && !attr->extra->ecommunity)
return bgp_attr_malformed (args,
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
args->total);
@ -2477,6 +2530,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
case BGP_ATTR_COMMUNITIES:
ret = bgp_attr_community (&attr_args);
break;
case BGP_ATTR_LARGE_COMMUNITIES:
ret = bgp_attr_large_community (&attr_args);
break;
case BGP_ATTR_ORIGINATOR_ID:
ret = bgp_attr_originator_id (&attr_args);
break;
@ -3101,6 +3157,28 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
stream_put (s, attr->community->val, attr->community->size * 4);
}
/*
* Large Community attribute.
*/
if (attr->extra &&
CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)
&& (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)))
{
if (attr->extra->lcommunity->size * 12 > 255)
{
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putw (s, attr->extra->lcommunity->size * 12);
}
else
{
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putc (s, attr->extra->lcommunity->size * 12);
}
stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12);
}
/* Route Reflector. */
if (peer->sort == BGP_PEER_IBGP
&& from
@ -3333,6 +3411,7 @@ bgp_attr_init (void)
attrhash_init ();
community_init ();
ecommunity_init ();
lcommunity_init ();
cluster_init ();
transit_init ();
encap_init ();
@ -3345,6 +3424,7 @@ bgp_attr_finish (void)
attrhash_finish ();
community_finish ();
ecommunity_finish ();
lcommunity_finish ();
cluster_finish ();
transit_finish ();
encap_finish ();
@ -3448,6 +3528,25 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
stream_put (s, attr->community->val, attr->community->size * 4);
}
/* Large Community attribute. */
if (attr->extra && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES))
{
if (attr->extra->lcommunity->size * 12 > 255)
{
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putw (s, attr->extra->lcommunity->size * 12);
}
else
{
stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putc (s, attr->extra->lcommunity->size * 12);
}
stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12);
}
/* Add a MP_NLRI attribute to dump the IPv6 next hop */
if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
(attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||

View file

@ -92,6 +92,9 @@ struct attr_extra
/* Extended Communities attribute. */
struct ecommunity *ecommunity;
/* Large Communities attribute. */
struct lcommunity *lcommunity;
/* Route-Reflector Cluster attribute */
struct cluster_list *cluster;

View file

@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgpd.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_clist.h"
@ -45,6 +46,8 @@ community_list_master_lookup (struct community_list_handler *ch, int master)
return &ch->community_list;
case EXTCOMMUNITY_LIST_MASTER:
return &ch->extcommunity_list;
case LARGE_COMMUNITY_LIST_MASTER:
return &ch->lcommunity_list;
}
return NULL;
}
@ -66,6 +69,10 @@ community_entry_free (struct community_entry *entry)
if (entry->u.com)
community_free (entry->u.com);
break;
case LARGE_COMMUNITY_LIST_STANDARD:
if (entry->u.lcom)
lcommunity_free (&entry->u.lcom);
break;
case EXTCOMMUNITY_LIST_STANDARD:
/* In case of standard extcommunity-list, configuration string
is made by ecommunity_ecom2str(). */
@ -76,6 +83,7 @@ community_entry_free (struct community_entry *entry)
break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
case LARGE_COMMUNITY_LIST_EXPANDED:
if (entry->config)
XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
if (entry->reg)
@ -320,8 +328,13 @@ community_list_entry_lookup (struct community_list *list, const void *arg,
if (entry->direct == direct && ecommunity_cmp (entry->u.ecom, arg))
return entry;
break;
case LARGE_COMMUNITY_LIST_STANDARD:
if (entry->direct == direct && lcommunity_cmp (entry->u.lcom, arg))
return entry;
break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
case LARGE_COMMUNITY_LIST_EXPANDED:
if (entry->direct == direct && strcmp (entry->config, arg) == 0)
return entry;
break;
@ -447,6 +460,91 @@ community_regexp_match (struct community *com, regex_t * reg)
return 0;
}
static char *
lcommunity_str_get (struct lcommunity *lcom, int i)
{
struct lcommunity_val lcomval;
u_int32_t globaladmin;
u_int32_t localdata1;
u_int32_t localdata2;
char *str;
u_char *ptr;
char *pnt;
ptr = lcom->val;
ptr += (i * LCOMMUNITY_SIZE);
memcpy (&lcomval, ptr, LCOMMUNITY_SIZE);
/* Allocate memory. 48 bytes taken off bgp_lcommunity.c */
str = pnt = XMALLOC (MTYPE_LCOMMUNITY_STR, 48);
ptr = (u_char *)lcomval.val;
globaladmin = (*ptr++ << 24);
globaladmin |= (*ptr++ << 16);
globaladmin |= (*ptr++ << 8);
globaladmin |= (*ptr++);
localdata1 = (*ptr++ << 24);
localdata1 |= (*ptr++ << 16);
localdata1 |= (*ptr++ << 8);
localdata1 |= (*ptr++);
localdata2 = (*ptr++ << 24);
localdata2 |= (*ptr++ << 16);
localdata2 |= (*ptr++ << 8);
localdata2 |= (*ptr++);
sprintf (pnt, "%u:%u:%u", globaladmin, localdata1, localdata2);
pnt += strlen (pnt);
*pnt = '\0';
return str;
}
/* Internal function to perform regular expression match for
* * a single community. */
static int
lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i)
{
const char *str;
/* When there is no communities attribute it is treated as empty
* string. */
if (lcom == NULL || lcom->size == 0)
str = "";
else
str = lcommunity_str_get (lcom, i);
/* Regular expression match. */
if (regexec (reg, str, 0, NULL, 0) == 0)
return 1;
/* No match. */
return 0;
}
static int
lcommunity_regexp_match (struct lcommunity *com, regex_t * reg)
{
const char *str;
/* When there is no communities attribute it is treated as empty
string. */
if (com == NULL || com->size == 0)
str = "";
else
str = lcommunity_str (com);
/* Regular expression match. */
if (regexec (reg, str, 0, NULL, 0) == 0)
return 1;
/* No match. */
return 0;
}
static int
ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
{
@ -546,6 +644,30 @@ community_list_match (struct community *com, struct community_list *list)
return 0;
}
int
lcommunity_list_match (struct lcommunity *lcom, struct community_list *list)
{
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next)
{
if (entry->any)
return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
if (entry->style == LARGE_COMMUNITY_LIST_STANDARD)
{
if (lcommunity_match (lcom, entry->u.lcom))
return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
}
else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED)
{
if (lcommunity_regexp_match (lcom, entry->reg))
return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
}
}
return 0;
}
int
ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
{
@ -694,12 +816,17 @@ community_list_dup_check (struct community_list *list,
if (community_cmp (entry->u.com, new->u.com))
return 1;
break;
case LARGE_COMMUNITY_LIST_STANDARD:
if (lcommunity_cmp (entry->u.lcom, new->u.lcom))
return 1;
break;
case EXTCOMMUNITY_LIST_STANDARD:
if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
return 1;
break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
case LARGE_COMMUNITY_LIST_EXPANDED:
if (strcmp (entry->config, new->config) == 0)
return 1;
break;
@ -817,6 +944,185 @@ community_list_unset (struct community_list_handler *ch,
return 0;
}
/* Delete all permitted large communities in the list from com. */
struct lcommunity *
lcommunity_list_match_delete (struct lcommunity *lcom,
struct community_list *list)
{
struct community_entry *entry;
u_int32_t com_index_to_delete[lcom->size];
u_char *ptr;
int delete_index = 0;
int i;
/* Loop over each lcommunity value and evaluate each against the
* community-list. If we need to delete a community value add its index to
* com_index_to_delete.
*/
ptr = lcom->val;
for (i = 0; i < lcom->size; i++)
{
ptr += (i * LCOMMUNITY_SIZE);
for (entry = list->head; entry; entry = entry->next)
{
if (entry->any)
{
if (entry->direct == COMMUNITY_PERMIT)
{
com_index_to_delete[delete_index] = i;
delete_index++;
}
break;
}
else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
&& lcommunity_include (entry->u.lcom, ptr) )
{
if (entry->direct == COMMUNITY_PERMIT)
{
com_index_to_delete[delete_index] = i;
delete_index++;
}
break;
}
else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
&& lcommunity_regexp_include (entry->reg, lcom, 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 */
ptr = lcom->val;
for (i = delete_index-1; i >= 0; i--)
{
ptr += (com_index_to_delete[i] * LCOMMUNITY_SIZE);
lcommunity_del_val (lcom, ptr);
}
return lcom;
}
/* Set lcommunity-list. */
int
lcommunity_list_set (struct community_list_handler *ch,
const char *name, const char *str, int direct, int style)
{
struct community_entry *entry = NULL;
struct community_list *list;
struct lcommunity *lcom = NULL;
regex_t *regex = NULL;
/* Get community list. */
list = community_list_get (ch, name, LARGE_COMMUNITY_LIST_MASTER);
/* When community-list already has entry, new entry should have same
style. If you want to have mixed style community-list, you can
comment out this check. */
if (!community_list_empty_p (list))
{
struct community_entry *first;
first = list->head;
if (style != first->style)
{
return (first->style == COMMUNITY_LIST_STANDARD
? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
: COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
}
}
if (str)
{
if (style == LARGE_COMMUNITY_LIST_STANDARD)
lcom = lcommunity_str2com (str);
else
regex = bgp_regcomp (str);
if (! lcom && ! regex)
return COMMUNITY_LIST_ERR_MALFORMED_VAL;
}
entry = community_entry_new ();
entry->direct = direct;
entry->style = style;
entry->any = (str ? 0 : 1);
entry->u.lcom = lcom;
entry->reg = regex;
if (lcom)
entry->config = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST);
else if (regex)
entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
else
entry->config = NULL;
/* Do not put duplicated community entry. */
if (community_list_dup_check (list, entry))
community_entry_free (entry);
else
community_list_entry_add (list, entry);
return 0;
}
/* Unset community-list. When str is NULL, delete all of
community-list entry belongs to the specified name. */
int
lcommunity_list_unset (struct community_list_handler *ch,
const char *name, const char *str,
int direct, int style)
{
struct community_entry *entry = NULL;
struct community_list *list;
struct lcommunity *lcom = NULL;
regex_t *regex = NULL;
/* Lookup community list. */
list = community_list_lookup (ch, name, LARGE_COMMUNITY_LIST_MASTER);
if (list == NULL)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
/* Delete all of entry belongs to this community-list. */
if (!str)
{
community_list_delete (list);
return 0;
}
if (style == LARGE_COMMUNITY_LIST_STANDARD)
lcom = lcommunity_str2com (str);
else
regex = bgp_regcomp (str);
if (! lcom && ! regex)
return COMMUNITY_LIST_ERR_MALFORMED_VAL;
if (lcom)
entry = community_list_entry_lookup (list, lcom, direct);
else
entry = community_list_entry_lookup (list, str, direct);
if (lcom)
lcommunity_free (&lcom);
if (regex)
bgp_regex_free (regex);
if (!entry)
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
community_list_entry_delete (list, entry, style);
return 0;
}
/* Set extcommunity-list. */
int
extcommunity_list_set (struct community_list_handler *ch,
@ -959,6 +1265,12 @@ community_list_terminate (struct community_list_handler *ch)
while ((list = cm->str.head) != NULL)
community_list_delete (list);
cm = &ch->lcommunity_list;
while ((list = cm->num.head) != NULL)
community_list_delete (list);
while ((list = cm->str.head) != NULL)
community_list_delete (list);
cm = &ch->extcommunity_list;
while ((list = cm->num.head) != NULL)
community_list_delete (list);

View file

@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* Master Community-list. */
#define COMMUNITY_LIST_MASTER 0
#define EXTCOMMUNITY_LIST_MASTER 1
#define LARGE_COMMUNITY_LIST_MASTER 2
/* Community-list deny and permit. */
#define COMMUNITY_DENY 0
@ -38,6 +39,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define COMMUNITY_LIST_EXPANDED 1 /* Expanded community-list. */
#define EXTCOMMUNITY_LIST_STANDARD 2 /* Standard extcommunity-list. */
#define EXTCOMMUNITY_LIST_EXPANDED 3 /* Expanded extcommunity-list. */
#define LARGE_COMMUNITY_LIST_STANDARD 4 /* Standard Large community-list. */
#define LARGE_COMMUNITY_LIST_EXPANDED 5 /* Expanded Large community-list. */
/* Community-list. */
struct community_list
@ -80,6 +83,7 @@ struct community_entry
{
struct community *com;
struct ecommunity *ecom;
struct lcommunity *lcom;
} u;
/* Configuration string. */
@ -112,6 +116,9 @@ struct community_list_handler
/* Exteded community-list. */
struct community_list_master extcommunity_list;
/* Large community-list. */
struct community_list_master lcommunity_list;
};
/* Error code of community-list. */
@ -139,6 +146,12 @@ extern int extcommunity_list_set (struct community_list_handler *ch,
extern int extcommunity_list_unset (struct community_list_handler *ch,
const char *name, const char *str,
int direct, int style, int delete_all);
extern int lcommunity_list_set (struct community_list_handler *ch,
const char *name, const char *str,
int direct, int style);
extern int lcommunity_list_unset (struct community_list_handler *ch,
const char *name, const char *str,
int direct, int style);
extern struct community_list_master *
community_list_master_lookup (struct community_list_handler *, int);
@ -148,9 +161,12 @@ community_list_lookup (struct community_list_handler *, const char *, int);
extern int community_list_match (struct community *, struct community_list *);
extern int ecommunity_list_match (struct ecommunity *, struct community_list *);
extern int lcommunity_list_match (struct lcommunity *, struct community_list *);
extern int community_list_exact_match (struct community *,
struct community_list *);
extern struct community *
community_list_match_delete (struct community *, struct community_list *);
extern struct lcommunity *
lcommunity_list_match_delete (struct lcommunity *lcom,
struct community_list *list);
#endif /* _QUAGGA_BGP_CLIST_H */

View file

@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_aspath.h"
/* Hash of community attribute. */

View file

@ -41,6 +41,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_encap.h"

563
bgpd/bgp_lcommunity.c Normal file
View file

@ -0,0 +1,563 @@
/* BGP Large Communities Attribute
Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
This file is part of GNU Zebra.
GNU Zebra is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU Zebra is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Zebra; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include <zebra.h>
#include "hash.h"
#include "memory.h"
#include "prefix.h"
#include "command.h"
#include "filter.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_aspath.h"
/* Hash of community attribute. */
static struct hash *lcomhash;
/* Allocate a new lcommunities. */
static struct lcommunity *
lcommunity_new (void)
{
return (struct lcommunity *) XCALLOC (MTYPE_LCOMMUNITY,
sizeof (struct lcommunity));
}
/* Allocate lcommunities. */
void
lcommunity_free (struct lcommunity **lcom)
{
if ((*lcom)->val)
XFREE (MTYPE_LCOMMUNITY_VAL, (*lcom)->val);
if ((*lcom)->str)
XFREE (MTYPE_LCOMMUNITY_STR, (*lcom)->str);
XFREE (MTYPE_LCOMMUNITY, *lcom);
lcom = NULL;
}
/* Add a new Large Communities value to Large Communities
Attribute structure. When the value is already exists in the
structure, we don't add the value. Newly added value is sorted by
numerical order. When the value is added to the structure return 1
else return 0. */
static int
lcommunity_add_val (struct lcommunity *lcom, struct lcommunity_val *lval)
{
u_int8_t *p;
int ret;
int c;
/* When this is fist value, just add it. */
if (lcom->val == NULL)
{
lcom->size++;
lcom->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom_length (lcom));
memcpy (lcom->val, lval->val, LCOMMUNITY_SIZE);
return 1;
}
/* If the value already exists in the structure return 0. */
c = 0;
for (p = lcom->val; c < lcom->size; p += LCOMMUNITY_SIZE, c++)
{
ret = memcmp (p, lval->val, LCOMMUNITY_SIZE);
if (ret == 0)
return 0;
if (ret > 0)
break;
}
/* Add the value to the structure with numerical sorting. */
lcom->size++;
lcom->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom->val, lcom_length (lcom));
memmove (lcom->val + (c + 1) * LCOMMUNITY_SIZE,
lcom->val + c * LCOMMUNITY_SIZE,
(lcom->size - 1 - c) * LCOMMUNITY_SIZE);
memcpy (lcom->val + c * LCOMMUNITY_SIZE, lval->val, LCOMMUNITY_SIZE);
return 1;
}
/* This function takes pointer to Large Communites strucutre then
create a new Large Communities structure by uniq and sort each
Large Communities value. */
struct lcommunity *
lcommunity_uniq_sort (struct lcommunity *lcom)
{
int i;
struct lcommunity *new;
struct lcommunity_val *lval;
if (! lcom)
return NULL;
new = lcommunity_new ();
for (i = 0; i < lcom->size; i++)
{
lval = (struct lcommunity_val *) (lcom->val + (i * LCOMMUNITY_SIZE));
lcommunity_add_val (new, lval);
}
return new;
}
/* Parse Large Communites Attribute in BGP packet. */
struct lcommunity *
lcommunity_parse (u_int8_t *pnt, u_short length)
{
struct lcommunity tmp;
struct lcommunity *new;
/* Length check. */
if (length % LCOMMUNITY_SIZE)
return NULL;
/* Prepare tmporary structure for making a new Large Communities
Attribute. */
tmp.size = length / LCOMMUNITY_SIZE;
tmp.val = pnt;
/* Create a new Large Communities Attribute by uniq and sort each
Large Communities value */
new = lcommunity_uniq_sort (&tmp);
return lcommunity_intern (new);
}
/* Duplicate the Large Communities Attribute structure. */
struct lcommunity *
lcommunity_dup (struct lcommunity *lcom)
{
struct lcommunity *new;
new = XCALLOC (MTYPE_LCOMMUNITY, sizeof (struct lcommunity));
new->size = lcom->size;
if (new->size)
{
new->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom->size * LCOMMUNITY_SIZE);
memcpy (new->val, lcom->val, lcom->size * LCOMMUNITY_SIZE);
}
else
new->val = NULL;
return new;
}
/* Retrun string representation of communities attribute. */
char *
lcommunity_str (struct lcommunity *lcom)
{
if (! lcom->str)
lcom->str = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_DISPLAY);
return lcom->str;
}
/* Merge two Large Communities Attribute structure. */
struct lcommunity *
lcommunity_merge (struct lcommunity *lcom1, struct lcommunity *lcom2)
{
if (lcom1->val)
lcom1->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom1->val,
(lcom1->size + lcom2->size) * LCOMMUNITY_SIZE);
else
lcom1->val = XMALLOC (MTYPE_LCOMMUNITY_VAL,
(lcom1->size + lcom2->size) * LCOMMUNITY_SIZE);
memcpy (lcom1->val + (lcom1->size * LCOMMUNITY_SIZE),
lcom2->val, lcom2->size * LCOMMUNITY_SIZE);
lcom1->size += lcom2->size;
return lcom1;
}
/* Intern Large Communities Attribute. */
struct lcommunity *
lcommunity_intern (struct lcommunity *lcom)
{
struct lcommunity *find;
assert (lcom->refcnt == 0);
find = (struct lcommunity *) hash_get (lcomhash, lcom, hash_alloc_intern);
if (find != lcom)
lcommunity_free (&lcom);
find->refcnt++;
if (! find->str)
find->str = lcommunity_lcom2str (find, LCOMMUNITY_FORMAT_DISPLAY);
return find;
}
/* Unintern Large Communities Attribute. */
void
lcommunity_unintern (struct lcommunity **lcom)
{
struct lcommunity *ret;
if ((*lcom)->refcnt)
(*lcom)->refcnt--;
/* Pull off from hash. */
if ((*lcom)->refcnt == 0)
{
/* Large community must be in the hash. */
ret = (struct lcommunity *) hash_release (lcomhash, *lcom);
assert (ret != NULL);
lcommunity_free (lcom);
}
}
/* Utility function to make hash key. */
unsigned int
lcommunity_hash_make (void *arg)
{
const struct lcommunity *lcom = arg;
int size = lcom->size * LCOMMUNITY_SIZE;
u_int8_t *pnt = lcom->val;
unsigned int key = 0;
int c;
for (c = 0; c < size; c += LCOMMUNITY_SIZE)
{
key += pnt[c];
key += pnt[c + 1];
key += pnt[c + 2];
key += pnt[c + 3];
key += pnt[c + 4];
key += pnt[c + 5];
key += pnt[c + 6];
key += pnt[c + 7];
key += pnt[c + 8];
key += pnt[c + 9];
key += pnt[c + 10];
key += pnt[c + 11];
}
return key;
}
/* Compare two Large Communities Attribute structure. */
int
lcommunity_cmp (const void *arg1, const void *arg2)
{
const struct lcommunity *lcom1 = arg1;
const struct lcommunity *lcom2 = arg2;
return (lcom1->size == lcom2->size
&& memcmp (lcom1->val, lcom2->val, lcom1->size * LCOMMUNITY_SIZE) == 0);
}
/* Return communities hash. */
struct hash *
lcommunity_hash (void)
{
return lcomhash;
}
/* Initialize Large Comminities related hash. */
void
lcommunity_init (void)
{
lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp);
}
void
lcommunity_finish (void)
{
hash_free (lcomhash);
lcomhash = NULL;
}
/* Large Communities token enum. */
enum lcommunity_token
{
lcommunity_token_unknown = 0,
lcommunity_token_val,
};
/* Get next Large Communities token from the string. */
static const char *
lcommunity_gettoken (const char *str, struct lcommunity_val *lval,
enum lcommunity_token *token)
{
const char *p = str;
/* Skip white space. */
while (isspace ((int) *p))
{
p++;
str++;
}
/* Check the end of the line. */
if (*p == '\0')
return NULL;
/* Community value. */
if (isdigit ((int) *p))
{
int separator = 0;
int digit = 0;
u_int32_t globaladmin = 0;
u_int32_t localdata1 = 0;
u_int32_t localdata2 = 0;
while (isdigit ((int) *p) || *p == ':')
{
if (*p == ':')
{
if (separator == 2)
{
*token = lcommunity_token_unknown;
return NULL;
}
else
{
separator++;
digit = 0;
if (separator == 1) {
globaladmin = localdata2;
} else {
localdata1 = localdata2;
}
localdata2 = 0;
}
}
else
{
digit = 1;
localdata2 *= 10;
localdata2 += (*p - '0');
}
p++;
}
if (! digit)
{
*token = lcommunity_token_unknown;
return NULL;
}
/*
* Copy the large comm.
*/
lval->val[0] = (globaladmin >> 24) & 0xff;
lval->val[1] = (globaladmin >> 16) & 0xff;
lval->val[2] = (globaladmin >> 8) & 0xff;
lval->val[3] = globaladmin & 0xff;
lval->val[4] = (localdata1 >> 24) & 0xff;
lval->val[5] = (localdata1 >> 16) & 0xff;
lval->val[6] = (localdata1 >> 8) & 0xff;
lval->val[7] = localdata1 & 0xff;
lval->val[8] = (localdata2 >> 24) & 0xff;
lval->val[9] = (localdata2 >> 16) & 0xff;
lval->val[10] = (localdata2 >> 8) & 0xff;
lval->val[11] = localdata2 & 0xff;
*token = lcommunity_token_val;
return p;
}
*token = lcommunity_token_unknown;
return p;
}
/*
Convert string to large community attribute.
When type is already known, please specify both str and type.
When string includes keyword for each large community value.
Please specify keyword_included as non-zero value.
*/
struct lcommunity *
lcommunity_str2com (const char *str)
{
struct lcommunity *lcom = NULL;
enum lcommunity_token token = lcommunity_token_unknown;
struct lcommunity_val lval;
while ((str = lcommunity_gettoken (str, &lval, &token)))
{
switch (token)
{
case lcommunity_token_val:
if (lcom == NULL)
lcom = lcommunity_new ();
lcommunity_add_val (lcom, &lval);
break;
case lcommunity_token_unknown:
default:
if (lcom)
lcommunity_free (&lcom);
return NULL;
}
}
return lcom;
}
int
lcommunity_include (struct lcommunity *lcom, u_char *ptr)
{
int i;
u_char *lcom_ptr;
lcom_ptr = lcom->val;
for (i = 0; i < lcom->size; i++) {
lcom_ptr += (i * LCOMMUNITY_SIZE);
if (memcmp (ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0)
return 1;
}
return 0;
}
/* Convert large community attribute to string.
The large coms will be in 65535:65531:0 format.
*/
char *
lcommunity_lcom2str (struct lcommunity *lcom, int format)
{
int i;
u_int8_t *pnt;
#define LCOMMUNITY_STR_DEFAULT_LEN 40
int str_size;
int str_pnt;
char *str_buf;
int len = 0;
int first = 1;
u_int32_t globaladmin, localdata1, localdata2;
if (lcom->size == 0)
{
str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, 1);
str_buf[0] = '\0';
return str_buf;
}
/* Prepare buffer. */
str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, LCOMMUNITY_STR_DEFAULT_LEN + 1);
str_size = LCOMMUNITY_STR_DEFAULT_LEN + 1;
str_pnt = 0;
for (i = 0; i < lcom->size; i++)
{
/* Make it sure size is enough. */
while (str_pnt + LCOMMUNITY_STR_DEFAULT_LEN >= str_size)
{
str_size *= 2;
str_buf = XREALLOC (MTYPE_LCOMMUNITY_STR, str_buf, str_size);
}
/* Space between each value. */
if (! first)
str_buf[str_pnt++] = ' ';
pnt = lcom->val + (i * 12);
globaladmin = (*pnt++ << 24);
globaladmin |= (*pnt++ << 16);
globaladmin |= (*pnt++ << 8);
globaladmin |= (*pnt++);
localdata1 = (*pnt++ << 24);
localdata1 |= (*pnt++ << 16);
localdata1 |= (*pnt++ << 8);
localdata1 |= (*pnt++);
localdata2 = (*pnt++ << 24);
localdata2 |= (*pnt++ << 16);
localdata2 |= (*pnt++ << 8);
localdata2 |= (*pnt++);
len = sprintf( str_buf + str_pnt, "%u:%u:%u", globaladmin,
localdata1, localdata2);
str_pnt += len;
first = 0;
}
return str_buf;
}
int
lcommunity_match (const struct lcommunity *lcom1,
const struct lcommunity *lcom2)
{
int i = 0;
int j = 0;
if (lcom1 == NULL && lcom2 == NULL)
return 1;
if (lcom1 == NULL || lcom2 == NULL)
return 0;
if (lcom1->size < lcom2->size)
return 0;
/* Every community on com2 needs to be on com1 for this to match */
while (i < lcom1->size && j < lcom2->size)
{
if (memcmp (lcom1->val + (i*12), lcom2->val + (j*12), LCOMMUNITY_SIZE) == 0)
j++;
i++;
}
if (j == lcom2->size)
return 1;
else
return 0;
}
/* Delete one lcommunity. */
void
lcommunity_del_val (struct lcommunity *lcom, u_char *ptr)
{
int i = 0;
int c = 0;
if (! lcom->val)
return;
while (i < lcom->size)
{
if (memcmp (lcom->val + i*LCOMMUNITY_SIZE, ptr, LCOMMUNITY_SIZE) == 0)
{
c = lcom->size -i -1;
if (c > 0)
memmove (lcom->val + i*LCOMMUNITY_SIZE, lcom->val + (i + 1)*LCOMMUNITY_SIZE, c * LCOMMUNITY_SIZE);
lcom->size--;
if (lcom->size > 0)
lcom->val = XREALLOC (MTYPE_COMMUNITY_VAL, lcom->val,
lcom_length (lcom));
else
{
XFREE (MTYPE_COMMUNITY_VAL, lcom->val);
lcom->val = NULL;
}
return;
}
i++;
}
}

75
bgpd/bgp_lcommunity.h Normal file
View file

@ -0,0 +1,75 @@
/* BGP Large Communities Attribute.
Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
This file is part of GNU Zebra.
GNU Zebra is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU Zebra is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Zebra; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#ifndef _QUAGGA_BGP_LCOMMUNITY_H
#define _QUAGGA_BGP_LCOMMUNITY_H
/* Extended communities attribute string format. */
#define LCOMMUNITY_FORMAT_ROUTE_MAP 0
#define LCOMMUNITY_FORMAT_COMMUNITY_LIST 1
#define LCOMMUNITY_FORMAT_DISPLAY 2
/* Large Communities value is twelve octets long. */
#define LCOMMUNITY_SIZE 12
/* Large Communities attribute. */
struct lcommunity
{
/* Reference counter. */
unsigned long refcnt;
/* Size of Extended Communities attribute. */
int size;
/* Extended Communities value. */
u_int8_t *val;
/* Human readable format string. */
char *str;
};
/* Extended community value is eight octet. */
struct lcommunity_val
{
char val[LCOMMUNITY_SIZE];
};
#define lcom_length(X) ((X)->size * LCOMMUNITY_SIZE)
extern void lcommunity_init (void);
extern void lcommunity_finish (void);
extern void lcommunity_free (struct lcommunity **);
extern struct lcommunity *lcommunity_parse (u_int8_t *, u_short);
extern struct lcommunity *lcommunity_dup (struct lcommunity *);
extern struct lcommunity *lcommunity_merge (struct lcommunity *, struct lcommunity *);
extern struct lcommunity *lcommunity_uniq_sort (struct lcommunity *);
extern struct lcommunity *lcommunity_intern (struct lcommunity *);
extern int lcommunity_cmp (const void *, const void *);
extern void lcommunity_unintern (struct lcommunity **);
extern unsigned int lcommunity_hash_make (void *);
extern struct hash *lcommunity_hash (void);
extern struct lcommunity *lcommunity_str2com (const char *);
extern char *lcommunity_lcom2str (struct lcommunity *, int);
extern int lcommunity_match (const struct lcommunity *, const struct lcommunity *);
extern char *lcommunity_str (struct lcommunity *);
extern int lcommunity_include (struct lcommunity *lcom, u_char *ptr);
extern void lcommunity_del_val (struct lcommunity *lcom, u_char *ptr);
#endif /* _QUAGGA_BGP_LCOMMUNITY_H */

View file

@ -111,3 +111,7 @@ DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV")
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options")
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value")
DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community")
DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string")
DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")

View file

@ -108,4 +108,7 @@ DECLARE_MTYPE(ENCAP_TLV)
DECLARE_MTYPE(BGP_TEA_OPTIONS)
DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE)
DECLARE_MTYPE(LCOMMUNITY)
DECLARE_MTYPE(LCOMMUNITY_STR)
DECLARE_MTYPE(LCOMMUNITY_VAL)
#endif /* _QUAGGA_BGP_MEMORY_H */

View file

@ -38,6 +38,7 @@
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_mpath.h"
/*
@ -662,6 +663,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
u_char origin;
struct community *community, *commerge;
struct ecommunity *ecomm, *ecommerge;
struct lcommunity *lcomm, *lcommerge;
struct attr_extra *ae;
struct attr attr = { 0 };
@ -698,6 +700,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
community = attr.community ? community_dup (attr.community) : NULL;
ae = attr.extra;
ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL;
lcomm = (ae && ae->lcommunity) ? lcommunity_dup (ae->lcommunity) : NULL;
for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
mpinfo = bgp_info_mpath_next (mpinfo))
@ -733,6 +736,17 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
else
ecomm = ecommunity_dup (ae->ecommunity);
}
if (ae && ae->lcommunity)
{
if (lcomm)
{
lcommerge = lcommunity_merge (lcomm, ae->lcommunity);
lcomm = lcommunity_uniq_sort (lcommerge);
lcommunity_free (&lcommerge);
}
else
lcomm = lcommunity_dup (ae->lcommunity);
}
}
attr.aspath = aspath;

View file

@ -46,6 +46,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_network.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_encap.h"

View file

@ -1,5 +1,6 @@
/* BGP routing information
Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
Copyright (C) 2016 Job Snijders <job@instituut.net>
This file is part of GNU Zebra.
@ -46,6 +47,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_clist.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_filter.h"
@ -7059,7 +7061,12 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
}
}
/* Line 6 display Originator, Cluster-id */
/* Line 6 display Large community */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))
vty_out (vty, " Large Community: %s%s",
attr->extra->lcommunity->str, VTY_NEWLINE);
/* Line 7 display Originator, Cluster-id */
if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) ||
(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)))
{
@ -7115,7 +7122,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (binfo->extra && binfo->extra->damp_info)
bgp_damp_info_vty (vty, binfo, json_path);
/* Line 7 display Addpath IDs */
/* Line 8 display Addpath IDs */
if (binfo->addpath_rx_id || binfo->addpath_tx_id)
{
if (json_paths)
@ -7170,7 +7177,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
}
}
/* Line 8 display Uptime */
/* Line 9 display Uptime */
tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
if (json_paths)
{
@ -7227,6 +7234,9 @@ enum bgp_show_type
bgp_show_type_community_exact,
bgp_show_type_community_list,
bgp_show_type_community_list_exact,
bgp_show_type_lcommunity_all,
bgp_show_type_lcommunity,
bgp_show_type_lcommunity_list,
bgp_show_type_flap_statistics,
bgp_show_type_flap_neighbor,
bgp_show_type_dampend_paths,
@ -7416,6 +7426,32 @@ bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table,
if (! community_list_exact_match (ri->attr->community, list))
continue;
}
if (type == bgp_show_type_community_all)
{
if (! ri->attr->community)
continue;
}
if (type == bgp_show_type_lcommunity)
{
struct lcommunity *lcom = output_arg;
if (! ri->attr->extra || ! ri->attr->extra->lcommunity ||
! lcommunity_match (ri->attr->extra->lcommunity, lcom))
continue;
}
if (type == bgp_show_type_lcommunity_list)
{
struct community_list *list = output_arg;
if (! ri->attr->extra ||
! lcommunity_list_match (ri->attr->extra->lcommunity, list))
continue;
}
if (type == bgp_show_type_lcommunity_all)
{
if (! ri->attr->extra || ! ri->attr->extra->lcommunity)
continue;
}
if (type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
{
@ -7832,6 +7868,63 @@ bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
use_json);
}
static int
bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc,
struct cmd_token **argv, afi_t afi, safi_t safi, u_char uj)
{
struct lcommunity *lcom;
struct buffer *b;
int i;
char *str;
int first = 0;
b = buffer_new (1024);
for (i = 0; i < argc; i++)
{
if (first)
buffer_putc (b, ' ');
else
{
if (strmatch (argv[i]->text, "<AA:BB:CC>"))
{
first = 1;
buffer_putstr (b, argv[i]->arg);
}
}
}
buffer_putc (b, '\0');
str = buffer_getstr (b);
buffer_free (b);
lcom = lcommunity_str2com (str);
XFREE (MTYPE_TMP, str);
if (! lcom)
{
vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE);
return CMD_WARNING;
}
return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity, lcom, uj);
}
static int
bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom,
afi_t afi, safi_t safi, u_char uj)
{
struct community_list *list;
list = community_list_lookup (bgp_clist, lcom, LARGE_COMMUNITY_LIST_MASTER);
if (list == NULL)
{
vty_out (vty, "%% %s is not a valid large-community-list name%s", lcom,
VTY_NEWLINE);
return CMD_WARNING;
}
return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_list, list, uj);
}
/* BGP route print out function. */
DEFUN (show_ip_bgp_ipv4,
show_ip_bgp_ipv4_cmd,
@ -7844,6 +7937,8 @@ DEFUN (show_ip_bgp_ipv4,
|filter-list WORD\
|community [<AA:NN|local-AS|no-advertise|no-export> [exact-match]]\
|community-list <(1-500)|WORD> [exact-match]\
|large-community [<AA:BB:CC>...]\
|large-community-list <(1-500)|WORD>\
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes>\
] [json]",
@ -7878,6 +7973,14 @@ DEFUN (show_ip_bgp_ipv4,
"community-list number\n"
"community-list name\n"
"Exact match of the communities\n"
"Display routes matching the large-communities\n"
"large-community number\n"
"large-community number\n"
"large-community number\n"
"large-community number\n"
"Display routes matching the large-community-list\n"
"large-community-list number\n"
"large-community-list name\n"
"IPv4 prefix\n"
"Display route and more specific routes\n"
"IPv6 prefix\n"
@ -7967,6 +8070,17 @@ DEFUN (show_ip_bgp_ipv4,
exact_match = 1;
return bgp_show_community_list (vty, vrf, clist_number_or_name, exact_match, afi, safi);
}
else if (strmatch(argv[idx]->text, "large-community"))
{
if (strmatch(argv[idx+1]->text, "<AA:BB:CC>"))
return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj);
else
return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj);
}
else if (strmatch(argv[idx]->text, "large-community-list"))
{
return bgp_show_lcommunity_list (vty, bgp, argv[idx+1]->arg, afi, safi, uj);
}
/* prefix-longer */
else if (argv[idx]->type == IPV4_TKN || argv[idx]->type == IPV6_TKN)
return bgp_show_prefix_longer (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_longer);
@ -10527,6 +10641,7 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd);
install_element (VIEW_NODE, &show_ip_bgp_instance_neighbor_advertised_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd);
install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
@ -10537,6 +10652,7 @@ bgp_route_init (void)
/* BGP dampening clear commands */
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd);
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd);
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd);
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd);

View file

@ -52,6 +52,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_filter.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_debug.h"
@ -84,6 +85,8 @@ o Cisco route-map
as-path tag : Not yet
automatic-tag : (This will not be implemented by bgpd)
community : Done
large-community : Done
large-comm-list : Done
comm-list : Not yet
dampning : Not yet
default : (This will not be implemented by bgpd)
@ -847,6 +850,78 @@ struct route_map_rule_cmd route_match_community_cmd =
route_match_community_free
};
/* Match function for lcommunity match. */
static route_map_result_t
route_match_lcommunity (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
struct community_list *list;
struct bgp_info *bgp_info;
struct rmap_community *rcom;
if (type == RMAP_BGP)
{
bgp_info = object;
rcom = rule;
list = community_list_lookup (bgp_clist, rcom->name,
LARGE_COMMUNITY_LIST_MASTER);
if (! list)
return RMAP_NOMATCH;
if (bgp_info->attr->extra &&
lcommunity_list_match (bgp_info->attr->extra->lcommunity, list))
return RMAP_MATCH;
}
return RMAP_NOMATCH;
}
/* Compile function for community match. */
static void *
route_match_lcommunity_compile (const char *arg)
{
struct rmap_community *rcom;
int len;
char *p;
rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community));
p = strchr (arg, ' ');
if (p)
{
len = p - arg;
rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
memcpy (rcom->name, arg, len);
}
else
{
rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
rcom->exact = 0;
}
return rcom;
}
/* Compile function for community match. */
static void
route_match_lcommunity_free (void *rule)
{
struct rmap_community *rcom = rule;
XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name);
XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom);
}
/* Route map commands for community matching. */
struct route_map_rule_cmd route_match_lcommunity_cmd =
{
"large-community",
route_match_lcommunity,
route_match_lcommunity_compile,
route_match_lcommunity_free
};
/* Match function for extcommunity match. */
static route_map_result_t
route_match_ecommunity (void *rule, struct prefix *prefix,
@ -1544,6 +1619,225 @@ struct route_map_rule_cmd route_set_community_cmd =
route_set_community_free,
};
/* `set community COMMUNITY' */
struct rmap_lcom_set
{
struct lcommunity *lcom;
int additive;
int none;
};
/* For lcommunity set mechanism. */
static route_map_result_t
route_set_lcommunity (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
struct rmap_lcom_set *rcs;
struct bgp_info *binfo;
struct attr *attr;
struct lcommunity *new = NULL;
struct lcommunity *old;
struct lcommunity *merge;
if (type == RMAP_BGP)
{
rcs = rule;
binfo = object;
attr = binfo->attr;
old = (attr->extra) ? attr->extra->lcommunity : NULL;
/* "none" case. */
if (rcs->none)
{
attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES));
if (attr->extra) {
attr->extra->lcommunity = NULL;
}
/* See the longer comment down below. */
if (old && old->refcnt == 0)
lcommunity_free(&old);
return RMAP_OKAY;
}
if (rcs->additive && old)
{
merge = lcommunity_merge (lcommunity_dup (old), rcs->lcom);
/* HACK: if the old large-community is not intern'd,
* we should free it here, or all reference to it may be lost.
* Really need to cleanup attribute caching sometime.
*/
if (old->refcnt == 0)
lcommunity_free (&old);
new = lcommunity_uniq_sort (merge);
lcommunity_free (&merge);
}
else
new = lcommunity_dup (rcs->lcom);
/* will be interned by caller if required */
if (attr->extra) {
attr->extra->lcommunity = new;
}
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
}
return RMAP_OKAY;
}
/* Compile function for set community. */
static void *
route_set_lcommunity_compile (const char *arg)
{
struct rmap_lcom_set *rcs;
struct lcommunity *lcom = NULL;
char *sp;
int additive = 0;
int none = 0;
if (strcmp (arg, "none") == 0)
none = 1;
else
{
sp = strstr (arg, "additive");
if (sp && sp > arg)
{
/* "additive" keyworkd is included. */
additive = 1;
*(sp - 1) = '\0';
}
lcom = lcommunity_str2com (arg);
if (additive)
*(sp - 1) = ' ';
if (! lcom)
return NULL;
}
rcs = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set));
rcs->lcom = lcom;
rcs->additive = additive;
rcs->none = none;
return rcs;
}
/* Free function for set lcommunity. */
static void
route_set_lcommunity_free (void *rule)
{
struct rmap_lcom_set *rcs = rule;
if (rcs->lcom) {
lcommunity_free (&rcs->lcom);
}
XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs);
}
/* Set community rule structure. */
struct route_map_rule_cmd route_set_lcommunity_cmd =
{
"large-community",
route_set_lcommunity,
route_set_lcommunity_compile,
route_set_lcommunity_free,
};
/* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */
/* For large community set mechanism. */
static route_map_result_t
route_set_lcommunity_delete (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
struct community_list *list;
struct lcommunity *merge;
struct lcommunity *new;
struct lcommunity *old;
struct bgp_info *binfo;
if (type == RMAP_BGP)
{
if (! rule)
return RMAP_OKAY;
binfo = object;
list = community_list_lookup (bgp_clist, rule,
LARGE_COMMUNITY_LIST_MASTER);
old = ((binfo->attr->extra) ? binfo->attr->extra->lcommunity : NULL);
if (list && old)
{
merge = lcommunity_list_match_delete (lcommunity_dup (old), list);
new = lcommunity_uniq_sort (merge);
lcommunity_free (&merge);
/* HACK: if the old community is not intern'd,
* we should free it here, or all reference to it may be lost.
* Really need to cleanup attribute caching sometime.
*/
if (old->refcnt == 0)
lcommunity_free (&old);
if (new->size == 0)
{
binfo->attr->extra->lcommunity = NULL;
binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
lcommunity_free (&new);
}
else
{
binfo->attr->extra->lcommunity = new;
binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
}
}
}
return RMAP_OKAY;
}
/* Compile function for set lcommunity. */
static void *
route_set_lcommunity_delete_compile (const char *arg)
{
char *p;
char *str;
int len;
p = strchr (arg, ' ');
if (p)
{
len = p - arg;
str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
memcpy (str, arg, len);
}
else
str = NULL;
return str;
}
/* Free function for set lcommunity. */
static void
route_set_lcommunity_delete_free (void *rule)
{
XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
}
/* Set lcommunity rule structure. */
struct route_map_rule_cmd route_set_lcommunity_delete_cmd =
{
"large-comm-list",
route_set_lcommunity_delete,
route_set_lcommunity_delete_compile,
route_set_lcommunity_delete_free,
};
/* `set comm-list (<1-99>|<100-500>|WORD) delete' */
/* For community set mechanism. */
@ -3114,7 +3408,32 @@ DEFUN (no_match_community,
RMAP_EVENT_CLIST_DELETED);
}
DEFUN (match_lcommunity,
match_lcommunity_cmd,
"match large-community [(1-99)|(100-500)|WORD]",
MATCH_STR
"Match BGP large community list\n"
"Large Community-list number (standard)\n"
"Large Community-list number (expanded)\n"
"Large Community-list name\n")
{
return bgp_route_match_add (vty, "large-community", argv[2]->arg,
RMAP_EVENT_LLIST_ADDED);
}
DEFUN (no_match_lcommunity,
no_match_lcommunity_cmd,
"no match large-community [(1-99)|(100-500)|WORD]",
NO_STR
MATCH_STR
"Match BGP large community list\n"
"Large Community-list number (standard)\n"
"Large Community-list number (expanded)\n"
"Large Community-list name\n")
{
return bgp_route_match_delete (vty, "large-community", NULL,
RMAP_EVENT_LLIST_DELETED);
}
DEFUN (match_ecommunity,
match_ecommunity_cmd,
@ -3547,6 +3866,86 @@ DEFUN (no_set_community_delete,
"comm-list", NULL);
}
DEFUN (set_lcommunity,
set_lcommunity_cmd,
"set large-community AA:BB:CC...",
SET_STR
"BGP large community attribute\n"
"Large Community number in aa:bb:cc format or additive\n")
{
int ret;
char *str;
str = argv_concat (argv, argc, 2);
ret = generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), "large-community", str);
XFREE (MTYPE_TMP, str);
return ret;
}
DEFUN (set_lcommunity_none,
set_lcommunity_none_cmd,
"set large-community none",
SET_STR
"BGP large community attribute\n"
"No large community attribute\n")
{
return generic_set_add (vty, VTY_GET_CONTEXT(route_map_index),
"large-community", "none");
}
DEFUN (no_set_lcommunity,
no_set_lcommunity_cmd,
"no set large-community <none|[AA:BB:CC...]>",
NO_STR
SET_STR
"BGP large community attribute\n"
"No community attribute\n"
"Large community\n"
"Large community in AA:BB:CC... format or additive\n")
{
return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
"large-community", NULL);
}
DEFUN (set_lcommunity_delete,
set_lcommunity_delete_cmd,
"set large-comm-list <(1-99)|(100-500)|WORD> delete",
SET_STR
"set BGP large community list (for deletion)\n"
"Large Community-list number (standard)\n"
"Large Communitly-list number (expanded)\n"
"Large Community-list name\n"
"Delete matching large communities\n")
{
char *str;
str = XCALLOC (MTYPE_TMP, strlen (argv[2]->arg) + strlen (" delete") + 1);
strcpy (str, argv[2]->arg);
strcpy (str + strlen (argv[2]->arg), " delete");
generic_set_add (vty, VTY_GET_CONTEXT(route_map_index),
"large-comm-list", str);
XFREE (MTYPE_TMP, str);
return CMD_SUCCESS;
}
DEFUN (no_set_lcommunity_delete,
no_set_lcommunity_delete_cmd,
"no set large-comm-list [<(1-99|(100-500)|word)> delete]",
NO_STR
SET_STR
"set BGP large community list (for deletion)\n"
"Large Community-list number (standard)\n"
"Large Communitly-list number (expanded)\n"
"Large Community-list name\n"
"Delete matching large communities\n")
{
return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
"large-comm-list", NULL);
}
DEFUN (set_ecommunity_rt,
set_ecommunity_rt_cmd,
@ -4002,6 +4401,7 @@ bgp_route_map_init (void)
route_map_install_match (&route_match_ip_route_source_prefix_list_cmd);
route_map_install_match (&route_match_aspath_cmd);
route_map_install_match (&route_match_community_cmd);
route_map_install_match (&route_match_lcommunity_cmd);
route_map_install_match (&route_match_ecommunity_cmd);
route_map_install_match (&route_match_local_pref_cmd);
route_map_install_match (&route_match_metric_cmd);
@ -4021,6 +4421,8 @@ bgp_route_map_init (void)
route_map_install_set (&route_set_aggregator_as_cmd);
route_map_install_set (&route_set_community_cmd);
route_map_install_set (&route_set_community_delete_cmd);
route_map_install_set (&route_set_lcommunity_cmd);
route_map_install_set (&route_set_lcommunity_delete_cmd);
route_map_install_set (&route_set_vpnv4_nexthop_cmd);
route_map_install_set (&route_set_originator_id_cmd);
route_map_install_set (&route_set_ecommunity_rt_cmd);
@ -4042,6 +4444,8 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &match_community_cmd);
install_element (RMAP_NODE, &match_community_exact_cmd);
install_element (RMAP_NODE, &no_match_community_cmd);
install_element (RMAP_NODE, &match_lcommunity_cmd);
install_element (RMAP_NODE, &no_match_lcommunity_cmd);
install_element (RMAP_NODE, &match_ecommunity_cmd);
install_element (RMAP_NODE, &no_match_ecommunity_cmd);
install_element (RMAP_NODE, &match_origin_cmd);
@ -4071,6 +4475,11 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &no_set_community_cmd);
install_element (RMAP_NODE, &set_community_delete_cmd);
install_element (RMAP_NODE, &no_set_community_delete_cmd);
install_element (RMAP_NODE, &set_lcommunity_cmd);
install_element (RMAP_NODE, &set_lcommunity_none_cmd);
install_element (RMAP_NODE, &no_set_lcommunity_cmd);
install_element (RMAP_NODE, &set_lcommunity_delete_cmd);
install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd);
install_element (RMAP_NODE, &set_ecommunity_rt_cmd);
install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd);
install_element (RMAP_NODE, &set_ecommunity_soo_cmd);

View file

@ -41,6 +41,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_damp.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_fsm.h"
@ -3748,13 +3749,15 @@ DEFUN (no_neighbor_send_community,
/* neighbor send-community extended. */
DEFUN (neighbor_send_community_type,
neighbor_send_community_type_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|extended|standard>",
"neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Send Community attribute to this neighbor\n"
"Send Standard and Extended Community attributes\n"
"Send Standard, Large and Extended Community attributes\n"
"Send Extended Community attributes\n"
"Send Standard Community attributes\n")
"Send Standard Community attributes\n"
"Send Large Community attributes\n")
{
int idx = 0;
u_int32_t flag = 0;
@ -3765,25 +3768,35 @@ DEFUN (neighbor_send_community_type,
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
else if (argv_find (argv, argc, "extended", &idx))
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
else if (argv_find (argv, argc, "large", &idx))
SET_FLAG (flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
else if (argv_find (argv, argc, "both", &idx))
{
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
}
else
{
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
}
{
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
SET_FLAG (flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
}
return peer_af_flag_set_vty (vty, peer, bgp_node_afi (vty), bgp_node_safi (vty), flag);
}
DEFUN (no_neighbor_send_community_type,
no_neighbor_send_community_type_cmd,
"no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|extended|standard>",
"no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Send Community attribute to this neighbor\n"
"Send Standard and Extended Community attributes\n"
"Send Standard, Large and Extended Community attributes\n"
"Send Extended Community attributes\n"
"Send Standard Community attributes\n")
"Send Standard Community attributes\n"
"Send Large Community attributes\n")
{
int idx_peer = 2;
int idx_type = 4;
@ -3795,11 +3808,21 @@ DEFUN (no_neighbor_send_community_type,
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
bgp_node_safi (vty),
PEER_FLAG_SEND_EXT_COMMUNITY);
if (strncmp (argv[idx_type]->arg, "l", 1) == 0)
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
bgp_node_safi (vty),
PEER_FLAG_SEND_LARGE_COMMUNITY);
if (strncmp (argv[idx_type]->arg, "b", 1) == 0)
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
bgp_node_safi (vty),
PEER_FLAG_SEND_COMMUNITY |
PEER_FLAG_SEND_EXT_COMMUNITY);
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
bgp_node_safi (vty),
(PEER_FLAG_SEND_COMMUNITY |
PEER_FLAG_SEND_EXT_COMMUNITY));
PEER_FLAG_SEND_EXT_COMMUNITY|
PEER_FLAG_SEND_LARGE_COMMUNITY));
}
/* neighbor soft-reconfig. */
@ -6132,6 +6155,12 @@ DEFUN (show_bgp_memory,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct ecommunity)),
VTY_NEWLINE);
if ((count = mtype_stats_alloc (MTYPE_LCOMMUNITY)))
vty_out (vty, "%ld BGP large-community entries, using %s of memory%s",
count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct lcommunity)),
VTY_NEWLINE);
if ((count = mtype_stats_alloc (MTYPE_CLUSTER)))
vty_out (vty, "%ld Cluster lists, using %s of memory%s", count,
@ -7109,12 +7138,16 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi,
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
vty_out (vty, " MED is propagated unchanged to this neighbor%s", VTY_NEWLINE);
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
|| CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
|| CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
|| CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
{
vty_out (vty, " Community attribute sent to this neighbor");
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
&& CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
vty_out (vty, "(both)%s", VTY_NEWLINE);
&& CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
&& CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
vty_out (vty, "(all)%s", VTY_NEWLINE);
else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
vty_out (vty, "(large)%s", VTY_NEWLINE);
else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
vty_out (vty, "(extended)%s", VTY_NEWLINE);
else
@ -8637,6 +8670,36 @@ DEFUN (show_ip_bgp_community_info,
return CMD_SUCCESS;
}
static void
lcommunity_show_all_iterator (struct hash_backet *backet, struct vty *vty)
{
struct lcommunity *lcom;
lcom = (struct lcommunity *) backet->data;
vty_out (vty, "[%p] (%ld) %s%s", (void *)backet, lcom->refcnt,
lcommunity_str (lcom), VTY_NEWLINE);
}
/* Show BGP's community internal data. */
DEFUN (show_ip_bgp_lcommunity_info,
show_ip_bgp_lcommunity_info_cmd,
"show ip bgp large-community-info",
SHOW_STR
IP_STR
BGP_STR
"List all bgp large-community information\n")
{
vty_out (vty, "Address Refcnt Large-community%s", VTY_NEWLINE);
hash_iterate (lcommunity_hash (),
(void (*) (struct hash_backet *, void *))
lcommunity_show_all_iterator,
vty);
return CMD_SUCCESS;
}
DEFUN (show_ip_bgp_attr_info,
show_ip_bgp_attr_info_cmd,
"show [ip] bgp attribute-info",
@ -10738,6 +10801,8 @@ bgp_vty_init (void)
/* "show [ip] bgp community" commands. */
install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd);
/* "show ip bgp large-community" commands. */
install_element (VIEW_NODE, &show_ip_bgp_lcommunity_info_cmd);
/* "show [ip] bgp attribute-info" commands. */
install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd);
@ -11070,6 +11135,324 @@ DEFUN (show_ip_community_list_arg,
return CMD_SUCCESS;
}
/*
* Large Community code.
*/
static int
lcommunity_list_set_vty (struct vty *vty, int argc, struct cmd_token **argv,
int style, int reject_all_digit_name)
{
int ret;
int direct;
char *str;
int idx = 0;
char *cl_name;
direct = argv_find (argv, argc, "permit", &idx) ? COMMUNITY_PERMIT : COMMUNITY_DENY;
/* All digit name check. */
idx = 0;
argv_find (argv, argc, "WORD", &idx);
argv_find (argv, argc, "(1-99)", &idx);
argv_find (argv, argc, "(100-500)", &idx);
cl_name = argv[idx]->arg;
if (reject_all_digit_name && all_digit (cl_name))
{
vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE);
return CMD_WARNING;
}
argv_find (argv, argc, "AA:BB:CC", &idx);
argv_find (argv, argc, "LINE", &idx);
/* Concat community string argument. */
if (idx)
str = argv_concat (argv, argc, idx);
else
str = NULL;
ret = lcommunity_list_set (bgp_clist, cl_name, str, direct, style);
/* Free temporary community list string allocated by
argv_concat(). */
if (str)
XFREE (MTYPE_TMP, str);
if (ret < 0)
{
community_list_perror (vty, ret);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
static int
lcommunity_list_unset_vty (struct vty *vty, int argc, struct cmd_token **argv,
int style)
{
int ret;
int direct = 0;
char *str = NULL;
int idx = 0;
argv_find (argv, argc, "permit", &idx);
argv_find (argv, argc, "deny", &idx);
if (idx)
{
/* Check the list direct. */
if (strncmp (argv[idx]->arg, "p", 1) == 0)
direct = COMMUNITY_PERMIT;
else
direct = COMMUNITY_DENY;
idx = 0;
argv_find (argv, argc, "LINE", &idx);
argv_find (argv, argc, "AA:AA:NN", &idx);
/* Concat community string argument. */
str = argv_concat (argv, argc, idx);
}
idx = 0;
argv_find (argv, argc, "(1-99)", &idx);
argv_find (argv, argc, "(100-500)", &idx);
argv_find (argv, argc, "WORD", &idx);
/* Unset community list. */
ret = lcommunity_list_unset (bgp_clist, argv[idx]->arg, str, direct, style);
/* Free temporary community list string allocated by
argv_concat(). */
if (str)
XFREE (MTYPE_TMP, str);
if (ret < 0)
{
community_list_perror (vty, ret);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
/* "large-community-list" keyword help string. */
#define LCOMMUNITY_LIST_STR "Add a large community list entry\n"
#define LCOMMUNITY_VAL_STR "large community in 'aa:bb:cc' format\n"
DEFUN (ip_lcommunity_list_standard,
ip_lcommunity_list_standard_cmd,
"ip large-community-list (1-99) <deny|permit> [AA:BB:CC...]",
IP_STR
LCOMMUNITY_LIST_STR
"Large Community list number (standard)\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
LCOMMUNITY_VAL_STR)
{
return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 0);
}
DEFUN (ip_lcommunity_list_expanded,
ip_lcommunity_list_expanded_cmd,
"ip large-community-list (100-500) <deny|permit> LINE...",
IP_STR
LCOMMUNITY_LIST_STR
"Large Community list number (expanded)\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
"An ordered list as a regular-expression\n")
{
return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 0);
}
DEFUN (ip_lcommunity_list_name_standard,
ip_lcommunity_list_name_standard_cmd,
"ip large-community-list standard WORD <deny|permit> [AA:BB.CC...]",
IP_STR
LCOMMUNITY_LIST_STR
"Specify standard large-community-list\n"
"Large Community list name\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
LCOMMUNITY_VAL_STR)
{
return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1);
}
DEFUN (ip_lcommunity_list_name_expanded,
ip_lcommunity_list_name_expanded_cmd,
"ip large-community-list expanded WORD <deny|permit> LINE...",
IP_STR
LCOMMUNITY_LIST_STR
"Specify expanded large-community-list\n"
"Large Community list name\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
"An ordered list as a regular-expression\n")
{
return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 1);
}
DEFUN (no_ip_lcommunity_list_standard_all,
no_ip_lcommunity_list_standard_all_cmd,
"no ip large-community-list <(1-99)|(100-500)|WORD>",
NO_STR
IP_STR
LCOMMUNITY_LIST_STR
"Large Community list number (standard)\n"
"Large Community list number (expanded)\n"
"Large Community list name\n")
{
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
}
DEFUN (no_ip_lcommunity_list_name_expanded_all,
no_ip_lcommunity_list_name_expanded_all_cmd,
"no ip large-community-list expanded WORD",
NO_STR
IP_STR
LCOMMUNITY_LIST_STR
"Specify expanded large-community-list\n"
"Large Community list name\n")
{
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
}
DEFUN (no_ip_lcommunity_list_standard,
no_ip_lcommunity_list_standard_cmd,
"no ip large-community-list (1-99) <deny|permit> AA:AA:NN...",
NO_STR
IP_STR
LCOMMUNITY_LIST_STR
"Large Community list number (standard)\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
LCOMMUNITY_VAL_STR)
{
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
}
DEFUN (no_ip_lcommunity_list_expanded,
no_ip_lcommunity_list_expanded_cmd,
"no ip large-community-list (100-500) <deny|permit> LINE...",
NO_STR
IP_STR
LCOMMUNITY_LIST_STR
"Large Community list number (expanded)\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
"An ordered list as a regular-expression\n")
{
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
}
DEFUN (no_ip_lcommunity_list_name_standard,
no_ip_lcommunity_list_name_standard_cmd,
"no ip large-community-list standard WORD <deny|permit> AA:AA:NN...",
NO_STR
IP_STR
LCOMMUNITY_LIST_STR
"Specify standard large-community-list\n"
"Large Community list name\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
LCOMMUNITY_VAL_STR)
{
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
}
DEFUN (no_ip_lcommunity_list_name_expanded,
no_ip_lcommunity_list_name_expanded_cmd,
"no ip large-community-list expanded WORD <deny|permit> LINE...",
NO_STR
IP_STR
LCOMMUNITY_LIST_STR
"Specify expanded large-community-list\n"
"Large community list name\n"
"Specify large community to reject\n"
"Specify large community to accept\n"
"An ordered list as a regular-expression\n")
{
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
}
static void
lcommunity_list_show (struct vty *vty, struct community_list *list)
{
struct community_entry *entry;
for (entry = list->head; entry; entry = entry->next)
{
if (entry == list->head)
{
if (all_digit (list->name))
vty_out (vty, "Large community %s list %s%s",
entry->style == EXTCOMMUNITY_LIST_STANDARD ?
"standard" : "(expanded) access",
list->name, VTY_NEWLINE);
else
vty_out (vty, "Named large community %s list %s%s",
entry->style == EXTCOMMUNITY_LIST_STANDARD ?
"standard" : "expanded",
list->name, VTY_NEWLINE);
}
if (entry->any)
vty_out (vty, " %s%s",
community_direct_str (entry->direct), VTY_NEWLINE);
else
vty_out (vty, " %s %s%s",
community_direct_str (entry->direct),
entry->style == EXTCOMMUNITY_LIST_STANDARD ?
entry->u.ecom->str : entry->config,
VTY_NEWLINE);
}
}
DEFUN (show_ip_lcommunity_list,
show_ip_lcommunity_list_cmd,
"show ip large-community-list",
SHOW_STR
IP_STR
"List large-community list\n")
{
struct community_list *list;
struct community_list_master *cm;
cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER);
if (! cm)
return CMD_SUCCESS;
for (list = cm->num.head; list; list = list->next)
lcommunity_list_show (vty, list);
for (list = cm->str.head; list; list = list->next)
lcommunity_list_show (vty, list);
return CMD_SUCCESS;
}
DEFUN (show_ip_lcommunity_list_arg,
show_ip_lcommunity_list_arg_cmd,
"show ip large-community-list <(1-500)|WORD>",
SHOW_STR
IP_STR
"List large-community list\n"
"large-community-list number\n"
"large-community-list name\n")
{
struct community_list *list;
list = community_list_lookup (bgp_clist, argv[3]->arg, LARGE_COMMUNITY_LIST_MASTER);
if (! list)
{
vty_out (vty, "%% Can't find extcommunity-list%s", VTY_NEWLINE);
return CMD_WARNING;
}
lcommunity_list_show (vty, list);
return CMD_SUCCESS;
}
/* "extcommunity-list" keyword help string. */
#define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n"
#define EXTCOMMUNITY_VAL_STR "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n"
@ -11379,6 +11762,30 @@ community_list_config_write (struct vty *vty)
community_list_config_str (entry), VTY_NEWLINE);
write++;
}
/* lcommunity-list. */
cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER);
for (list = cm->num.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next)
{
vty_out (vty, "ip large-community-list %s %s %s%s",
list->name, community_direct_str (entry->direct),
community_list_config_str (entry), VTY_NEWLINE);
write++;
}
for (list = cm->str.head; list; list = list->next)
for (entry = list->head; entry; entry = entry->next)
{
vty_out (vty, "ip large-community-list %s %s %s %s%s",
entry->style == LARGE_COMMUNITY_LIST_STANDARD
? "standard" : "expanded",
list->name, community_direct_str (entry->direct),
community_list_config_str (entry), VTY_NEWLINE);
write++;
}
return write;
}
@ -11409,4 +11816,18 @@ community_list_vty (void)
install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd);
install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd);
install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd);
/* Large Community List */
install_element (CONFIG_NODE, &ip_lcommunity_list_standard_cmd);
install_element (CONFIG_NODE, &ip_lcommunity_list_expanded_cmd);
install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd);
install_element (CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd);
install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd);
install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_all_cmd);
install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_cmd);
install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_cmd);
install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_cmd);
install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_cmd);
install_element (VIEW_NODE, &show_ip_lcommunity_list_cmd);
install_element (VIEW_NODE, &show_ip_lcommunity_list_arg_cmd);
}

View file

@ -902,6 +902,7 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi)
{
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
}
/* Clear neighbor default_originate_rmap */
@ -1206,6 +1207,7 @@ peer_new (struct bgp *bgp)
{
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
}
peer->orf_plist[afi][safi] = NULL;
}
@ -3702,6 +3704,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] =
{
{ PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out },
{ PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out },
{ PEER_FLAG_SEND_LARGE_COMMUNITY, 1, peer_change_reset_out },
{ PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out },
{ PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset },
{ PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset },
@ -6982,10 +6985,17 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp,
if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
{
if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
&& peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
&& peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)
&& peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
{
afi_header_vty_out (vty, afi, safi, write,
" neighbor %s send-community both%s",
" neighbor %s send-community all%s",
addr, VTY_NEWLINE);
}
else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
{
afi_header_vty_out (vty, afi, safi, write,
" neighbor %s send-community large%s",
addr, VTY_NEWLINE);
}
else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
@ -7006,10 +7016,19 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp,
if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) &&
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) &&
!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)))
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) &&
!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY) &&
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)))
{
afi_header_vty_out (vty, afi, safi, write,
" no neighbor %s send-community both%s",
" no neighbor %s send-community all%s",
addr, VTY_NEWLINE);
}
else if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY) &&
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)))
{
afi_header_vty_out (vty, afi, safi, write,
" no neighbor %s send-community large%s",
addr, VTY_NEWLINE);
}
else if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&

View file

@ -705,6 +705,7 @@ struct peer
#define PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS (1 << 23) /* addpath-tx-bestpath-per-AS */
#define PEER_FLAG_WEIGHT (1 << 24) /* weight */
#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */
#define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 26) /* Send large Communities */
/* MD5 password */
char *password;
@ -963,6 +964,7 @@ struct bgp_nlri
#define BGP_ATTR_AS4_AGGREGATOR 18
#define BGP_ATTR_AS_PATHLIMIT 21
#define BGP_ATTR_ENCAP 23
#define BGP_ATTR_LARGE_COMMUNITIES 32
#if ENABLE_BGP_VNC
#define BGP_ATTR_VNC 255
#endif

View file

@ -710,6 +710,7 @@ enum route_map_dep_type
ROUTE_MAP_DEP_RMAP = 1,
ROUTE_MAP_DEP_CLIST,
ROUTE_MAP_DEP_ECLIST,
ROUTE_MAP_DEP_LCLIST,
ROUTE_MAP_DEP_PLIST,
ROUTE_MAP_DEP_ASPATH,
ROUTE_MAP_DEP_FILTER,
@ -1819,6 +1820,7 @@ route_map_dep_update (struct hash *dephash, const char *dep_name,
case RMAP_EVENT_CLIST_ADDED:
case RMAP_EVENT_ECLIST_ADDED:
case RMAP_EVENT_ASLIST_ADDED:
case RMAP_EVENT_LLIST_ADDED:
case RMAP_EVENT_CALL_ADDED:
case RMAP_EVENT_FILTER_ADDED:
if (rmap_debug)
@ -1840,6 +1842,7 @@ route_map_dep_update (struct hash *dephash, const char *dep_name,
case RMAP_EVENT_CLIST_DELETED:
case RMAP_EVENT_ECLIST_DELETED:
case RMAP_EVENT_ASLIST_DELETED:
case RMAP_EVENT_LLIST_DELETED:
case RMAP_EVENT_CALL_DELETED:
case RMAP_EVENT_FILTER_DELETED:
if (rmap_debug)
@ -1902,6 +1905,10 @@ route_map_get_dep_hash (route_map_event_t event)
case RMAP_EVENT_ASLIST_DELETED:
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
break;
case RMAP_EVENT_LLIST_ADDED:
case RMAP_EVENT_LLIST_DELETED:
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
break;
case RMAP_EVENT_CALL_ADDED:
case RMAP_EVENT_CALL_DELETED:
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];

View file

@ -84,6 +84,8 @@ typedef enum
RMAP_EVENT_CLIST_DELETED,
RMAP_EVENT_ECLIST_ADDED,
RMAP_EVENT_ECLIST_DELETED,
RMAP_EVENT_LLIST_ADDED,
RMAP_EVENT_LLIST_DELETED,
RMAP_EVENT_ASLIST_ADDED,
RMAP_EVENT_ASLIST_DELETED,
RMAP_EVENT_FILTER_ADDED,