Mailing List Archive

[PATCH] Add BGP Large Communities support (draft-ietf-idr-large-community-11)
Signed-off-by: Michael Lambert <lambert@psc.edu>
---
bgpd/Makefile.am | 6 +-
bgpd/bgp_attr.c | 111 +++++-
bgpd/bgp_attr.h | 5 +-
bgpd/bgp_clist.c | 313 +++++++++++++++
bgpd/bgp_clist.h | 18 +-
bgpd/bgp_ecommunity.c | 1 +
bgpd/bgp_encap.c | 1 +
bgpd/bgp_lcommunity.c | 562 +++++++++++++++++++++++++++
bgpd/bgp_lcommunity.h | 75 ++++
bgpd/bgp_mpath.c | 16 +
bgpd/bgp_open.c | 2 +
bgpd/bgp_packet.c | 1 +
bgpd/bgp_route.c | 1009 ++++++++++++++++++++++++++++++++++++++++++++++++-
bgpd/bgp_routemap.c | 440 ++++++++++++++++++++-
bgpd/bgp_vty.c | 475 ++++++++++++++++++++++-
bgpd/bgpd.c | 19 +-
bgpd/bgpd.h | 2 +
lib/memtypes.c | 3 +
18 files changed, 3030 insertions(+), 29 deletions(-)
create mode 100644 bgpd/bgp_lcommunity.c
create mode 100644 bgpd/bgp_lcommunity.h

diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index fe1be32..753b679 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -14,7 +14,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_encap.c bgp_encap_tlv.c bgp_nht.c

@@ -22,7 +23,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_encap.h bgp_encap_tlv.h bgp_encap_types.h bgp_nht.h

diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 6aab50a..1511319 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -39,6 +39,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 "table.h"
#include "bgp_encap_types.h"

@@ -65,6 +66,18 @@ static const struct message attr_str [] =
{ BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
{ BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
{ BGP_ATTR_ENCAP, "ENCAP" },
+ { 21, ""},
+ { 22, ""},
+ { 23, ""},
+ { 24, ""},
+ { 25, ""},
+ { 26, ""},
+ { 27, ""},
+ { 28, ""},
+ { 29, ""},
+ { 30, ""},
+ { 31, ""},
+ { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }
};
static const int attr_str_max = array_size(attr_str);

@@ -505,6 +518,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)
@@ -547,6 +562,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)
@@ -658,6 +674,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)
@@ -791,7 +814,11 @@ 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);
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST));
@@ -853,6 +880,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);
@@ -1002,6 +1031,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;

@@ -1791,6 +1821,37 @@ 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;
+
+ 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)
@@ -1812,7 +1873,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);
@@ -2225,6 +2286,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;
@@ -2794,6 +2858,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
@@ -3002,6 +3088,7 @@ bgp_attr_init (void)
attrhash_init ();
community_init ();
ecommunity_init ();
+ lcommunity_init ();
cluster_init ();
transit_init ();
}
@@ -3013,6 +3100,7 @@ bgp_attr_finish (void)
attrhash_finish ();
community_finish ();
ecommunity_finish ();
+ lcommunity_finish ();
cluster_finish ();
transit_finish ();
}
@@ -3115,6 +3203,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_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_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 == 16 || attr->extra->mp_nexthop_len == 32) )
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 8457f40..cf82765 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -66,7 +66,10 @@ struct attr_extra

/* Extended Communities attribute. */
struct ecommunity *ecommunity;
-
+
+ /* Large Communities attribute. */
+ struct lcommunity *lcommunity;
+
/* Route-Reflector Cluster attribute */
struct cluster_list *cluster;

diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index bb06028..54f9418 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -28,6 +28,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"
@@ -44,6 +45,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;
}
@@ -65,6 +68,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(). */
@@ -75,6 +82,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)
@@ -315,12 +323,17 @@ community_list_entry_lookup (struct community_list *list, const void *arg,
if (community_cmp (entry->u.com, arg))
return entry;
break;
+ case LARGE_COMMUNITY_LIST_STANDARD:
+ if (lcommunity_cmp (entry->u.lcom, arg))
+ return entry;
+ break;
case EXTCOMMUNITY_LIST_STANDARD:
if (ecommunity_cmp (entry->u.ecom, arg))
return entry;
break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
+ case LARGE_COMMUNITY_LIST_EXPANDED:
if (strcmp (entry->config, arg) == 0)
return entry;
break;
@@ -441,6 +454,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)
{
@@ -491,6 +589,30 @@ community_list_match (struct community *com, struct community_list *list)
}

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)
{
struct community_entry *entry;
@@ -638,12 +760,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;
@@ -762,6 +889,186 @@ 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.
+ */
+
+ for (i = 0; i < lcom->size; i++)
+ {
+ ptr = lcom->val + (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)
+ && entry->reg
+ && 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 */
+
+ for (i = delete_index-1; i >= 0; i--)
+ {
+ ptr = lcom->val + (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,
@@ -904,6 +1211,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);
diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h
index 5dcb3b4..d9db418 100644
--- a/bgpd/bgp_clist.h
+++ b/bgpd/bgp_clist.h
@@ -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);
+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 */
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 5d69b42..c06b34e 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -28,6 +28,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. */
diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c
index edd9d76..ea37cc6 100644
--- a/bgpd/bgp_encap.c
+++ b/bgpd/bgp_encap.c
@@ -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"
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c
new file mode 100644
index 0000000..cc67e12
--- /dev/null
+++ b/bgpd/bgp_lcommunity.c
@@ -0,0 +1,562 @@
+/* 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;
+
+ for (i = 0; i < lcom->size; i++) {
+ lcom_ptr = lcom->val + (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++;
+ }
+}
diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h
new file mode 100644
index 0000000..7841b4b
--- /dev/null
+++ b/bgpd/bgp_lcommunity.h
@@ -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 */
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 6465aad..8195e47 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -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"

bool
@@ -647,6 +648,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
u_char origin, attr_chg;
struct community *community, *commerge;
struct ecommunity *ecomm, *ecommerge;
+ struct lcommunity *lcomm, *lcommerge;
struct attr_extra *ae;
struct attr attr = { 0 };

@@ -711,6 +713,8 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
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))
{
@@ -745,6 +749,18 @@ 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;
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 7b8b657..8920ed6 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -144,6 +144,8 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
return 1;
}
break;
+ case AFI_ETHER:
+ break;
}

zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index f42e544..aad5270 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -45,6 +45,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"
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 4cb6c14..c8c0265 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -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.

@@ -44,6 +45,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"
@@ -6428,8 +6430,13 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))
vty_out (vty, " Extended Community: %s%s",
attr->extra->ecommunity->str, VTY_NEWLINE);
-
- /* 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)))
{
@@ -6452,7 +6459,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);

- /* Line 7 display Uptime */
+ /* Line 8 display Uptime */
#ifdef HAVE_CLOCK_MONOTONIC
tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
vty_out (vty, " Last update: %s", ctime(&tbuf));
@@ -6486,6 +6493,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_address,
bgp_show_type_flap_prefix,
@@ -6648,6 +6658,32 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router
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_flap_address
|| type == bgp_show_type_flap_prefix)
{
@@ -9163,6 +9199,84 @@ DEFUN (show_ipv6_mbgp_community_all,
bgp_show_type_community_all, NULL);
}

+/* large-community */
+DEFUN (show_ip_bgp_lcommunity_all,
+ show_ip_bgp_lcommunity_all_cmd,
+ "show ip bgp large-community",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display routes matching the large-communities\n")
+{
+ return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
+ bgp_show_type_lcommunity_all, NULL);
+}
+
+DEFUN (show_ip_bgp_ipv4_lcommunity_all,
+ show_ip_bgp_ipv4_lcommunity_all_cmd,
+ "show ip bgp ipv4 (unicast|multicast) large-community",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-communities\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST,
+ bgp_show_type_lcommunity_all, NULL);
+
+ return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST,
+ bgp_show_type_lcommunity_all, NULL);
+}
+
+DEFUN (show_bgp_lcommunity_all,
+ show_bgp_lcommunity_all_cmd,
+ "show bgp large-community",
+ SHOW_STR
+ BGP_STR
+ "Display routes matching the large-communities\n")
+{
+ return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST,
+ bgp_show_type_lcommunity_all, NULL);
+}
+
+ALIAS (show_bgp_lcommunity_all,
+ show_bgp_ipv6_lcommunity_all_cmd,
+ "show bgp ipv6 large-community",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Display routes matching the large-communities\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_lcommunity_all,
+ show_ipv6_bgp_lcommunity_all_cmd,
+ "show ipv6 bgp large-community",
+ SHOW_STR
+ IPV6_STR
+ BGP_STR
+ "Display routes matching the large-communities\n")
+{
+ return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST,
+ bgp_show_type_lcommunity_all, NULL);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_lcommunity_all,
+ show_ipv6_mbgp_lcommunity_all_cmd,
+ "show ipv6 mbgp large-community",
+ SHOW_STR
+ IPV6_STR
+ MBGP_STR
+ "Display routes matching the large-communities\n")
+{
+ return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST,
+ bgp_show_type_lcommunity_all, NULL);
+}
+
+
DEFUN (show_bgp_ipv4_route_map,
show_bgp_ipv4_route_map_cmd,
"show bgp ipv4 route-map WORD",
@@ -11396,6 +11510,795 @@ DEFUN (show_bgp_ipv6_safi_community_list_exact,
return bgp_show_community_list (vty, argv[1], 1, AFI_IP6, safi);
}

+/*
+ * Large Community show commands.
+ */
+
+DEFUN (show_bgp_afi_lcommunity_all,
+ show_bgp_afi_lcommunity_all_cmd,
+ "show bgp (ipv4|ipv6) large-community",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address family\n"
+ "Display routes matching the large-communities\n")
+{
+ afi_t afi;
+ safi_t safi = SAFI_UNICAST;
+
+ if (bgp_parse_afi(argv[0], &afi)) {
+ vty_out (vty, "Error: Bad AFI: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_show (vty, NULL, afi, safi, bgp_show_type_lcommunity_all, NULL);
+}
+
+static int
+bgp_show_lcommunity (struct vty *vty, const char *view_name, int argc,
+ const char **argv, afi_t afi, safi_t safi)
+{
+ struct lcommunity *lcom;
+ struct buffer *b;
+ struct bgp *bgp;
+ int i;
+ char *str;
+ int first = 0;
+
+ /* BGP structure lookup */
+ if (view_name)
+ {
+ bgp = bgp_lookup_by_name (view_name);
+ if (bgp == NULL)
+ {
+ vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ else
+ {
+ bgp = bgp_get_default ();
+ if (bgp == NULL)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ b = buffer_new (1024);
+ for (i = 0; i < argc; i++)
+ {
+ if (first)
+ buffer_putc (b, ' ');
+ else
+ {
+ if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0))
+ continue;
+ first = 1;
+ }
+
+ buffer_putstr (b, argv[i]);
+ }
+ 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);
+}
+
+DEFUN (show_ip_bgp_lcommunity,
+ show_ip_bgp_lcommunity_cmd,
+ "show ip bgp large-community (AA:BB:CC)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n")
+{
+ return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_ip_bgp_lcommunity,
+ show_ip_bgp_lcommunity2_cmd,
+ "show ip bgp large-community (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_ip_bgp_lcommunity,
+ show_ip_bgp_lcommunity3_cmd,
+ "show ip bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "largecommunity number\n"
+ "largecommunity number\n"
+ "largecommunity number\n")
+
+ALIAS (show_ip_bgp_lcommunity,
+ show_ip_bgp_lcommunity4_cmd,
+ "show ip bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+DEFUN (show_ip_bgp_ipv4_lcommunity,
+ show_ip_bgp_ipv4_lcommunity_cmd,
+ "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_MULTICAST);
+
+ return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_ip_bgp_ipv4_lcommunity,
+ show_ip_bgp_ipv4_lcommunity2_cmd,
+ "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_ip_bgp_ipv4_lcommunity,
+ show_ip_bgp_ipv4_lcommunity3_cmd,
+ "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_ip_bgp_ipv4_lcommunity,
+ show_ip_bgp_ipv4_lcommunity4_cmd,
+ "show ip bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+DEFUN (show_bgp_lcommunity,
+ show_bgp_lcommunity_cmd,
+ "show bgp large-community (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n")
+{
+ return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_lcommunity,
+ show_bgp_ipv6_lcommunity_cmd,
+ "show bgp ipv6 large-community (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+ show_bgp_lcommunity2_cmd,
+ "show bgp large-community (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+ show_bgp_ipv6_lcommunity2_cmd,
+ "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+ show_bgp_lcommunity3_cmd,
+ "show bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+ show_bgp_ipv6_lcommunity3_cmd,
+ "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+ show_bgp_lcommunity4_cmd,
+ "show bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_lcommunity,
+ show_bgp_ipv6_lcommunity4_cmd,
+ "show bgp ipv6 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_lcommunity,
+ show_ipv6_bgp_lcommunity_cmd,
+ "show ipv6 bgp large-community (AA:BB:CC)",
+ SHOW_STR
+ IPV6_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n")
+{
+ return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_UNICAST);
+}
+
+/* old command */
+ALIAS (show_ipv6_bgp_lcommunity,
+ show_ipv6_bgp_lcommunity2_cmd,
+ "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IPV6_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n")
+
+/* old command */
+ALIAS (show_ipv6_bgp_lcommunity,
+ show_ipv6_bgp_lcommunity3_cmd,
+ "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IPV6_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+/* old command */
+ALIAS (show_ipv6_bgp_lcommunity,
+ show_ipv6_bgp_lcommunity4_cmd,
+ "show ipv6 bgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IPV6_STR
+ BGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+/* old command */
+DEFUN (show_ipv6_mbgp_lcommunity,
+ show_ipv6_mbgp_lcommunity_cmd,
+ "show ipv6 mbgp large-community (AA:BB:CC)",
+ SHOW_STR
+ IPV6_STR
+ MBGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n")
+{
+ return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP6, SAFI_MULTICAST);
+}
+
+/* old command */
+ALIAS (show_ipv6_mbgp_lcommunity,
+ show_ipv6_mbgp_lcommunity2_cmd,
+ "show ipv6 mbgp large-community (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IPV6_STR
+ MBGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n")
+
+/* old command */
+ALIAS (show_ipv6_mbgp_lcommunity,
+ show_ipv6_mbgp_lcommunity3_cmd,
+ "show ipv6 mbgp large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IPV6_STR
+ MBGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+/* old command */
+ALIAS (show_ipv6_mbgp_lcommunity,
+ show_ipv6_mbgp_lcommunity4_cmd,
+ "show ipv6 mbgp laarge-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ IPV6_STR
+ MBGP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+DEFUN (show_bgp_ipv4_lcommunity,
+ show_bgp_ipv4_lcommunity_cmd,
+ "show bgp ipv4 large-community (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ IP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n")
+{
+ return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_ipv4_lcommunity,
+ show_bgp_ipv4_lcommunity2_cmd,
+ "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ IP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_ipv4_lcommunity,
+ show_bgp_ipv4_lcommunity3_cmd,
+ "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ IP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_ipv4_lcommunity,
+ show_bgp_ipv4_lcommunity4_cmd,
+ "show bgp ipv4 large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ IP_STR
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+DEFUN (show_bgp_ipv4_safi_lcommunity,
+ show_bgp_ipv4_safi_lcommunity_cmd,
+ "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_MULTICAST);
+
+ return bgp_show_lcommunity (vty, NULL, argc, argv, AFI_IP, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_ipv4_safi_lcommunity,
+ show_bgp_ipv4_safi_lcommunity2_cmd,
+ "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_ipv4_safi_lcommunity,
+ show_bgp_ipv4_safi_lcommunity3_cmd,
+ "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_ipv4_safi_lcommunity,
+ show_bgp_ipv4_safi_lcommunity4_cmd,
+ "show bgp ipv4 (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+DEFUN (show_bgp_view_afi_safi_lcommunity_all,
+ show_bgp_view_afi_safi_lcommunity_all_cmd,
+ "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Address family\n"
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-communities\n")
+{
+ int afi;
+ int safi;
+ struct bgp *bgp;
+
+ /* BGP structure lookup. */
+ bgp = bgp_lookup_by_name (argv[0]);
+ if (bgp == NULL)
+ {
+ vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
+ safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+ return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL);
+}
+
+DEFUN (show_bgp_view_afi_safi_lcommunity,
+ show_bgp_view_afi_safi_lcommunity_cmd,
+ "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Address family\n"
+ "Address family\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n")
+{
+ int afi;
+ int safi;
+
+ afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
+ safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+ return bgp_show_lcommunity (vty, argv[0], argc-3, &argv[3], afi, safi);
+}
+
+ALIAS (show_bgp_view_afi_safi_lcommunity,
+ show_bgp_view_afi_safi_lcommunity2_cmd,
+ "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Address family\n"
+ "Address family\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_view_afi_safi_lcommunity,
+ show_bgp_view_afi_safi_lcommunity3_cmd,
+ "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Address family\n"
+ "Address family\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_view_afi_safi_lcommunity,
+ show_bgp_view_afi_safi_lcommunity4_cmd,
+ "show bgp view WORD (ipv4|ipv6) (unicast|multicast) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "BGP view\n"
+ "View name\n"
+ "Address family\n"
+ "Address family\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+DEFUN (show_bgp_ipv6_safi_lcommunity,
+ show_bgp_ipv6_safi_lcommunity_cmd,
+ "show bgp ipv6 (encap|multicast|unicast|vpn) large-community AA:BB:CC",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n")
+{
+ safi_t safi;
+
+ if (bgp_parse_safi(argv[0], &safi)) {
+ vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_show_lcommunity (vty, NULL, argc-1, argv+1, AFI_IP6, safi);
+}
+
+ALIAS (show_bgp_ipv6_safi_lcommunity,
+ show_bgp_ipv6_safi_lcommunity2_cmd,
+ "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_ipv6_safi_lcommunity,
+ show_bgp_ipv6_safi_lcommunity3_cmd,
+ "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+ALIAS (show_bgp_ipv6_safi_lcommunity,
+ show_bgp_ipv6_safi_lcommunity4_cmd,
+ "show bgp ipv6 (encap|multicast|unicast|vpn) large-community (AA:BB:CC) (AA:BB:CC) (AA:BB:CC) (AA:BB:CC)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Display routes matching the large-communities\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n"
+ "large-community number\n")
+
+static int
+bgp_show_lcommunity_list (struct vty *vty, const char *lcom,
+ afi_t afi, safi_t safi)
+{
+ 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, NULL, afi, safi, bgp_show_type_lcommunity_list, list);
+}
+
+DEFUN (show_ip_bgp_lcommunity_list,
+ show_ip_bgp_lcommunity_list_cmd,
+ "show ip bgp large-community-list (<1-500>|WORD)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Display routes matching the large-community-list\n"
+ "large-community-list number\n"
+ "large-community-list name\n")
+{
+ return bgp_show_lcommunity_list (vty, argv[0], AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_ip_bgp_ipv4_lcommunity_list,
+ show_ip_bgp_ipv4_lcommunity_list_cmd,
+ "show ip bgp ipv4 (unicast|multicast) large-community-list (<1-500>|WORD)",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-community-list\n"
+ "large-community-list number\n"
+ "large-community-list name\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_MULTICAST);
+
+ return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_bgp_lcommunity_list,
+ show_bgp_lcommunity_list_cmd,
+ "show bgp large-community-list (<1-500>|WORD)",
+ SHOW_STR
+ BGP_STR
+ "Display routes matching the large-community-list\n"
+ "large-community-list number\n"
+ "large-community-list name\n")
+{
+ return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
+ALIAS (show_bgp_lcommunity_list,
+ show_bgp_ipv6_lcommunity_list_cmd,
+ "show bgp ipv6 large-community-list (<1-500>|WORD)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Display routes matching the large-community-list\n"
+ "large-community-list number\n"
+ "large-community-list name\n")
+
+/* old command */
+DEFUN (show_ipv6_bgp_lcommunity_list,
+ show_ipv6_bgp_lcommunity_list_cmd,
+ "show ipv6 bgp large-community-list WORD",
+ SHOW_STR
+ IPV6_STR
+ BGP_STR
+ "Display routes matching the large-community-list\n"
+ "large-community-list name\n")
+{
+ return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
+/* old command */
+DEFUN (show_ipv6_mbgp_lcommunity_list,
+ show_ipv6_mbgp_lcommunity_list_cmd,
+ "show ipv6 mbgp large-community-list WORD",
+ SHOW_STR
+ IPV6_STR
+ MBGP_STR
+ "Display routes matching the large-community-list\n"
+ "large-community-list name\n")
+{
+ return bgp_show_lcommunity_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST);
+}
+
+DEFUN (show_bgp_ipv4_lcommunity_list,
+ show_bgp_ipv4_lcommunity_list_cmd,
+ "show bgp ipv4 large-community-list (<1-500>|WORD)",
+ SHOW_STR
+ BGP_STR
+ IP_STR
+ "Display routes matching the large-community-list\n"
+ "large-community-list number\n"
+ "large-community-list name\n")
+{
+ return bgp_show_lcommunity_list (vty, argv[0], AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_bgp_ipv4_safi_lcommunity_list,
+ show_bgp_ipv4_safi_lcommunity_list_cmd,
+ "show bgp ipv4 (unicast|multicast) large-community-list (<1-500>|WORD)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address Family modifier\n"
+ "Address Family modifier\n"
+ "Display routes matching the large-community-list\n"
+ "large-community-list number\n"
+ "large-community-list name\n")
+{
+ if (strncmp (argv[0], "m", 1) == 0)
+ return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_MULTICAST);
+
+ return bgp_show_lcommunity_list (vty, argv[1], AFI_IP, SAFI_UNICAST);
+}
+
+DEFUN (show_bgp_ipv6_safi_lcommunity_list,
+ show_bgp_ipv6_safi_lcommunity_list_cmd,
+ "show bgp ipv6 (encap|multicast|unicast|vpn) large-community-list (<1-500>|WORD)",
+ SHOW_STR
+ BGP_STR
+ "Address family\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Address family modifier\n"
+ "Display routes matching the large-community-list\n"
+ "large-community-list number\n"
+ "large-community-list name\n")
+{
+ safi_t safi;
+
+ if (bgp_parse_safi(argv[0], &safi)) {
+ vty_out (vty, "Error: Bad SAFI: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_show_lcommunity_list (vty, argv[1], AFI_IP6, safi);
+}
+
static int
bgp_show_prefix_longer (struct vty *vty, const char *prefix, afi_t afi,
safi_t safi, enum bgp_show_type type)
@@ -16407,6 +17310,24 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_cmd);
install_element (VIEW_NODE, &show_bgp_ipv4_community_list_exact_cmd);
install_element (VIEW_NODE, &show_bgp_ipv4_safi_community_list_exact_cmd);
+
+ /* large-communities */
+ install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity2_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity3_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity4_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity2_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity3_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity4_cmd);
+ install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity_all_cmd);
+ install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity_cmd);
+ install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity2_cmd);
+ install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity3_cmd);
+ install_element (VIEW_NODE, &show_bgp_view_afi_safi_lcommunity4_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_lcommunity_list_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv4_safi_lcommunity_list_cmd);
+
install_element (VIEW_NODE, &show_bgp_ipv4_prefix_longer_cmd);
install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_longer_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_longer_cmd);
@@ -16504,6 +17425,22 @@ bgp_route_init (void)
install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community2_exact_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community3_exact_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_community4_exact_cmd);
+
+ /* large-community */
+ install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity2_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity3_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv4_lcommunity4_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity2_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity3_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_lcommunity4_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity_all_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity2_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity3_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_lcommunity4_cmd);
+
install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd);
install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd);
@@ -16512,6 +17449,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);

@@ -16556,6 +17494,14 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_bgp_ipv6_safi_community3_exact_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_safi_community4_exact_cmd);
install_element (VIEW_NODE, &show_bgp_community_list_cmd);
+
+ /* large-community */
+ install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity2_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity3_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity4_cmd);
+ install_element (VIEW_NODE, &show_bgp_lcommunity_list_cmd);
+
install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd);
@@ -16602,6 +17548,10 @@ bgp_route_init (void)
install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community2_exact_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community3_exact_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_community4_exact_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity2_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity3_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_lcommunity4_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_route_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_prefix_cmd);
@@ -16751,6 +17701,18 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd);
install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_lcommunity_all_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_all_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_lcommunity_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_lcommunity2_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_lcommunity3_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_lcommunity4_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity2_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity3_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity4_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_lcommunity_list_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_ipv4_lcommunity_list_cmd);
install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd);
install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd);
@@ -16824,6 +17786,14 @@ bgp_route_init (void)
install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_exact_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_exact_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_exact_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity2_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity3_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_lcommunity4_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity2_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity3_cmd);
+ install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_lcommunity4_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_route_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd);
@@ -16860,6 +17830,13 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_cmd);
install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_safi_community_list_exact_cmd);
+ install_element (VIEW_NODE, &show_bgp_lcommunity_all_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_all_cmd);
+ install_element (VIEW_NODE, &show_bgp_lcommunity_cmd);
+ install_element (VIEW_NODE, &show_bgp_lcommunity2_cmd);
+ install_element (VIEW_NODE, &show_bgp_lcommunity3_cmd);
+ install_element (VIEW_NODE, &show_bgp_lcommunity4_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_safi_lcommunity_list_cmd);
install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd);
install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd);
install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd);
@@ -16895,6 +17872,10 @@ bgp_route_init (void)
install_element (RESTRICTED_NODE, &show_bgp_community2_exact_cmd);
install_element (RESTRICTED_NODE, &show_bgp_community3_exact_cmd);
install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_lcommunity_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_lcommunity2_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_lcommunity3_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_lcommunity4_cmd);
install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd);
install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd);
install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd);
@@ -16919,6 +17900,12 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd);
install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd);
install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd);
+ install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_all_cmd);
+ install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_cmd);
+ install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity2_cmd);
+ install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity3_cmd);
+ install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity4_cmd);
+ install_element (VIEW_NODE, &show_ipv6_bgp_lcommunity_list_cmd);
install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd);
install_element (VIEW_NODE, &show_ipv6_mbgp_cmd);
install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd);
@@ -16937,6 +17924,12 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd);
install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd);
install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_all_cmd);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_cmd);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity2_cmd);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity3_cmd);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity4_cmd);
+ install_element (VIEW_NODE, &show_ipv6_mbgp_lcommunity_list_cmd);
install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd);
install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd);
install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd);
@@ -16965,6 +17958,16 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd);

+ install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity2_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity3_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity4_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity2_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity3_cmd);
+ install_element (RESTRICTED_NODE, &show_bgp_ipv6_lcommunity4_cmd);
+ install_element (VIEW_NODE, &show_bgp_ipv6_lcommunity_list_cmd);
+
install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd);
install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd);
install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index c66f260..8f3632a 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -51,6 +51,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"

/* Memo of route-map commands.
@@ -59,6 +60,7 @@ o Cisco route-map

match as-path : Done
community : Done
+ lcommunity : Done
interface : Not yet
ip address : Done
ip next-hop : Done
@@ -78,6 +80,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)
@@ -840,21 +844,93 @@ 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,
+route_match_ecommunity (void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
struct community_list *list;
struct bgp_info *bgp_info;

- if (type == RMAP_BGP)
+ if (type == RMAP_BGP)
{
bgp_info = object;
-
+
if (!bgp_info->attr->extra)
return RMAP_NOMATCH;
-
+
list = community_list_lookup (bgp_clist, (char *) rule,
EXTCOMMUNITY_LIST_MASTER);
if (! list)
@@ -1504,6 +1580,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. */
@@ -3032,6 +3327,32 @@ ALIAS (no_match_community,
"Community-list name\n"
"Do exact matching of communities\n")

+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, vty->index, "large-community", argv[0]);
+}
+
+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, vty->index, "large-community", NULL);
+}
+
+
DEFUN (match_ecommunity,
match_ecommunity_cmd,
"match extcommunity (<1-99>|<100-500>|WORD)",
@@ -3612,6 +3933,104 @@ ALIAS (no_set_community_delete,
"Community-list name\n"
"Delete matching communities\n")

+
+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, 0);
+ ret = bgp_route_set_add (vty, vty->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 bgp_route_set_add (vty, vty->index, "large-community", "none");
+}
+
+DEFUN (no_set_lcommunity,
+ no_set_lcommunity_cmd,
+ "no set large-community",
+ NO_STR
+ SET_STR
+ "BGP large community attribute\n"
+ "Large community\n")
+{
+ return bgp_route_set_delete (vty, vty->index, "large-community", NULL);
+}
+
+ALIAS (no_set_lcommunity,
+ no_set_lcommunity_val_cmd,
+ "no set large-community .AA:BB:CC",
+ NO_STR
+ SET_STR
+ "BGP large community attribute\n"
+ "Large community in .AA:BB:CC format or additive\n")
+
+ALIAS (no_set_lcommunity,
+ no_set_lcommunity_none_cmd,
+ "no set large-community none",
+ NO_STR
+ SET_STR
+ "BGP community attribute\n"
+ "No community attribute\n")
+
+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[0]) + strlen (" delete") + 1);
+ strcpy (str, argv[0]);
+ strcpy (str + strlen (argv[0]), " delete");
+
+ bgp_route_set_add (vty, vty->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",
+ NO_STR
+ SET_STR
+ "set BGP large community list (for deletion)\n")
+{
+ return bgp_route_set_delete (vty, vty->index, "large-comm-list", NULL);
+}
+
+ALIAS (no_set_lcommunity_delete,
+ no_set_lcommunity_delete_val_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")
+
DEFUN (set_ecommunity_rt,
set_ecommunity_rt_cmd,
"set extcommunity rt .ASN:nn_or_IP-address:nn",
@@ -4170,6 +4589,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);
@@ -4188,6 +4608,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);
@@ -4232,6 +4654,8 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &no_match_community_cmd);
install_element (RMAP_NODE, &no_match_community_val_cmd);
install_element (RMAP_NODE, &no_match_community_exact_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, &no_match_ecommunity_val_cmd);
@@ -4283,6 +4707,14 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &set_community_delete_cmd);
install_element (RMAP_NODE, &no_set_community_delete_cmd);
install_element (RMAP_NODE, &no_set_community_delete_val_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, &no_set_lcommunity_val_cmd);
+ install_element (RMAP_NODE, &no_set_lcommunity_none_cmd);
+ install_element (RMAP_NODE, &set_lcommunity_delete_cmd);
+ install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd);
+ install_element (RMAP_NODE, &no_set_lcommunity_delete_val_cmd);
install_element (RMAP_NODE, &set_ecommunity_rt_cmd);
install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd);
install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 7af4e81..bf53086 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -38,6 +38,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"
@@ -2364,13 +2365,15 @@ DEFUN (no_neighbor_send_community,
/* neighbor send-community extended. */
DEFUN (neighbor_send_community_type,
neighbor_send_community_type_cmd,
- NEIGHBOR_CMD2 "send-community (both|extended|standard)",
+ NEIGHBOR_CMD2 "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 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")
{
if (strncmp (argv[1], "s", 1) == 0)
return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
@@ -2380,23 +2383,30 @@ DEFUN (neighbor_send_community_type,
return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty),
PEER_FLAG_SEND_EXT_COMMUNITY);
+ if (strncmp (argv[1], "l", 1) == 0)
+ return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_SEND_LARGE_COMMUNITY);

return peer_af_flag_set_vty (vty, argv[0], 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));
}

DEFUN (no_neighbor_send_community_type,
no_neighbor_send_community_type_cmd,
- NO_NEIGHBOR_CMD2 "send-community (both|extended|standard)",
+ NO_NEIGHBOR_CMD2 "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 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")
{
if (strncmp (argv[1], "s", 1) == 0)
return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
@@ -2406,11 +2416,16 @@ DEFUN (no_neighbor_send_community_type,
return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
bgp_node_safi (vty),
PEER_FLAG_SEND_EXT_COMMUNITY);
+ if (strncmp (argv[1], "l", 1) == 0)
+ return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_SEND_LARGE_COMMUNITY);

return peer_af_flag_unset_vty (vty, argv[0], 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. */
@@ -7434,7 +7449,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,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
@@ -8232,14 +8252,18 @@ 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_EXT_COMMUNITY))
vty_out (vty, "(extended)%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
vty_out (vty, "(standard)%s", VTY_NEWLINE);
}
@@ -9097,6 +9121,35 @@ 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",
@@ -11206,6 +11259,9 @@ 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);

@@ -11691,6 +11747,359 @@ DEFUN (show_ip_community_list_arg,
return CMD_SUCCESS;
}

+/*
+ * Large Community code.
+ */
+static int
+lcommunity_list_set_vty (struct vty *vty, int argc, const char **argv,
+ int style, int reject_all_digit_name)
+{
+ int ret;
+ int direct;
+ char *str;
+
+ /* Check the list type. */
+ if (strncmp (argv[1], "p", 1) == 0)
+ direct = COMMUNITY_PERMIT;
+ else if (strncmp (argv[1], "d", 1) == 0)
+ direct = COMMUNITY_DENY;
+ else
+ {
+ vty_out (vty, "%% Matching condition must be permit or deny%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* All digit name check. */
+ if (reject_all_digit_name && all_digit (argv[0]))
+ {
+ vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Concat community string argument. */
+ if (argc > 1)
+ str = argv_concat (argv, argc, 2);
+ else
+ str = NULL;
+
+ ret = lcommunity_list_set (bgp_clist, argv[0], 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, const char **argv,
+ int style)
+{
+ int ret;
+ int direct = 0;
+ char *str = NULL;
+
+ if (argc > 1)
+ {
+ /* Check the list direct. */
+ if (strncmp (argv[1], "p", 1) == 0)
+ direct = COMMUNITY_PERMIT;
+ else if (strncmp (argv[1], "d", 1) == 0)
+ direct = COMMUNITY_DENY;
+ else
+ {
+ vty_out (vty, "%% Matching condition must be permit or deny%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Concat community string argument. */
+ str = argv_concat (argv, argc, 2);
+ }
+
+ /* Unset community list. */
+ ret = lcommunity_list_unset (bgp_clist, argv[0], 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);
+}
+
+ALIAS (ip_lcommunity_list_standard,
+ ip_lcommunity_list_standard2_cmd,
+ "ip large-community-list <1-99> (deny|permit)",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (standard)\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n")
+
+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);
+}
+
+ALIAS (ip_lcommunity_list_name_standard,
+ ip_lcommunity_list_name_standard2_cmd,
+ "ip large-community-list standard WORD (deny|permit)",
+ 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")
+
+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>",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (standard)\n")
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_lcommunity_list_expanded_all,
+ no_ip_lcommunity_list_expanded_all_cmd,
+ "no ip large-community-list <100-500>",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (expanded)\n")
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
+}
+
+DEFUN (no_ip_lcommunity_list_name_standard_all,
+ no_ip_lcommunity_list_name_standard_all_cmd,
+ "no ip large-community-list standard WORD",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify standard large-community-list\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[0], 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;
+}
+
static int
extcommunity_list_set_vty (struct vty *vty, int argc, const char **argv,
int style, int reject_all_digit_name)
@@ -12113,6 +12522,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;
}

@@ -12163,4 +12596,22 @@ community_list_vty (void)
install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_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_standard2_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_standard2_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_expanded_all_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_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);
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 018a599..b654117 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -627,6 +627,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 */
@@ -861,6 +862,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;
}
@@ -2508,6 +2510,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] =
{ PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out },
{ 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_SOFT_RECONFIG, 0, peer_change_reset_in },
{ PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset },
{ PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset },
@@ -5251,23 +5254,31 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
{
if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
- && peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
- vty_out (vty, " neighbor %s send-community both%s", addr, VTY_NEWLINE);
+ && peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)
+ && peer_af_flag_check(peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
+ vty_out (vty, " neighbor %s send-community all%s", addr, VTY_NEWLINE);
else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
vty_out (vty, " neighbor %s send-community extended%s",
addr, VTY_NEWLINE);
+ else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
+ vty_out (vty, " neighbor %s send-community large%s",
+ addr, VTY_NEWLINE);
else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY))
vty_out (vty, " neighbor %s send-community%s", addr, VTY_NEWLINE);
}
else
{
if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
- && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
- vty_out (vty, " no neighbor %s send-community both%s",
+ && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)
+ && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
+ vty_out (vty, " no neighbor %s send-community all%s",
addr, VTY_NEWLINE);
else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
vty_out (vty, " no neighbor %s send-community extended%s",
addr, VTY_NEWLINE);
+ else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
+ vty_out (vty, " no neighbor %s send-community large%s",
+ addr, VTY_NEWLINE);
else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY))
vty_out (vty, " no neighbor %s send-community%s",
addr, VTY_NEWLINE);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 0058b58..e0744ea 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -425,6 +425,7 @@ struct peer
#define PEER_FLAG_MAX_PREFIX_WARNING (1 << 15) /* maximum prefix warning-only */
#define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1 << 16) /* leave link-local nexthop unchanged */
#define PEER_FLAG_NEXTHOP_SELF_ALL (1 << 17) /* next-hop-self all */
+#define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 18) /* Send large Communities */

/* MD5 password */
char *password;
@@ -655,6 +656,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

/* BGP update origin. */
#define BGP_ORIGIN_IGP 0
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 8abe99d..768efa7 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -157,6 +157,9 @@ struct memory_list memory_list_bgp[] =
{ MTYPE_BGP_AGGREGATE, "BGP aggregate" },
{ MTYPE_BGP_ADDR, "BGP own address" },
{ MTYPE_ENCAP_TLV, "ENCAP TLV", },
+ { MTYPE_LCOMMUNITY, "Large Community", },
+ { MTYPE_LCOMMUNITY_STR, "Large Community str", },
+ { MTYPE_LCOMMUNITY_VAL, "Large Community val", },
{ -1, NULL }
};

--
2.10.1 (Apple Git-78)


_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev