summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/Makefile.am6
-rw-r--r--bgpd/bgp_attr.c103
-rw-r--r--bgpd/bgp_attr.h5
-rw-r--r--bgpd/bgp_clist.c320
-rw-r--r--bgpd/bgp_clist.h18
-rw-r--r--bgpd/bgp_ecommunity.c1
-rw-r--r--bgpd/bgp_encap.c1
-rw-r--r--bgpd/bgp_lcommunity.c569
-rw-r--r--bgpd/bgp_lcommunity.h74
-rw-r--r--bgpd/bgp_memory.c4
-rw-r--r--bgpd/bgp_memory.h3
-rw-r--r--bgpd/bgp_mpath.c14
-rw-r--r--bgpd/bgp_mplsvpn.h8
-rw-r--r--bgpd/bgp_packet.c1
-rw-r--r--bgpd/bgp_route.c192
-rw-r--r--bgpd/bgp_route.h3
-rw-r--r--bgpd/bgp_routemap.c418
-rw-r--r--bgpd/bgp_vty.c473
-rw-r--r--bgpd/bgpd.c27
-rw-r--r--bgpd/bgpd.h2
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c784
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.h23
-rw-r--r--bgpd/rfapi/rfapi.c97
-rw-r--r--bgpd/rfapi/rfapi_backend.h9
-rw-r--r--bgpd/rfapi/rfapi_import.c17
-rw-r--r--bgpd/rfapi/rfapi_import.h8
-rw-r--r--bgpd/rfapi/rfapi_private.h14
-rw-r--r--bgpd/rfapi/rfapi_rib.c6
-rw-r--r--bgpd/rfapi/rfapi_vty.c640
-rwxr-xr-xconfigure.ac3
-rw-r--r--lib/Makefile.am5
-rw-r--r--lib/command.c35
-rw-r--r--lib/command.h25
-rw-r--r--lib/command_lex.l13
-rw-r--r--lib/command_match.c39
-rw-r--r--lib/command_parse.y253
-rw-r--r--lib/grammar_sandbox.c242
-rw-r--r--lib/grammar_sandbox.h56
-rw-r--r--lib/grammar_sandbox_main.c64
-rw-r--r--lib/routemap.c7
-rw-r--r--lib/routemap.h2
-rw-r--r--lib/vty.c1
-rw-r--r--lib/zclient.c1
-rw-r--r--pimd/pim_cmd.c91
-rw-r--r--tests/testcli.refout8
-rw-r--r--tools/permutations.c2
-rw-r--r--vtysh/vtysh.c39
-rw-r--r--zebra/zebra_fpm_dt.c2
48 files changed, 4093 insertions, 635 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index 69c0504af4..6e36a950d6 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -75,7 +75,8 @@ libbgp_a_SOURCES = \
bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \
bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
- bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
+ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_lcommunity.c \
+ bgp_mplsvpn.c bgp_nexthop.c \
bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC)
@@ -85,7 +86,8 @@ noinst_HEADERS = \
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
- bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
+ bgp_ecommunity.h bgp_lcommunity.h \
+ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \
bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \
$(BGP_VNC_RFAPI_HD)
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 7538a50770..f4995faab0 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -42,6 +42,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_encap_types.h"
#if ENABLE_BGP_VNC
@@ -76,6 +77,7 @@ static const struct message attr_str [] =
#if ENABLE_BGP_VNC
{ BGP_ATTR_VNC, "VNC" },
#endif
+ { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }
};
static const int attr_str_max = array_size(attr_str);
@@ -670,6 +672,8 @@ attrhash_key_make (void *p)
if (extra)
{
+ if (extra->lcommunity)
+ MIX(lcommunity_hash_make (extra->lcommunity));
if (extra->ecommunity)
MIX(ecommunity_hash_make (extra->ecommunity));
if (extra->cluster)
@@ -718,6 +722,7 @@ attrhash_cmp (const void *p1, const void *p2)
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
&& IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
&& ae1->ecommunity == ae2->ecommunity
+ && ae1->lcommunity == ae2->lcommunity
&& ae1->cluster == ae2->cluster
&& ae1->transit == ae2->transit
&& (ae1->encap_tunneltype == ae2->encap_tunneltype)
@@ -836,6 +841,13 @@ bgp_attr_intern (struct attr *attr)
attre->ecommunity->refcnt++;
}
+ if (attre->lcommunity)
+ {
+ if (! attre->lcommunity->refcnt)
+ attre->lcommunity = lcommunity_intern (attre->lcommunity);
+ else
+ attre->lcommunity->refcnt++;
+ }
if (attre->cluster)
{
if (! attre->cluster->refcnt)
@@ -1026,7 +1038,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));
@@ -1096,6 +1112,8 @@ bgp_attr_flush (struct attr *attr)
if (attre->ecommunity && ! attre->ecommunity->refcnt)
ecommunity_free (&attre->ecommunity);
+ if (attre->lcommunity && ! attre->lcommunity->refcnt)
+ lcommunity_free (&attre->lcommunity);
if (attre->cluster && ! attre->cluster->refcnt)
{
cluster_free (attre->cluster);
@@ -1254,6 +1272,7 @@ const u_int8_t attr_flags_values [] = {
[BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_LARGE_COMMUNITIES]= BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
};
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
@@ -2044,6 +2063,40 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
return BGP_ATTR_PARSE_PROCEED;
}
+/* Large Community attribute. */
+static bgp_attr_parse_ret_t
+bgp_attr_large_community (struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ /*
+ * Large community follows new attribute format.
+ */
+ if (length == 0)
+ {
+ if (attr->extra)
+ attr->extra->lcommunity = NULL;
+ /* Empty extcomm doesn't seem to be invalid per se */
+ return BGP_ATTR_PARSE_PROCEED;
+ }
+
+ (bgp_attr_extra_get (attr))->lcommunity =
+ lcommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
+ /* XXX: fix ecommunity_parse to use stream API */
+ stream_forward_getp (peer->ibuf, length);
+
+ if (attr->extra && !attr->extra->lcommunity)
+ return bgp_attr_malformed (args,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
+
+ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
+
+ return BGP_ATTR_PARSE_PROCEED;
+}
+
/* Extended Community attribute. */
static bgp_attr_parse_ret_t
bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
@@ -2065,7 +2118,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);
@@ -2479,6 +2532,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;
@@ -3106,6 +3162,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
@@ -3338,6 +3416,7 @@ bgp_attr_init (void)
attrhash_init ();
community_init ();
ecommunity_init ();
+ lcommunity_init ();
cluster_init ();
transit_init ();
encap_init ();
@@ -3350,6 +3429,7 @@ bgp_attr_finish (void)
attrhash_finish ();
community_finish ();
ecommunity_finish ();
+ lcommunity_finish ();
cluster_finish ();
transit_finish ();
encap_finish ();
@@ -3453,6 +3533,25 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
stream_put (s, attr->community->val, attr->community->size * 4);
}
+ /* Large Community attribute. */
+ if (attr->extra && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES))
+ {
+ if (attr->extra->lcommunity->size * 12 > 255)
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
+ stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
+ stream_putw (s, attr->extra->lcommunity->size * 12);
+ }
+ else
+ {
+ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
+ stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
+ stream_putc (s, attr->extra->lcommunity->size * 12);
+ }
+
+ stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12);
+ }
+
/* Add a MP_NLRI attribute to dump the IPv6 next hop */
if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
(attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 6e639078d6..c5799ccd0d 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -92,7 +92,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 9032b1e2f4..b37034bf29 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgpd.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_clist.h"
@@ -42,9 +43,11 @@ community_list_master_lookup (struct community_list_handler *ch, int master)
switch (master)
{
case COMMUNITY_LIST_MASTER:
- return &ch->community_list;
+ return &ch->community_list;
case EXTCOMMUNITY_LIST_MASTER:
- return &ch->extcommunity_list;
+ return &ch->extcommunity_list;
+ case LARGE_COMMUNITY_LIST_MASTER:
+ return &ch->lcommunity_list;
}
return NULL;
}
@@ -66,6 +69,10 @@ community_entry_free (struct community_entry *entry)
if (entry->u.com)
community_free (entry->u.com);
break;
+ case LARGE_COMMUNITY_LIST_STANDARD:
+ if (entry->u.lcom)
+ lcommunity_free (&entry->u.lcom);
+ break;
case EXTCOMMUNITY_LIST_STANDARD:
/* In case of standard extcommunity-list, configuration string
is made by ecommunity_ecom2str(). */
@@ -76,6 +83,7 @@ community_entry_free (struct community_entry *entry)
break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
+ case LARGE_COMMUNITY_LIST_EXPANDED:
if (entry->config)
XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
if (entry->reg)
@@ -320,8 +328,13 @@ community_list_entry_lookup (struct community_list *list, const void *arg,
if (entry->direct == direct && ecommunity_cmp (entry->u.ecom, arg))
return entry;
break;
+ case LARGE_COMMUNITY_LIST_STANDARD:
+ if (entry->direct == direct && lcommunity_cmp (entry->u.lcom, arg))
+ return entry;
+ break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
+ case LARGE_COMMUNITY_LIST_EXPANDED:
if (entry->direct == direct && strcmp (entry->config, arg) == 0)
return entry;
break;
@@ -399,15 +412,14 @@ community_str_get (struct community *com, int i)
}
/* Internal function to perform regular expression match for
- * * a single community. */
+ * a single community. */
static int
community_regexp_include (regex_t * reg, struct community *com, int i)
{
char *str;
int rv;
- /* When there is no communities attribute it is treated as empty
- * string. */
+ /* When there is no communities attribute it is treated as empty string. */
if (com == NULL || com->size == 0)
str = XSTRDUP(MTYPE_COMMUNITY_STR, "");
else
@@ -447,6 +459,90 @@ 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)
{
@@ -547,6 +643,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;
@@ -694,12 +814,17 @@ community_list_dup_check (struct community_list *list,
if (community_cmp (entry->u.com, new->u.com))
return 1;
break;
+ case LARGE_COMMUNITY_LIST_STANDARD:
+ if (lcommunity_cmp (entry->u.lcom, new->u.lcom))
+ return 1;
+ break;
case EXTCOMMUNITY_LIST_STANDARD:
if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
return 1;
break;
case COMMUNITY_LIST_EXPANDED:
case EXTCOMMUNITY_LIST_EXPANDED:
+ case LARGE_COMMUNITY_LIST_EXPANDED:
if (strcmp (entry->config, new->config) == 0)
return 1;
break;
@@ -817,6 +942,185 @@ community_list_unset (struct community_list_handler *ch,
return 0;
}
+/* Delete all permitted large communities in the list from com. */
+struct lcommunity *
+lcommunity_list_match_delete (struct lcommunity *lcom,
+ struct community_list *list)
+{
+ struct community_entry *entry;
+ u_int32_t com_index_to_delete[lcom->size];
+ u_char *ptr;
+ int delete_index = 0;
+ int i;
+
+ /* Loop over each lcommunity value and evaluate each against the
+ * community-list. If we need to delete a community value add its index to
+ * com_index_to_delete.
+ */
+ ptr = lcom->val;
+ for (i = 0; i < lcom->size; i++)
+ {
+ ptr += (i * LCOMMUNITY_SIZE);
+ for (entry = list->head; entry; entry = entry->next)
+ {
+ if (entry->any)
+ {
+ if (entry->direct == COMMUNITY_PERMIT)
+ {
+ com_index_to_delete[delete_index] = i;
+ delete_index++;
+ }
+ break;
+ }
+
+ else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
+ && lcommunity_include (entry->u.lcom, ptr) )
+ {
+ if (entry->direct == COMMUNITY_PERMIT)
+ {
+ com_index_to_delete[delete_index] = i;
+ delete_index++;
+ }
+ break;
+ }
+
+ else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
+ && lcommunity_regexp_include (entry->reg, lcom, i))
+ {
+ if (entry->direct == COMMUNITY_PERMIT)
+ {
+ com_index_to_delete[delete_index] = i;
+ delete_index++;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Delete all of the communities we flagged for deletion */
+ ptr = lcom->val;
+ for (i = delete_index-1; i >= 0; i--)
+ {
+ ptr += (com_index_to_delete[i] * LCOMMUNITY_SIZE);
+ lcommunity_del_val (lcom, ptr);
+ }
+
+ return lcom;
+}
+
+/* Set lcommunity-list. */
+int
+lcommunity_list_set (struct community_list_handler *ch,
+ const char *name, const char *str, int direct, int style)
+{
+ struct community_entry *entry = NULL;
+ struct community_list *list;
+ struct lcommunity *lcom = NULL;
+ regex_t *regex = NULL;
+
+ /* Get community list. */
+ list = community_list_get (ch, name, LARGE_COMMUNITY_LIST_MASTER);
+
+ /* When community-list already has entry, new entry should have same
+ style. If you want to have mixed style community-list, you can
+ comment out this check. */
+ if (!community_list_empty_p (list))
+ {
+ struct community_entry *first;
+
+ first = list->head;
+
+ if (style != first->style)
+ {
+ return (first->style == COMMUNITY_LIST_STANDARD
+ ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
+ : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
+ }
+ }
+
+ if (str)
+ {
+ if (style == LARGE_COMMUNITY_LIST_STANDARD)
+ lcom = lcommunity_str2com (str);
+ else
+ regex = bgp_regcomp (str);
+
+ if (! lcom && ! regex)
+ return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+ }
+
+ entry = community_entry_new ();
+ entry->direct = direct;
+ entry->style = style;
+ entry->any = (str ? 0 : 1);
+ entry->u.lcom = lcom;
+ entry->reg = regex;
+ if (lcom)
+ entry->config = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST);
+ else if (regex)
+ entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
+ else
+ entry->config = NULL;
+
+ /* Do not put duplicated community entry. */
+ if (community_list_dup_check (list, entry))
+ community_entry_free (entry);
+ else
+ community_list_entry_add (list, entry);
+
+ return 0;
+}
+
+/* Unset community-list. When str is NULL, delete all of
+ community-list entry belongs to the specified name. */
+int
+lcommunity_list_unset (struct community_list_handler *ch,
+ const char *name, const char *str,
+ int direct, int style)
+{
+ struct community_entry *entry = NULL;
+ struct community_list *list;
+ struct lcommunity *lcom = NULL;
+ regex_t *regex = NULL;
+
+ /* Lookup community list. */
+ list = community_list_lookup (ch, name, LARGE_COMMUNITY_LIST_MASTER);
+ if (list == NULL)
+ return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+
+ /* Delete all of entry belongs to this community-list. */
+ if (!str)
+ {
+ community_list_delete (list);
+ return 0;
+ }
+
+ if (style == LARGE_COMMUNITY_LIST_STANDARD)
+ lcom = lcommunity_str2com (str);
+ else
+ regex = bgp_regcomp (str);
+
+ if (! lcom && ! regex)
+ return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+
+ if (lcom)
+ entry = community_list_entry_lookup (list, lcom, direct);
+ else
+ entry = community_list_entry_lookup (list, str, direct);
+
+ if (lcom)
+ lcommunity_free (&lcom);
+ if (regex)
+ bgp_regex_free (regex);
+
+ if (!entry)
+ return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
+
+ community_list_entry_delete (list, entry, style);
+
+ return 0;
+}
+
/* Set extcommunity-list. */
int
extcommunity_list_set (struct community_list_handler *ch,
@@ -959,6 +1263,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 277ab7226c..68e45c8f7b 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, int delete_all);
+extern int lcommunity_list_set (struct community_list_handler *ch,
+ const char *name, const char *str,
+ int direct, int style);
+extern int lcommunity_list_unset (struct community_list_handler *ch,
+ const char *name, const char *str,
+ int direct, int style);
extern struct community_list_master *
community_list_master_lookup (struct community_list_handler *, int);
@@ -148,9 +161,12 @@ community_list_lookup (struct community_list_handler *, const char *, int);
extern int community_list_match (struct community *, struct community_list *);
extern int ecommunity_list_match (struct ecommunity *, struct community_list *);
+extern int lcommunity_list_match (struct lcommunity *, struct community_list *);
extern int community_list_exact_match (struct community *,
struct community_list *);
extern struct community *
community_list_match_delete (struct community *, struct community_list *);
-
+extern struct lcommunity *
+lcommunity_list_match_delete (struct lcommunity *lcom,
+ struct community_list *list);
#endif /* _QUAGGA_BGP_CLIST_H */
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index b65af9e1fa..6689883d94 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_aspath.h"
/* Hash of community attribute. */
diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c
index 1bc8a67ffc..bc977b4581 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 0000000000..549a2ebad8
--- /dev/null
+++ b/bgpd/bgp_lcommunity.c
@@ -0,0 +1,569 @@
+/* BGP Large Communities Attribute
+ *
+ * Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
+ *
+ * This file is part of FreeRangeRouting (FRR).
+ *
+ * FRR 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.
+ *
+ * FRR 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 FRR; 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;
+}
+
+static void
+lcommunity_hash_free (struct lcommunity *lcom)
+{
+ lcommunity_free (&lcom);
+}
+
+/* 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_clean (lcomhash, (void (*)(void *))lcommunity_hash_free);
+ hash_free (lcomhash);
+ lcomhash = NULL;
+}
+
+/* Large Communities token enum. */
+enum lcommunity_token
+{
+ lcommunity_token_unknown = 0,
+ lcommunity_token_val,
+};
+
+/* Get next Large Communities token from the string. */
+static const char *
+lcommunity_gettoken (const char *str, struct lcommunity_val *lval,
+ enum lcommunity_token *token)
+{
+ const char *p = str;
+
+ /* Skip white space. */
+ while (isspace ((int) *p))
+ {
+ p++;
+ str++;
+ }
+
+ /* Check the end of the line. */
+ if (*p == '\0')
+ return NULL;
+
+ /* Community value. */
+ if (isdigit ((int) *p))
+ {
+ int separator = 0;
+ int digit = 0;
+ u_int32_t globaladmin = 0;
+ u_int32_t localdata1 = 0;
+ u_int32_t localdata2 = 0;
+
+ while (isdigit ((int) *p) || *p == ':')
+ {
+ if (*p == ':')
+ {
+ if (separator == 2)
+ {
+ *token = lcommunity_token_unknown;
+ return NULL;
+ }
+ else
+ {
+ separator++;
+ digit = 0;
+ if (separator == 1) {
+ globaladmin = localdata2;
+ } else {
+ localdata1 = localdata2;
+ }
+ localdata2 = 0;
+ }
+ }
+ else
+ {
+ digit = 1;
+ localdata2 *= 10;
+ localdata2 += (*p - '0');
+ }
+ p++;
+ }
+ if (! digit)
+ {
+ *token = lcommunity_token_unknown;
+ return NULL;
+ }
+
+ /*
+ * Copy the large comm.
+ */
+ lval->val[0] = (globaladmin >> 24) & 0xff;
+ lval->val[1] = (globaladmin >> 16) & 0xff;
+ lval->val[2] = (globaladmin >> 8) & 0xff;
+ lval->val[3] = globaladmin & 0xff;
+ lval->val[4] = (localdata1 >> 24) & 0xff;
+ lval->val[5] = (localdata1 >> 16) & 0xff;
+ lval->val[6] = (localdata1 >> 8) & 0xff;
+ lval->val[7] = localdata1 & 0xff;
+ lval->val[8] = (localdata2 >> 24) & 0xff;
+ lval->val[9] = (localdata2 >> 16) & 0xff;
+ lval->val[10] = (localdata2 >> 8) & 0xff;
+ lval->val[11] = localdata2 & 0xff;
+
+ *token = lcommunity_token_val;
+ return p;
+ }
+ *token = lcommunity_token_unknown;
+ return p;
+}
+
+/*
+ Convert string to large community attribute.
+ When type is already known, please specify both str and type.
+
+ When string includes keyword for each large community value.
+ Please specify keyword_included as non-zero value.
+*/
+struct lcommunity *
+lcommunity_str2com (const char *str)
+{
+ struct lcommunity *lcom = NULL;
+ enum lcommunity_token token = lcommunity_token_unknown;
+ struct lcommunity_val lval;
+
+ while ((str = lcommunity_gettoken (str, &lval, &token)))
+ {
+ switch (token)
+ {
+ case lcommunity_token_val:
+ if (lcom == NULL)
+ lcom = lcommunity_new ();
+ lcommunity_add_val (lcom, &lval);
+ break;
+ case lcommunity_token_unknown:
+ default:
+ if (lcom)
+ lcommunity_free (&lcom);
+ return NULL;
+ }
+ }
+ return lcom;
+}
+
+int
+lcommunity_include (struct lcommunity *lcom, u_char *ptr)
+{
+ int i;
+ u_char *lcom_ptr;
+
+ lcom_ptr = lcom->val;
+ for (i = 0; i < lcom->size; i++) {
+ lcom_ptr += (i * LCOMMUNITY_SIZE);
+ if (memcmp (ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+/* Convert large community attribute to string.
+ The large coms will be in 65535:65531:0 format.
+*/
+char *
+lcommunity_lcom2str (struct lcommunity *lcom, int format)
+{
+ int i;
+ u_int8_t *pnt;
+#define LCOMMUNITY_STR_DEFAULT_LEN 40
+ int str_size;
+ int str_pnt;
+ char *str_buf;
+ int len = 0;
+ int first = 1;
+ u_int32_t globaladmin, localdata1, localdata2;
+
+ if (lcom->size == 0)
+ {
+ str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, 1);
+ str_buf[0] = '\0';
+ return str_buf;
+ }
+
+ /* Prepare buffer. */
+ str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, LCOMMUNITY_STR_DEFAULT_LEN + 1);
+ str_size = LCOMMUNITY_STR_DEFAULT_LEN + 1;
+ str_pnt = 0;
+
+ for (i = 0; i < lcom->size; i++)
+ {
+ /* Make it sure size is enough. */
+ while (str_pnt + LCOMMUNITY_STR_DEFAULT_LEN >= str_size)
+ {
+ str_size *= 2;
+ str_buf = XREALLOC (MTYPE_LCOMMUNITY_STR, str_buf, str_size);
+ }
+
+ /* Space between each value. */
+ if (! first)
+ str_buf[str_pnt++] = ' ';
+
+ pnt = lcom->val + (i * 12);
+
+ globaladmin = (*pnt++ << 24);
+ globaladmin |= (*pnt++ << 16);
+ globaladmin |= (*pnt++ << 8);
+ globaladmin |= (*pnt++);
+
+ localdata1 = (*pnt++ << 24);
+ localdata1 |= (*pnt++ << 16);
+ localdata1 |= (*pnt++ << 8);
+ localdata1 |= (*pnt++);
+
+ localdata2 = (*pnt++ << 24);
+ localdata2 |= (*pnt++ << 16);
+ localdata2 |= (*pnt++ << 8);
+ localdata2 |= (*pnt++);
+
+ len = sprintf( str_buf + str_pnt, "%u:%u:%u", globaladmin,
+ localdata1, localdata2);
+ str_pnt += len;
+ first = 0;
+ }
+ return str_buf;
+}
+
+int
+lcommunity_match (const struct lcommunity *lcom1,
+ const struct lcommunity *lcom2)
+{
+ int i = 0;
+ int j = 0;
+
+ if (lcom1 == NULL && lcom2 == NULL)
+ return 1;
+
+ if (lcom1 == NULL || lcom2 == NULL)
+ return 0;
+
+ if (lcom1->size < lcom2->size)
+ return 0;
+
+ /* Every community on com2 needs to be on com1 for this to match */
+ while (i < lcom1->size && j < lcom2->size)
+ {
+ if (memcmp (lcom1->val + (i*12), lcom2->val + (j*12), LCOMMUNITY_SIZE) == 0)
+ j++;
+ i++;
+ }
+
+ if (j == lcom2->size)
+ return 1;
+ else
+ return 0;
+}
+
+/* Delete one lcommunity. */
+void
+lcommunity_del_val (struct lcommunity *lcom, u_char *ptr)
+{
+ int i = 0;
+ int c = 0;
+
+ if (! lcom->val)
+ return;
+
+ while (i < lcom->size)
+ {
+ if (memcmp (lcom->val + i*LCOMMUNITY_SIZE, ptr, LCOMMUNITY_SIZE) == 0)
+ {
+ c = lcom->size -i -1;
+
+ if (c > 0)
+ memmove (lcom->val + i*LCOMMUNITY_SIZE, lcom->val + (i + 1)*LCOMMUNITY_SIZE, c * LCOMMUNITY_SIZE);
+
+ lcom->size--;
+
+ if (lcom->size > 0)
+ lcom->val = XREALLOC (MTYPE_COMMUNITY_VAL, lcom->val,
+ lcom_length (lcom));
+ else
+ {
+ XFREE (MTYPE_COMMUNITY_VAL, lcom->val);
+ lcom->val = NULL;
+ }
+ return;
+ }
+ i++;
+ }
+}
diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h
new file mode 100644
index 0000000000..de3697f477
--- /dev/null
+++ b/bgpd/bgp_lcommunity.h
@@ -0,0 +1,74 @@
+/* BGP Large Communities Attribute.
+ *
+ * Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
+ *
+ * This file is part of FreeRangeRouting (FRR).
+ *
+ * FRR 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.
+ *
+ * FRR 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 FRR; 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_memory.c b/bgpd/bgp_memory.c
index 72c0311c17..85e32645ee 100644
--- a/bgpd/bgp_memory.c
+++ b/bgpd/bgp_memory.c
@@ -111,3 +111,7 @@ DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV")
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options")
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value")
+
+DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community")
+DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string")
+DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h
index a4ce8b891b..341fb235d0 100644
--- a/bgpd/bgp_memory.h
+++ b/bgpd/bgp_memory.h
@@ -108,4 +108,7 @@ DECLARE_MTYPE(ENCAP_TLV)
DECLARE_MTYPE(BGP_TEA_OPTIONS)
DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE)
+DECLARE_MTYPE(LCOMMUNITY)
+DECLARE_MTYPE(LCOMMUNITY_STR)
+DECLARE_MTYPE(LCOMMUNITY_VAL)
#endif /* _QUAGGA_BGP_MEMORY_H */
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 1701c70441..f564ff1691 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"
/*
@@ -662,6 +663,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
u_char origin;
struct community *community, *commerge;
struct ecommunity *ecomm, *ecommerge;
+ struct lcommunity *lcomm, *lcommerge;
struct attr_extra *ae;
struct attr attr = { 0 };
@@ -698,6 +700,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
community = attr.community ? community_dup (attr.community) : NULL;
ae = attr.extra;
ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL;
+ lcomm = (ae && ae->lcommunity) ? lcommunity_dup (ae->lcommunity) : NULL;
for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
mpinfo = bgp_info_mpath_next (mpinfo))
@@ -733,6 +736,17 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
else
ecomm = ecommunity_dup (ae->ecommunity);
}
+ if (ae && ae->lcommunity)
+ {
+ if (lcomm)
+ {
+ lcommerge = lcommunity_merge (lcomm, ae->lcommunity);
+ lcomm = lcommunity_uniq_sort (lcommerge);
+ lcommunity_free (&lcommerge);
+ }
+ else
+ lcomm = lcommunity_dup (ae->lcommunity);
+ }
}
attr.aspath = aspath;
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index 201b9bf710..e496db0d78 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -32,6 +32,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define RD_ADDRSTRLEN 28
+#ifdef MPLS_LABEL_MAX
+# undef MPLS_LABEL_MAX
+#endif
+
typedef enum {
MPLS_LABEL_IPV4_EXPLICIT_NULL = 0, /* [RFC3032] */
MPLS_LABEL_ROUTER_ALERT = 1, /* [RFC3032] */
@@ -47,7 +51,9 @@ typedef enum {
MPLS_LABEL_UNASSIGNED11 = 11,
MPLS_LABEL_GAL = 13, /* [RFC5586] */
MPLS_LABEL_OAM_ALERT = 14, /* [RFC3429] */
- MPLS_LABEL_EXTENSION = 15 /* [RFC7274] */
+ MPLS_LABEL_EXTENSION = 15, /* [RFC7274] */
+ MPLS_LABEL_MAX = 1048575,
+ MPLS_LABEL_ILLEGAL = 0xFFFFFFFF /* for internal use only */
} mpls_special_label_t;
#define MPLS_LABEL_IS_SPECIAL(label) \
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index c4eacb5042..2df22ab568 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -46,6 +46,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_network.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_encap.h"
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 8be76595f7..a3dd5f7cf5 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.
@@ -46,6 +47,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_clist.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_filter.h"
@@ -7099,7 +7101,12 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
}
}
- /* Line 6 display Originator, Cluster-id */
+ /* Line 6 display Large community */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))
+ vty_out (vty, " Large Community: %s%s",
+ attr->extra->lcommunity->str, VTY_NEWLINE);
+
+ /* Line 7 display Originator, Cluster-id */
if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) ||
(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)))
{
@@ -7155,7 +7162,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
if (binfo->extra && binfo->extra->damp_info)
bgp_damp_info_vty (vty, binfo, json_path);
- /* Line 7 display Addpath IDs */
+ /* Line 8 display Addpath IDs */
if (binfo->addpath_rx_id || binfo->addpath_tx_id)
{
if (json_paths)
@@ -7210,7 +7217,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
}
}
- /* Line 8 display Uptime */
+ /* Line 9 display Uptime */
tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
if (json_paths)
{
@@ -7436,6 +7443,27 @@ bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table,
if (! community_list_exact_match (ri->attr->community, list))
continue;
}
+ if (type == bgp_show_type_lcommunity)
+ {
+ struct lcommunity *lcom = output_arg;
+
+ if (! ri->attr->extra || ! ri->attr->extra->lcommunity ||
+ ! lcommunity_match (ri->attr->extra->lcommunity, lcom))
+ continue;
+ }
+ if (type == bgp_show_type_lcommunity_list)
+ {
+ struct community_list *list = output_arg;
+
+ if (! ri->attr->extra ||
+ ! lcommunity_list_match (ri->attr->extra->lcommunity, list))
+ continue;
+ }
+ if (type == bgp_show_type_lcommunity_all)
+ {
+ if (! ri->attr->extra || ! ri->attr->extra->lcommunity)
+ continue;
+ }
if (type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
{
@@ -7864,6 +7892,158 @@ bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
use_json);
}
+static int
+bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc,
+ struct cmd_token **argv, afi_t afi, safi_t safi, u_char uj)
+{
+ struct lcommunity *lcom;
+ struct buffer *b;
+ int i;
+ char *str;
+ int first = 0;
+
+ b = buffer_new (1024);
+ for (i = 0; i < argc; i++)
+ {
+ if (first)
+ buffer_putc (b, ' ');
+ else
+ {
+ if (strmatch (argv[i]->text, "<AA:BB:CC>"))
+ {
+ first = 1;
+ buffer_putstr (b, argv[i]->arg);
+ }
+ }
+ }
+ buffer_putc (b, '\0');
+
+ str = buffer_getstr (b);
+ buffer_free (b);
+
+ lcom = lcommunity_str2com (str);
+ XFREE (MTYPE_TMP, str);
+ if (! lcom)
+ {
+ vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity, lcom, uj);
+}
+
+static int
+bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom,
+ afi_t afi, safi_t safi, u_char uj)
+{
+ struct community_list *list;
+
+ list = community_list_lookup (bgp_clist, lcom, LARGE_COMMUNITY_LIST_MASTER);
+ if (list == NULL)
+ {
+ vty_out (vty, "%% %s is not a valid large-community-list name%s", lcom,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_list, list, uj);
+}
+
+DEFUN (show_ip_bgp_large_community_list,
+ show_ip_bgp_large_community_list_cmd,
+ "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community-list <(1-500)|WORD> [json]",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ BGP_INSTANCE_HELP_STR
+ "Address Family\n"
+ "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"
+ JSON_STR)
+{
+ char *vrf = NULL;
+ afi_t afi = AFI_IP6;
+ safi_t safi = SAFI_UNICAST;
+ int idx = 0;
+
+ if (argv_find (argv, argc, "ip", &idx))
+ afi = AFI_IP;
+ if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx))
+ vrf = argv[++idx]->arg;
+ if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx))
+ {
+ afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP;
+ if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx))
+ safi = bgp_vty_safi_from_arg (argv[idx]->text);
+ }
+
+ int uj = use_json (argc, argv);
+
+ struct bgp *bgp = bgp_lookup_by_name (vrf);
+ if (bgp == NULL)
+ {
+ vty_out (vty, "Can't find BGP instance %s%s", vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ argv_find (argv, argc, "large-community-list", &idx);
+ return bgp_show_lcommunity_list (vty, bgp, argv[idx+1]->arg, afi, safi, uj);
+}
+DEFUN (show_ip_bgp_large_community,
+ show_ip_bgp_large_community_cmd,
+ "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community [AA:BB:CC] [json]",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ BGP_INSTANCE_HELP_STR
+ "Address Family\n"
+ "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"
+ "List of large-community numbers\n"
+ JSON_STR)
+{
+ char *vrf = NULL;
+ afi_t afi = AFI_IP6;
+ safi_t safi = SAFI_UNICAST;
+ int idx = 0;
+
+ if (argv_find (argv, argc, "ip", &idx))
+ afi = AFI_IP;
+ if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx))
+ vrf = argv[++idx]->arg;
+ if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx))
+ {
+ afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP;
+ if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx))
+ safi = bgp_vty_safi_from_arg (argv[idx]->text);
+ }
+
+ int uj = use_json (argc, argv);
+
+ struct bgp *bgp = bgp_lookup_by_name (vrf);
+ if (bgp == NULL)
+ {
+ vty_out (vty, "Can't find BGP instance %s%s", vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ argv_find (argv, argc, "large-community", &idx);
+ if (strmatch(argv[idx+1]->text, "AA:BB:CC"))
+ return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj);
+ else
+ return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj);
+}
+
/* BGP route print out function. */
DEFUN (show_ip_bgp_ipv4,
show_ip_bgp_ipv4_cmd,
@@ -10487,6 +10667,7 @@ bgp_route_init (void)
install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd);
+
install_element (VIEW_NODE, &show_ip_bgp_instance_neighbor_advertised_route_cmd);
install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd);
install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
@@ -10500,6 +10681,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);
@@ -10569,6 +10751,10 @@ bgp_route_init (void)
/* IPv4 Multicast Mode */
install_element (BGP_IPV4M_NODE, &bgp_damp_set_cmd);
install_element (BGP_IPV4M_NODE, &bgp_damp_unset_cmd);
+
+ /* Large Communities */
+ install_element (VIEW_NODE, &show_ip_bgp_large_community_list_cmd);
+ install_element (VIEW_NODE, &show_ip_bgp_large_community_cmd);
}
void
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 21ca64091c..83954beaea 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -256,6 +256,9 @@ enum bgp_show_type
bgp_show_type_community_exact,
bgp_show_type_community_list,
bgp_show_type_community_list_exact,
+ bgp_show_type_lcommunity_all,
+ bgp_show_type_lcommunity,
+ bgp_show_type_lcommunity_list,
bgp_show_type_flap_statistics,
bgp_show_type_flap_neighbor,
bgp_show_type_dampend_paths,
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 50524baa01..58788d2041 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -52,6 +52,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_filter.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_debug.h"
@@ -84,6 +85,8 @@ o Cisco route-map
as-path tag : Not yet
automatic-tag : (This will not be implemented by bgpd)
community : Done
+ large-community : Done
+ large-comm-list : Done
comm-list : Not yet
dampning : Not yet
default : (This will not be implemented by bgpd)
@@ -847,6 +850,78 @@ struct route_map_rule_cmd route_match_community_cmd =
route_match_community_free
};
+/* Match function for lcommunity match. */
+static route_map_result_t
+route_match_lcommunity (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct community_list *list;
+ struct bgp_info *bgp_info;
+ struct rmap_community *rcom;
+
+ if (type == RMAP_BGP)
+ {
+ bgp_info = object;
+ rcom = rule;
+
+ list = community_list_lookup (bgp_clist, rcom->name,
+ LARGE_COMMUNITY_LIST_MASTER);
+ if (! list)
+ return RMAP_NOMATCH;
+
+ if (bgp_info->attr->extra &&
+ lcommunity_list_match (bgp_info->attr->extra->lcommunity, list))
+ return RMAP_MATCH;
+
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Compile function for community match. */
+static void *
+route_match_lcommunity_compile (const char *arg)
+{
+ struct rmap_community *rcom;
+ int len;
+ char *p;
+
+ rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community));
+
+ p = strchr (arg, ' ');
+ if (p)
+ {
+ len = p - arg;
+ rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
+ memcpy (rcom->name, arg, len);
+ }
+ else
+ {
+ rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+ rcom->exact = 0;
+ }
+ return rcom;
+}
+
+/* Compile function for community match. */
+static void
+route_match_lcommunity_free (void *rule)
+{
+ struct rmap_community *rcom = rule;
+
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name);
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom);
+}
+
+/* Route map commands for community matching. */
+struct route_map_rule_cmd route_match_lcommunity_cmd =
+{
+ "large-community",
+ route_match_lcommunity,
+ route_match_lcommunity_compile,
+ route_match_lcommunity_free
+};
+
+
/* Match function for extcommunity match. */
static route_map_result_t
route_match_ecommunity (void *rule, struct prefix *prefix,
@@ -1544,6 +1619,224 @@ 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 intern()'d or attr_flush()'d by bgp_update_main() */
+ (bgp_attr_extra_get (attr))->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. */
@@ -3164,7 +3457,32 @@ DEFUN (no_match_community,
RMAP_EVENT_CLIST_DELETED);
}
+DEFUN (match_lcommunity,
+ match_lcommunity_cmd,
+ "match large-community [<(1-99)|(100-500)|WORD>]",
+ MATCH_STR
+ "Match BGP large community list\n"
+ "Large Community-list number (standard)\n"
+ "Large Community-list number (expanded)\n"
+ "Large Community-list name\n")
+{
+ return bgp_route_match_add (vty, "large-community", argv[2]->arg,
+ RMAP_EVENT_LLIST_ADDED);
+}
+DEFUN (no_match_lcommunity,
+ no_match_lcommunity_cmd,
+ "no match large-community [<(1-99)|(100-500)|WORD>]",
+ NO_STR
+ MATCH_STR
+ "Match BGP large community list\n"
+ "Large Community-list number (standard)\n"
+ "Large Community-list number (expanded)\n"
+ "Large Community-list name\n")
+{
+ return bgp_route_match_delete (vty, "large-community", NULL,
+ RMAP_EVENT_LLIST_DELETED);
+}
DEFUN (match_ecommunity,
match_ecommunity_cmd,
@@ -3597,6 +3915,95 @@ DEFUN (no_set_community_delete,
"comm-list", NULL);
}
+DEFUN (set_lcommunity,
+ set_lcommunity_cmd,
+ "set large-community AA:BB:CC...",
+ SET_STR
+ "BGP large community attribute\n"
+ "Large Community number in aa:bb:cc format or additive\n")
+{
+ int ret;
+ char *str;
+
+ str = argv_concat (argv, argc, 2);
+ ret = generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), "large-community", str);
+ XFREE (MTYPE_TMP, str);
+
+ return ret;
+}
+
+DEFUN (set_lcommunity_none,
+ set_lcommunity_none_cmd,
+ "set large-community none",
+ SET_STR
+ "BGP large community attribute\n"
+ "No large community attribute\n")
+{
+ return generic_set_add (vty, VTY_GET_CONTEXT(route_map_index),
+ "large-community", "none");
+}
+
+DEFUN (no_set_lcommunity,
+ no_set_lcommunity_cmd,
+ "no set large-community none",
+ NO_STR
+ SET_STR
+ "BGP large community attribute\n"
+ "No community attribute\n")
+{
+ return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
+ "large-community", NULL);
+}
+
+DEFUN (no_set_lcommunity1,
+ no_set_lcommunity1_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")
+{
+ return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
+ "large-community", NULL);
+}
+
+DEFUN (set_lcommunity_delete,
+ set_lcommunity_delete_cmd,
+ "set large-comm-list <(1-99)|(100-500)|WORD> delete",
+ SET_STR
+ "set BGP large community list (for deletion)\n"
+ "Large Community-list number (standard)\n"
+ "Large Communitly-list number (expanded)\n"
+ "Large Community-list name\n"
+ "Delete matching large communities\n")
+{
+ char *str;
+
+ str = XCALLOC (MTYPE_TMP, strlen (argv[2]->arg) + strlen (" delete") + 1);
+ strcpy (str, argv[2]->arg);
+ strcpy (str + strlen (argv[2]->arg), " delete");
+
+ generic_set_add (vty, VTY_GET_CONTEXT(route_map_index),
+ "large-comm-list", str);
+
+ XFREE (MTYPE_TMP, str);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_set_lcommunity_delete,
+ no_set_lcommunity_delete_cmd,
+ "no set large-comm-list <(1-99|(100-500)|WORD)> [delete]",
+ NO_STR
+ SET_STR
+ "set BGP large community list (for deletion)\n"
+ "Large Community-list number (standard)\n"
+ "Large Communitly-list number (expanded)\n"
+ "Large Community-list name\n"
+ "Delete matching large communities\n")
+{
+ return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
+ "large-comm-list", NULL);
+}
DEFUN (set_ecommunity_rt,
set_ecommunity_rt_cmd,
@@ -4139,6 +4546,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);
@@ -4158,6 +4566,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_vpnv6_nexthop_cmd);
route_map_install_set (&route_set_originator_id_cmd);
@@ -4180,6 +4590,8 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &match_community_cmd);
install_element (RMAP_NODE, &match_community_exact_cmd);
install_element (RMAP_NODE, &no_match_community_cmd);
+ install_element (RMAP_NODE, &match_lcommunity_cmd);
+ install_element (RMAP_NODE, &no_match_lcommunity_cmd);
install_element (RMAP_NODE, &match_ecommunity_cmd);
install_element (RMAP_NODE, &no_match_ecommunity_cmd);
install_element (RMAP_NODE, &match_origin_cmd);
@@ -4209,6 +4621,12 @@ bgp_route_map_init (void)
install_element (RMAP_NODE, &no_set_community_cmd);
install_element (RMAP_NODE, &set_community_delete_cmd);
install_element (RMAP_NODE, &no_set_community_delete_cmd);
+ install_element (RMAP_NODE, &set_lcommunity_cmd);
+ install_element (RMAP_NODE, &set_lcommunity_none_cmd);
+ install_element (RMAP_NODE, &no_set_lcommunity_cmd);
+ install_element (RMAP_NODE, &no_set_lcommunity1_cmd);
+ install_element (RMAP_NODE, &set_lcommunity_delete_cmd);
+ install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd);
install_element (RMAP_NODE, &set_ecommunity_rt_cmd);
install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd);
install_element (RMAP_NODE, &set_ecommunity_soo_cmd);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 91b655e724..17b8485237 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -41,6 +41,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_damp.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_fsm.h"
@@ -3748,13 +3749,15 @@ DEFUN (no_neighbor_send_community,
/* neighbor send-community extended. */
DEFUN (neighbor_send_community_type,
neighbor_send_community_type_cmd,
- "neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|extended|standard>",
+ "neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Send Community attribute to this neighbor\n"
"Send Standard and Extended Community attributes\n"
+ "Send Standard, Large and Extended Community attributes\n"
"Send Extended Community attributes\n"
- "Send Standard Community attributes\n")
+ "Send Standard Community attributes\n"
+ "Send Large Community attributes\n")
{
int idx = 0;
u_int32_t flag = 0;
@@ -3765,25 +3768,35 @@ DEFUN (neighbor_send_community_type,
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
else if (argv_find (argv, argc, "extended", &idx))
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
+ else if (argv_find (argv, argc, "large", &idx))
+ SET_FLAG (flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
+ else if (argv_find (argv, argc, "both", &idx))
+ {
+ SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
+ }
else
- {
- SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
- SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
- }
+ {
+ SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG (flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
+ }
return peer_af_flag_set_vty (vty, peer, bgp_node_afi (vty), bgp_node_safi (vty), flag);
}
DEFUN (no_neighbor_send_community_type,
no_neighbor_send_community_type_cmd,
- "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|extended|standard>",
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Send Community attribute to this neighbor\n"
"Send Standard and Extended Community attributes\n"
+ "Send Standard, Large and Extended Community attributes\n"
"Send Extended Community attributes\n"
- "Send Standard Community attributes\n")
+ "Send Standard Community attributes\n"
+ "Send Large Community attributes\n")
{
int idx_peer = 2;
int idx_type = 4;
@@ -3795,11 +3808,21 @@ DEFUN (no_neighbor_send_community_type,
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
bgp_node_safi (vty),
PEER_FLAG_SEND_EXT_COMMUNITY);
+ if (strncmp (argv[idx_type]->arg, "l", 1) == 0)
+ return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_SEND_LARGE_COMMUNITY);
+ if (strncmp (argv[idx_type]->arg, "b", 1) == 0)
+ return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
+ bgp_node_safi (vty),
+ PEER_FLAG_SEND_COMMUNITY |
+ PEER_FLAG_SEND_EXT_COMMUNITY);
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
bgp_node_safi (vty),
(PEER_FLAG_SEND_COMMUNITY |
- PEER_FLAG_SEND_EXT_COMMUNITY));
+ PEER_FLAG_SEND_EXT_COMMUNITY|
+ PEER_FLAG_SEND_LARGE_COMMUNITY));
}
/* neighbor soft-reconfig. */
@@ -6156,6 +6179,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,
@@ -7133,12 +7162,16 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi,
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
vty_out (vty, " MED is propagated unchanged to this neighbor%s", VTY_NEWLINE);
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
- || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
+ || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
+ || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
{
vty_out (vty, " Community attribute sent to this neighbor");
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
- && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
- vty_out (vty, "(both)%s", VTY_NEWLINE);
+ && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
+ && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
+ vty_out (vty, "(all)%s", VTY_NEWLINE);
+ else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
+ vty_out (vty, "(large)%s", VTY_NEWLINE);
else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
vty_out (vty, "(extended)%s", VTY_NEWLINE);
else
@@ -8666,6 +8699,36 @@ DEFUN (show_ip_bgp_community_info,
return CMD_SUCCESS;
}
+static void
+lcommunity_show_all_iterator (struct hash_backet *backet, struct vty *vty)
+{
+ struct lcommunity *lcom;
+
+ lcom = (struct lcommunity *) backet->data;
+ vty_out (vty, "[%p] (%ld) %s%s", (void *)backet, lcom->refcnt,
+ lcommunity_str (lcom), VTY_NEWLINE);
+}
+
+/* Show BGP's community internal data. */
+DEFUN (show_ip_bgp_lcommunity_info,
+ show_ip_bgp_lcommunity_info_cmd,
+ "show ip bgp large-community-info",
+ SHOW_STR
+ IP_STR
+ BGP_STR
+ "List all bgp large-community information\n")
+{
+ vty_out (vty, "Address Refcnt Large-community%s", VTY_NEWLINE);
+
+ hash_iterate (lcommunity_hash (),
+ (void (*) (struct hash_backet *, void *))
+ lcommunity_show_all_iterator,
+ vty);
+
+ return CMD_SUCCESS;
+}
+
+
DEFUN (show_ip_bgp_attr_info,
show_ip_bgp_attr_info_cmd,
"show [ip] bgp attribute-info",
@@ -10770,6 +10833,8 @@ bgp_vty_init (void)
/* "show [ip] bgp community" commands. */
install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd);
+ /* "show ip bgp large-community" commands. */
+ install_element (VIEW_NODE, &show_ip_bgp_lcommunity_info_cmd);
/* "show [ip] bgp attribute-info" commands. */
install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd);
@@ -11102,6 +11167,350 @@ DEFUN (show_ip_community_list_arg,
return CMD_SUCCESS;
}
+/*
+ * Large Community code.
+ */
+static int
+lcommunity_list_set_vty (struct vty *vty, int argc, struct cmd_token **argv,
+ int style, int reject_all_digit_name)
+{
+ int ret;
+ int direct;
+ char *str;
+ int idx = 0;
+ char *cl_name;
+
+ direct = argv_find (argv, argc, "permit", &idx) ? COMMUNITY_PERMIT : COMMUNITY_DENY;
+
+ /* All digit name check. */
+ idx = 0;
+ argv_find (argv, argc, "WORD", &idx);
+ argv_find (argv, argc, "(1-99)", &idx);
+ argv_find (argv, argc, "(100-500)", &idx);
+ cl_name = argv[idx]->arg;
+ if (reject_all_digit_name && all_digit (cl_name))
+ {
+ vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ argv_find (argv, argc, "AA:BB:CC", &idx);
+ argv_find (argv, argc, "LINE", &idx);
+ /* Concat community string argument. */
+ if (idx)
+ str = argv_concat (argv, argc, idx);
+ else
+ str = NULL;
+
+ ret = lcommunity_list_set (bgp_clist, cl_name, str, direct, style);
+
+ /* Free temporary community list string allocated by
+ argv_concat(). */
+ if (str)
+ XFREE (MTYPE_TMP, str);
+
+ if (ret < 0)
+ {
+ community_list_perror (vty, ret);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+static int
+lcommunity_list_unset_vty (struct vty *vty, int argc, struct cmd_token **argv,
+ int style)
+{
+ int ret;
+ int direct = 0;
+ char *str = NULL;
+ int idx = 0;
+
+ argv_find (argv, argc, "permit", &idx);
+ argv_find (argv, argc, "deny", &idx);
+
+ if (idx)
+ {
+ /* Check the list direct. */
+ if (strncmp (argv[idx]->arg, "p", 1) == 0)
+ direct = COMMUNITY_PERMIT;
+ else
+ direct = COMMUNITY_DENY;
+
+ idx = 0;
+ argv_find (argv, argc, "LINE", &idx);
+ argv_find (argv, argc, "AA:AA:NN", &idx);
+ /* Concat community string argument. */
+ str = argv_concat (argv, argc, idx);
+ }
+
+ idx = 0;
+ argv_find (argv, argc, "(1-99)", &idx);
+ argv_find (argv, argc, "(100-500)", &idx);
+ argv_find (argv, argc, "WORD", &idx);
+
+ /* Unset community list. */
+ ret = lcommunity_list_unset (bgp_clist, argv[idx]->arg, str, direct, style);
+
+ /* Free temporary community list string allocated by
+ argv_concat(). */
+ if (str)
+ XFREE (MTYPE_TMP, str);
+
+ if (ret < 0)
+ {
+ community_list_perror (vty, ret);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* "large-community-list" keyword help string. */
+#define LCOMMUNITY_LIST_STR "Add a large community list entry\n"
+#define LCOMMUNITY_VAL_STR "large community in 'aa:bb:cc' format\n"
+
+DEFUN (ip_lcommunity_list_standard,
+ ip_lcommunity_list_standard_cmd,
+ "ip large-community-list (1-99) <deny|permit>",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (standard)\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ LCOMMUNITY_VAL_STR)
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 0);
+}
+
+DEFUN (ip_lcommunity_list_standard1,
+ ip_lcommunity_list_standard1_cmd,
+ "ip large-community-list (1-99) <deny|permit> AA:BB:CC...",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (standard)\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ LCOMMUNITY_VAL_STR)
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 0);
+}
+
+DEFUN (ip_lcommunity_list_expanded,
+ ip_lcommunity_list_expanded_cmd,
+ "ip large-community-list (100-500) <deny|permit> LINE...",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (expanded)\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ "An ordered list as a regular-expression\n")
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 0);
+}
+
+DEFUN (ip_lcommunity_list_name_standard,
+ ip_lcommunity_list_name_standard_cmd,
+ "ip large-community-list standard WORD <deny|permit>",
+ 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")
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1);
+}
+
+DEFUN (ip_lcommunity_list_name_standard1,
+ ip_lcommunity_list_name_standard1_cmd,
+ "ip large-community-list standard WORD <deny|permit> AA:BB:CC...",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify standard large-community-list\n"
+ "Large Community list name\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ LCOMMUNITY_VAL_STR)
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1);
+}
+
+DEFUN (ip_lcommunity_list_name_expanded,
+ ip_lcommunity_list_name_expanded_cmd,
+ "ip large-community-list expanded WORD <deny|permit> LINE...",
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify expanded large-community-list\n"
+ "Large Community list name\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ "An ordered list as a regular-expression\n")
+{
+ return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 1);
+}
+
+DEFUN (no_ip_lcommunity_list_standard_all,
+ no_ip_lcommunity_list_standard_all_cmd,
+ "no ip large-community-list <(1-99)|(100-500)|WORD>",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (standard)\n"
+ "Large Community list number (expanded)\n"
+ "Large Community list name\n")
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_lcommunity_list_name_expanded_all,
+ no_ip_lcommunity_list_name_expanded_all_cmd,
+ "no ip large-community-list expanded WORD",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify expanded large-community-list\n"
+ "Large Community list name\n")
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
+}
+
+DEFUN (no_ip_lcommunity_list_standard,
+ no_ip_lcommunity_list_standard_cmd,
+ "no ip large-community-list (1-99) <deny|permit> AA:AA:NN...",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (standard)\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ LCOMMUNITY_VAL_STR)
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_lcommunity_list_expanded,
+ no_ip_lcommunity_list_expanded_cmd,
+ "no ip large-community-list (100-500) <deny|permit> LINE...",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Large Community list number (expanded)\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ "An ordered list as a regular-expression\n")
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
+}
+
+DEFUN (no_ip_lcommunity_list_name_standard,
+ no_ip_lcommunity_list_name_standard_cmd,
+ "no ip large-community-list standard WORD <deny|permit> AA:AA:NN...",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify standard large-community-list\n"
+ "Large Community list name\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ LCOMMUNITY_VAL_STR)
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
+}
+
+DEFUN (no_ip_lcommunity_list_name_expanded,
+ no_ip_lcommunity_list_name_expanded_cmd,
+ "no ip large-community-list expanded WORD <deny|permit> LINE...",
+ NO_STR
+ IP_STR
+ LCOMMUNITY_LIST_STR
+ "Specify expanded large-community-list\n"
+ "Large community list name\n"
+ "Specify large community to reject\n"
+ "Specify large community to accept\n"
+ "An ordered list as a regular-expression\n")
+{
+ return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
+}
+
+static void
+lcommunity_list_show (struct vty *vty, struct community_list *list)
+{
+ struct community_entry *entry;
+
+ for (entry = list->head; entry; entry = entry->next)
+ {
+ if (entry == list->head)
+ {
+ if (all_digit (list->name))
+ vty_out (vty, "Large community %s list %s%s",
+ entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+ "standard" : "(expanded) access",
+ list->name, VTY_NEWLINE);
+ else
+ vty_out (vty, "Named large community %s list %s%s",
+ entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+ "standard" : "expanded",
+ list->name, VTY_NEWLINE);
+ }
+ if (entry->any)
+ vty_out (vty, " %s%s",
+ community_direct_str (entry->direct), VTY_NEWLINE);
+ else
+ vty_out (vty, " %s %s%s",
+ community_direct_str (entry->direct),
+ entry->style == EXTCOMMUNITY_LIST_STANDARD ?
+ entry->u.ecom->str : entry->config,
+ VTY_NEWLINE);
+ }
+}
+
+DEFUN (show_ip_lcommunity_list,
+ show_ip_lcommunity_list_cmd,
+ "show ip large-community-list",
+ SHOW_STR
+ IP_STR
+ "List large-community list\n")
+{
+ struct community_list *list;
+ struct community_list_master *cm;
+
+ cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER);
+ if (! cm)
+ return CMD_SUCCESS;
+
+ for (list = cm->num.head; list; list = list->next)
+ lcommunity_list_show (vty, list);
+
+ for (list = cm->str.head; list; list = list->next)
+ lcommunity_list_show (vty, list);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_lcommunity_list_arg,
+ show_ip_lcommunity_list_arg_cmd,
+ "show ip large-community-list <(1-500)|WORD>",
+ SHOW_STR
+ IP_STR
+ "List large-community list\n"
+ "large-community-list number\n"
+ "large-community-list name\n")
+{
+ struct community_list *list;
+
+ list = community_list_lookup (bgp_clist, argv[3]->arg, LARGE_COMMUNITY_LIST_MASTER);
+ if (! list)
+ {
+ vty_out (vty, "%% Can't find extcommunity-list%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ lcommunity_list_show (vty, list);
+
+ return CMD_SUCCESS;
+}
+
/* "extcommunity-list" keyword help string. */
#define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n"
#define EXTCOMMUNITY_VAL_STR "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n"
@@ -11411,6 +11820,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;
}
@@ -11441,4 +11874,20 @@ community_list_vty (void)
install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd);
install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd);
install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd);
+
+ /* Large Community List */
+ install_element (CONFIG_NODE, &ip_lcommunity_list_standard_cmd);
+ install_element (CONFIG_NODE, &ip_lcommunity_list_standard1_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_standard1_cmd);
+ install_element (CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_all_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_cmd);
+ install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_cmd);
+ install_element (VIEW_NODE, &show_ip_lcommunity_list_cmd);
+ install_element (VIEW_NODE, &show_ip_lcommunity_list_arg_cmd);
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 3602a1e18f..b0c163f1e3 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -902,6 +902,7 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi)
{
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
}
/* Clear neighbor default_originate_rmap */
@@ -1206,6 +1207,7 @@ peer_new (struct bgp *bgp)
{
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
}
peer->orf_plist[afi][safi] = NULL;
}
@@ -3702,6 +3704,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] =
{
{ PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out },
{ PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out },
+ { PEER_FLAG_SEND_LARGE_COMMUNITY, 1, peer_change_reset_out },
{ PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out },
{ PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset },
{ PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset },
@@ -6982,10 +6985,17 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp,
if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
{
if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
- && peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
+ && peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)
+ && peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
{
afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s send-community both%s",
+ " neighbor %s send-community all%s",
+ addr, VTY_NEWLINE);
+ }
+ else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
+ {
+ afi_header_vty_out (vty, afi, safi, write,
+ " neighbor %s send-community large%s",
addr, VTY_NEWLINE);
}
else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
@@ -7006,10 +7016,19 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp,
if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) &&
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) &&
!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&
- (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)))
+ (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) &&
+ !peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY) &&
+ (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)))
+ {
+ afi_header_vty_out (vty, afi, safi, write,
+ " no neighbor %s send-community all%s",
+ addr, VTY_NEWLINE);
+ }
+ else if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY) &&
+ (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)))
{
afi_header_vty_out (vty, afi, safi, write,
- " no neighbor %s send-community both%s",
+ " no neighbor %s send-community large%s",
addr, VTY_NEWLINE);
}
else if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 3dd5523dce..2eef04e1d1 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -705,6 +705,7 @@ struct peer
#define PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS (1 << 23) /* addpath-tx-bestpath-per-AS */
#define PEER_FLAG_WEIGHT (1 << 24) /* weight */
#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */
+#define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 26) /* Send large Communities */
/* MD5 password */
char *password;
@@ -963,6 +964,7 @@ struct bgp_nlri
#define BGP_ATTR_AS4_AGGREGATOR 18
#define BGP_ATTR_AS_PATHLIMIT 21
#define BGP_ATTR_ENCAP 23
+#define BGP_ATTR_LARGE_COMMUNITIES 32
#if ENABLE_BGP_VNC
#define BGP_ATTR_VNC 255
#endif
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index ab9a24e831..10b365c1c8 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -561,8 +561,9 @@ DEFUN (vnc_defaults_responselifetime,
return CMD_SUCCESS;
}
-static struct rfapi_nve_group_cfg *
-rfapi_group_lookup_byname (struct bgp *bgp, const char *name)
+struct rfapi_nve_group_cfg *
+bgp_rfapi_cfg_match_byname (struct bgp *bgp, const char *name,
+ rfapi_group_cfg_type_t type) /* _MAX = any */
{
struct rfapi_nve_group_cfg *rfg;
struct listnode *node, *nnode;
@@ -570,18 +571,29 @@ rfapi_group_lookup_byname (struct bgp *bgp, const char *name)
for (ALL_LIST_ELEMENTS
(bgp->rfapi_cfg->nve_groups_sequential, node, nnode, rfg))
{
- if (!strcmp (rfg->name, name))
+ if ((type == RFAPI_GROUP_CFG_MAX || type == rfg->type) &&
+ !strcmp (rfg->name, name))
return rfg;
}
return NULL;
}
static struct rfapi_nve_group_cfg *
-rfapi_group_new ()
+rfapi_group_new (struct bgp *bgp,
+ rfapi_group_cfg_type_t type,
+ const char *name)
{
struct rfapi_nve_group_cfg *rfg;
rfg = XCALLOC (MTYPE_RFAPI_GROUP_CFG, sizeof (struct rfapi_nve_group_cfg));
+ if (rfg)
+ {
+ rfg->type = type;
+ rfg->name = strdup (name);
+ /* add to tail of list */
+ listnode_add (bgp->rfapi_cfg->nve_groups_sequential, rfg);
+ }
+ rfg->label = MPLS_LABEL_ILLEGAL;
QOBJ_REG (rfg, rfapi_nve_group_cfg);
return rfg;
@@ -1033,7 +1045,8 @@ DEFUN (vnc_redistribute_nvegroup,
* OK if nve group doesn't exist yet; we'll set the pointer
* when the group is defined later
*/
- bgp->rfapi_cfg->rfg_redist = rfapi_group_lookup_byname (bgp, argv[3]->arg);
+ bgp->rfapi_cfg->rfg_redist = bgp_rfapi_cfg_match_byname (bgp, argv[3]->arg,
+ RFAPI_GROUP_CFG_NVE);
if (bgp->rfapi_cfg->rfg_redist_name)
free (bgp->rfapi_cfg->rfg_redist_name);
bgp->rfapi_cfg->rfg_redist_name = strdup (argv[3]->arg);
@@ -1622,7 +1635,7 @@ DEFUN (vnc_export_nvegroup,
return CMD_WARNING;
}
- rfg_new = rfapi_group_lookup_byname (bgp, argv[5]->arg);
+ rfg_new = bgp_rfapi_cfg_match_byname (bgp, argv[5]->arg, RFAPI_GROUP_CFG_NVE);
if (argv[2]->arg[0] == 'b')
{
@@ -2417,20 +2430,17 @@ DEFUN (vnc_nve_group,
struct rfapi_rfg_name *rfgn;
/* Search for name */
- rfg = rfapi_group_lookup_byname (bgp, argv[2]->arg);
+ rfg = bgp_rfapi_cfg_match_byname (bgp, argv[2]->arg, RFAPI_GROUP_CFG_NVE);
if (!rfg)
{
- rfg = rfapi_group_new ();
+ rfg = rfapi_group_new (bgp, RFAPI_GROUP_CFG_NVE, argv[2]->arg);
if (!rfg)
{
/* Error out of memory */
vty_out (vty, "Can't allocate memory for NVE group%s", VTY_NEWLINE);
return CMD_WARNING;
}
- rfg->name = strdup (argv[2]->arg);
- /* add to tail of list */
- listnode_add (bgp->rfapi_cfg->nve_groups_sequential, rfg);
/* Copy defaults from struct rfapi_cfg */
rfg->rd = bgp->rfapi_cfg->default_rd;
@@ -2453,7 +2463,7 @@ DEFUN (vnc_nve_group,
rfg->rt_import_list =
ecommunity_dup (bgp->rfapi_cfg->default_rt_import_list);
rfg->rfapi_import_table =
- rfapiImportTableRefAdd (bgp, rfg->rt_import_list);
+ rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);
}
/*
@@ -2629,7 +2639,8 @@ static int
bgp_rfapi_delete_named_nve_group (
struct vty *vty, /* NULL = no output */
struct bgp *bgp,
- const char *rfg_name) /* NULL = any */
+ const char *rfg_name, /* NULL = any */
+ rfapi_group_cfg_type_t type) /* _MAX = any */
{
struct rfapi_nve_group_cfg *rfg = NULL;
struct listnode *node, *nnode;
@@ -2638,7 +2649,7 @@ bgp_rfapi_delete_named_nve_group (
/* Search for name */
if (rfg_name)
{
- rfg = rfapi_group_lookup_byname (bgp, rfg_name);
+ rfg = bgp_rfapi_cfg_match_byname (bgp, rfg_name, type);
if (!rfg)
{
if (vty)
@@ -2665,7 +2676,8 @@ bgp_rfapi_delete_named_nve_group (
for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l,
node, rfgn))
{
- if (rfg_name == NULL || !strcmp (rfgn->name, rfg_name))
+ if (rfg_name == NULL ||
+ (type == RFAPI_GROUP_CFG_NVE && !strcmp (rfgn->name, rfg_name)))
{
rfgn->rfg = NULL;
/* remove exported routes from this group */
@@ -2680,7 +2692,8 @@ bgp_rfapi_delete_named_nve_group (
for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn))
{
- if (rfg_name == NULL || !strcmp (rfgn->name, rfg_name))
+ if (rfg_name == NULL ||
+ (type == RFAPI_GROUP_CFG_NVE && !strcmp (rfgn->name, rfg_name)))
{
rfgn->rfg = NULL;
/* remove exported routes from this group */
@@ -2707,7 +2720,7 @@ DEFUN (vnc_no_nve_group,
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[3]->arg);
+ return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[3]->arg, RFAPI_GROUP_CFG_NVE);
}
DEFUN (vnc_nve_group_prefix,
@@ -2890,7 +2903,7 @@ DEFUN (vnc_nve_group_rt_import,
*/
if (rfg->rfapi_import_table)
rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table);
- rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list);
+ rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);
if (is_export_bgp)
vnc_direct_bgp_add_group (bgp, rfg);
@@ -2997,7 +3010,7 @@ DEFUN (vnc_nve_group_rt_both,
*/
if (rfg->rfapi_import_table)
rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table);
- rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list);
+ rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);
if (is_export_bgp)
vnc_direct_bgp_add_group (bgp, rfg);
@@ -3238,6 +3251,492 @@ static struct cmd_node bgp_vnc_nve_group_node = {
};
/*-------------------------------------------------------------------------
+ * VNC nve-group
+ * Note there are two types of NVEs, one for VPNs one for RFP NVEs
+ *-----------------------------------------------------------------------*/
+
+DEFUN (vnc_vrf_policy,
+ vnc_vrf_policy_cmd,
+ "vrf-policy NAME",
+ "Configure a VRF policy group\n"
+ "VRF name\n")
+{
+ struct rfapi_nve_group_cfg *rfg;
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Search for name */
+ rfg = bgp_rfapi_cfg_match_byname (bgp, argv[1]->arg, RFAPI_GROUP_CFG_VRF);
+
+ if (!rfg)
+ {
+ rfg = rfapi_group_new (bgp, RFAPI_GROUP_CFG_VRF, argv[1]->arg);
+ if (!rfg)
+ {
+ /* Error out of memory */
+ vty_out (vty, "Can't allocate memory for NVE group%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ /*
+ * XXX subsequent calls will need to make sure this item is still
+ * in the linked list and has the same name
+ */
+ VTY_PUSH_CONTEXT_SUB (BGP_VRF_POLICY_NODE, rfg);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vnc_no_vrf_policy,
+ vnc_no_vrf_policy_cmd,
+ "no vrf-policy NAME",
+ NO_STR
+ "Remove a VRF policy group\n"
+ "VRF name\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[2]->arg, RFAPI_GROUP_CFG_VRF);
+}
+
+DEFUN (vnc_vrf_policy_label,
+ vnc_vrf_policy_label_cmd,
+ "label (0-1048575)",
+ "Default label value for VRF\n"
+ "Label Value <0-1048575>\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+
+ uint32_t label;
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ VTY_GET_INTEGER_RANGE ("Label value", label, argv[1]->arg, 0, MPLS_LABEL_MAX);
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ rfg->label = label;
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (vnc_vrf_policy_no_label,
+ vnc_vrf_policy_no_label_cmd,
+ "no label",
+ "Remove VRF default label\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current VRF group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ rfg->label = MPLS_LABEL_ILLEGAL;
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (vnc_vrf_policy_nexthop,
+ vnc_vrf_policy_nexthop_cmd,
+ "nexthop <A.B.C.D|X:X::X:X|self>",
+ "Specify next hop to use for VRF advertised prefixes\n"
+ "IPv4 prefix\n"
+ "IPv6 prefix\n"
+ "Use configured router-id (default)")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ struct prefix p;
+
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current VRF no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ if (!str2prefix (argv[1]->arg, &p) && p.family)
+ {
+ //vty_out (vty, "Nexthop set to self%s", VTY_NEWLINE);
+ SET_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF);
+ memset(&rfg->vn_prefix, 0, sizeof(struct prefix));
+ }
+ else
+ {
+ UNSET_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF);
+ rfg->vn_prefix = p;
+ }
+
+ /* TBD handle router-id/ nexthop changes when have advertised prefixes */
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* The RT code should be refactored/simplified with above... */
+DEFUN (vnc_vrf_policy_rt_import,
+ vnc_vrf_policy_rt_import_cmd,
+ "rt import RTLIST...",
+ "Specify route targets\n"
+ "Import filter\n"
+ "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int rc;
+ struct listnode *node;
+ struct rfapi_rfg_name *rfgn;
+ int is_export_bgp = 0;
+ int is_export_zebra = 0;
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list);
+ if (rc != CMD_SUCCESS)
+ return rc;
+
+ for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l,
+ node, rfgn))
+ {
+
+ if (rfgn->rfg == rfg)
+ {
+ is_export_bgp = 1;
+ break;
+ }
+ }
+
+ if (is_export_bgp)
+ vnc_direct_bgp_del_group (bgp, rfg);
+
+ for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn))
+ {
+
+ if (rfgn->rfg == rfg)
+ {
+ is_export_zebra = 1;
+ break;
+ }
+ }
+
+ if (is_export_zebra)
+ vnc_zebra_del_group (bgp, rfg);
+
+ /*
+ * stop referencing old import table, now reference new one
+ */
+ if (rfg->rfapi_import_table)
+ rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table);
+ rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);
+
+ if (is_export_bgp)
+ vnc_direct_bgp_add_group (bgp, rfg);
+
+ if (is_export_zebra)
+ vnc_zebra_add_group (bgp, rfg);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (vnc_vrf_policy_rt_export,
+ vnc_vrf_policy_rt_export_cmd,
+ "rt export RTLIST...",
+ "Specify route targets\n"
+ "Export filter\n"
+ "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int rc;
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list);
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+
+ return rc;
+}
+
+DEFUN (vnc_vrf_policy_rt_both,
+ vnc_vrf_policy_rt_both_cmd,
+ "rt both RTLIST...",
+ "Specify route targets\n"
+ "Export+import filters\n"
+ "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int rc;
+ int is_export_bgp = 0;
+ int is_export_zebra = 0;
+ struct listnode *node;
+ struct rfapi_rfg_name *rfgn;
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list);
+ if (rc != CMD_SUCCESS)
+ return rc;
+
+ for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l,
+ node, rfgn))
+ {
+
+ if (rfgn->rfg == rfg)
+ {
+ is_export_bgp = 1;
+ break;
+ }
+ }
+
+ if (is_export_bgp)
+ vnc_direct_bgp_del_group (bgp, rfg);
+
+ for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn))
+ {
+
+ if (rfgn->rfg == rfg)
+ {
+ is_export_zebra = 1;
+ break;
+ }
+ }
+
+ if (is_export_zebra)
+ {
+ vnc_zlog_debug_verbose ("%s: is_export_zebra", __func__);
+ vnc_zebra_del_group (bgp, rfg);
+ }
+
+ /*
+ * stop referencing old import table, now reference new one
+ */
+ if (rfg->rfapi_import_table)
+ rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table);
+ rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);
+
+ if (is_export_bgp)
+ vnc_direct_bgp_add_group (bgp, rfg);
+
+ if (is_export_zebra)
+ vnc_zebra_add_group (bgp, rfg);
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list);
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+
+ return rc;
+
+}
+
+DEFUN (vnc_vrf_policy_rd,
+ vnc_vrf_policy_rd_cmd,
+ "rd ASN:nn_or_IP-address:nn",
+ "Specify default VRF route distinguisher\n"
+ "Route Distinguisher (<as-number>:<number> | <ip-address>:<number> | auto:nh:<number> )\n")
+{
+ int ret;
+ struct prefix_rd prd;
+ VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* make sure it's still in list */
+ if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg))
+ {
+ /* Not in list anymore */
+ vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!strncmp (argv[1]->arg, "auto:nh:", 8))
+ {
+ /*
+ * use AF_UNIX to designate automatically-assigned RD
+ * auto:vn:nn where nn is a 2-octet quantity
+ */
+ char *end = NULL;
+ uint32_t value32 = strtoul (argv[1]->arg + 8, &end, 10);
+ uint16_t value = value32 & 0xffff;
+
+ if (!*(argv[1]->arg + 5) || *end)
+ {
+ vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (value32 > 0xffff)
+ {
+ vty_out (vty, "%% Malformed rd (must be less than %u%s",
+ 0x0ffff, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ memset (&prd, 0, sizeof (prd));
+ prd.family = AF_UNIX;
+ prd.prefixlen = 64;
+ prd.val[0] = (RD_TYPE_IP >> 8) & 0x0ff;
+ prd.val[1] = RD_TYPE_IP & 0x0ff;
+ prd.val[6] = (value >> 8) & 0x0ff;
+ prd.val[7] = value & 0x0ff;
+
+ }
+ else
+ {
+
+ ret = str2prefix_rd (argv[1]->arg, &prd);
+ if (!ret)
+ {
+ vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_prechange (bgp);
+ }
+
+ rfg->rd = prd;
+
+ if (bgp->rfapi_cfg->rfg_redist == rfg)
+ {
+ vnc_redistribute_postchange (bgp);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (exit_vrf_policy,
+ exit_vrf_policy_cmd,
+ "exit-vrf-policy",
+ "Exit VRF policy configuration mode\n")
+{
+ if (vty->node == BGP_VRF_POLICY_NODE)
+ {
+ vty->node = BGP_NODE;
+ }
+ return CMD_SUCCESS;
+}
+
+static struct cmd_node bgp_vrf_policy_node = {
+ BGP_VRF_POLICY_NODE,
+ "%s(config-router-vrf-policy)# ",
+ 1
+};
+
+/*-------------------------------------------------------------------------
* vnc-l2-group
*-----------------------------------------------------------------------*/
@@ -3247,11 +3746,17 @@ DEFUN (vnc_l2_group,
"vnc l2-group NAME",
VNC_CONFIG_STR "Configure a L2 group\n" "Group name\n")
{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
struct rfapi_l2_group_cfg *rfg;
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
/* Search for name */
- rfg = rfapi_l2_group_lookup_byname (bgp, argv[2]->arg);
+ rfg = rfapi_l2_group_lookup_byname (bgp, argv[1]->arg);
if (!rfg)
{
@@ -3262,7 +3767,7 @@ DEFUN (vnc_l2_group,
vty_out (vty, "Can't allocate memory for L2 group%s", VTY_NEWLINE);
return CMD_WARNING;
}
- rfg->name = strdup (argv[2]->arg);
+ rfg->name = strdup (argv[1]->arg);
/* add to tail of list */
listnode_add (bgp->rfapi_cfg->l2_groups, rfg);
}
@@ -3336,18 +3841,29 @@ DEFUN (vnc_no_l2_group,
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
return bgp_rfapi_delete_named_l2_group (vty, bgp, argv[3]->arg);
}
DEFUN (vnc_l2_group_lni,
vnc_l2_group_lni_cmd,
- "logical-network-id (0-4294967295)",
+ "logical-network-id <0-4294967295>",
"Specify Logical Network ID associated with group\n"
"value\n")
{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
/* make sure it's still in list */
if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
@@ -3364,14 +3880,20 @@ DEFUN (vnc_l2_group_lni,
DEFUN (vnc_l2_group_labels,
vnc_l2_group_labels_cmd,
- "labels LABELLIST...",
+ "labels .LABELLIST",
"Specify label values associated with group\n"
"Space separated list of label values <0-1048575>\n")
{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
struct list *ll;
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
/* make sure it's still in list */
if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
{
@@ -3386,13 +3908,12 @@ DEFUN (vnc_l2_group_labels,
ll = list_new ();
rfg->labels = ll;
}
-
- argc -= 1;
- argv += 1;
+ argc--;
+ argv++;
for (; argc; --argc, ++argv)
{
uint32_t label;
- VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, 1048575);
+ VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, MPLS_LABEL_MAX);
if (!listnode_lookup (ll, (void *) (uintptr_t) label))
listnode_add (ll, (void *) (uintptr_t) label);
}
@@ -3402,16 +3923,22 @@ DEFUN (vnc_l2_group_labels,
DEFUN (vnc_l2_group_no_labels,
vnc_l2_group_no_labels_cmd,
- "no labels LABELLIST...",
+ "no labels .LABELLIST",
NO_STR
"Remove label values associated with L2 group\n"
"Specify label values associated with L2 group\n"
"Space separated list of label values <0-1048575>\n")
{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
struct list *ll;
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
/* make sure it's still in list */
if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))
{
@@ -3427,12 +3954,12 @@ DEFUN (vnc_l2_group_no_labels,
return CMD_WARNING;
}
- argc -= 2;
- argv += 2;
+ argc-=2;
+ argv+=2;
for (; argc; --argc, ++argv)
{
uint32_t label;
- VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, 1048575);
+ VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, MPLS_LABEL_MAX);
listnode_delete (ll, (void *) (uintptr_t) label);
}
@@ -3448,8 +3975,8 @@ DEFUN (vnc_l2_group_rt,
"Import filters\n"
"A route target\n")
{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg);
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
int rc = CMD_SUCCESS;
int do_import = 0;
int do_export = 0;
@@ -3467,10 +3994,8 @@ DEFUN (vnc_l2_group_rt,
default:
vty_out (vty, "Unknown option, %s%s", argv[1]->arg, VTY_NEWLINE);
return CMD_ERR_NO_MATCH;
- }
- if (argc < 3)
- return CMD_ERR_INCOMPLETE;
+ }
if (!bgp)
{
vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
@@ -3486,9 +4011,9 @@ DEFUN (vnc_l2_group_rt,
}
if (do_import)
- rc = set_ecom_list (vty, argc - 2, argv + 2, &rfg->rt_import_list);
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list);
if (rc == CMD_SUCCESS && do_export)
- rc = set_ecom_list (vty, argc - 2, argv + 2, &rfg->rt_export_list);
+ rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list);
return rc;
}
@@ -3571,7 +4096,9 @@ bgp_rfapi_cfg_init (void)
install_node (&bgp_vnc_defaults_node, NULL);
install_node (&bgp_vnc_nve_group_node, NULL);
+ install_node (&bgp_vrf_policy_node, NULL);
install_node (&bgp_vnc_l2_group_node, NULL);
+ install_default (BGP_VRF_POLICY_NODE);
install_default (BGP_VNC_DEFAULTS_NODE);
install_default (BGP_VNC_NVE_GROUP_NODE);
install_default (BGP_VNC_L2_GROUP_NODE);
@@ -3582,6 +4109,8 @@ bgp_rfapi_cfg_init (void)
install_element (BGP_NODE, &vnc_defaults_cmd);
install_element (BGP_NODE, &vnc_nve_group_cmd);
install_element (BGP_NODE, &vnc_no_nve_group_cmd);
+ install_element (BGP_NODE, &vnc_vrf_policy_cmd);
+ install_element (BGP_NODE, &vnc_no_vrf_policy_cmd);
install_element (BGP_NODE, &vnc_l2_group_cmd);
install_element (BGP_NODE, &vnc_no_l2_group_cmd);
install_element (BGP_NODE, &vnc_advertise_un_method_cmd);
@@ -3645,6 +4174,16 @@ bgp_rfapi_cfg_init (void)
&vnc_nve_group_export_no_routemap_cmd);
install_element (BGP_VNC_NVE_GROUP_NODE, &exit_vnc_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_label_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_no_label_cmd);
+ //Hide per Jan 17 discussion
+ //install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_nexthop_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_import_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_export_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_both_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rd_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
+
install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_lni_cmd);
install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_labels_cmd);
install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_no_labels_cmd);
@@ -3713,7 +4252,7 @@ bgp_rfapi_cfg_destroy (struct bgp *bgp, struct rfapi_cfg *h)
if (h == NULL)
return;
- bgp_rfapi_delete_named_nve_group (NULL, bgp, NULL);
+ bgp_rfapi_delete_named_nve_group (NULL, bgp, NULL, RFAPI_GROUP_CFG_MAX);
bgp_rfapi_delete_named_l2_group (NULL, bgp, NULL);
if (h->l2_groups != NULL)
list_delete (h->l2_groups);
@@ -3741,6 +4280,166 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
afi_t afi;
int type;
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ for (ALL_LIST_ELEMENTS (hc->nve_groups_sequential, node, nnode, rfg))
+ if (rfg->type == RFAPI_GROUP_CFG_VRF)
+ {
+ ++write;
+ vty_out (vty, " vrf-policy %s%s", rfg->name, VTY_NEWLINE);
+ if (rfg->label <= MPLS_LABEL_MAX)
+ {
+ vty_out (vty, " label %u%s", rfg->label, VTY_NEWLINE);
+
+ }
+ if (CHECK_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF))
+ {
+ vty_out (vty, " nexthop self%s", VTY_NEWLINE);
+
+ }
+ else
+ {
+ if (rfg->vn_prefix.family)
+ {
+ char buf[BUFSIZ];
+ buf[0] = buf[BUFSIZ - 1] = 0;
+ inet_ntop(rfg->vn_prefix.family, &rfg->vn_prefix.u.prefix, buf, sizeof(buf));
+ if (!buf[0] || buf[BUFSIZ - 1])
+ {
+ //vty_out (vty, "nexthop self%s", VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out (vty, " nexthop %s%s", buf, VTY_NEWLINE);
+ }
+ }
+ }
+
+ if (rfg->rd.prefixlen)
+ {
+ char buf[BUFSIZ];
+ buf[0] = buf[BUFSIZ - 1] = 0;
+
+ if (AF_UNIX == rfg->rd.family)
+ {
+
+ uint16_t value = 0;
+
+ value = ((rfg->rd.val[6] << 8) & 0x0ff00) |
+ (rfg->rd.val[7] & 0x0ff);
+
+ vty_out (vty, " rd auto:nh:%d%s", value, VTY_NEWLINE);
+
+ }
+ else
+ {
+
+ if (!prefix_rd2str (&rfg->rd, buf, BUFSIZ) ||
+ !buf[0] || buf[BUFSIZ - 1])
+ {
+
+ vty_out (vty, "!Error: Can't convert rd%s", VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out (vty, " rd %s%s", buf, VTY_NEWLINE);
+ }
+ }
+ }
+
+ if (rfg->rt_import_list && rfg->rt_export_list &&
+ ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list))
+ {
+ char *b = ecommunity_ecom2str (rfg->rt_import_list,
+ ECOMMUNITY_FORMAT_ROUTE_MAP);
+ vty_out (vty, " rt both %s%s", b, VTY_NEWLINE);
+ XFREE (MTYPE_ECOMMUNITY_STR, b);
+ }
+ else
+ {
+ if (rfg->rt_import_list)
+ {
+ char *b = ecommunity_ecom2str (rfg->rt_import_list,
+ ECOMMUNITY_FORMAT_ROUTE_MAP);
+ vty_out (vty, " rt import %s%s", b, VTY_NEWLINE);
+ XFREE (MTYPE_ECOMMUNITY_STR, b);
+ }
+ if (rfg->rt_export_list)
+ {
+ char *b = ecommunity_ecom2str (rfg->rt_export_list,
+ ECOMMUNITY_FORMAT_ROUTE_MAP);
+ vty_out (vty, " rt export %s%s", b, VTY_NEWLINE);
+ XFREE (MTYPE_ECOMMUNITY_STR, b);
+ }
+ }
+
+ /*
+ * route filtering: prefix-lists and route-maps
+ */
+ for (afi = AFI_IP; afi < AFI_MAX; ++afi)
+ {
+
+ const char *afistr = (afi == AFI_IP) ? "ipv4" : "ipv6";
+
+ if (rfg->plist_export_bgp_name[afi])
+ {
+ vty_out (vty, " export bgp %s prefix-list %s%s",
+ afistr, rfg->plist_export_bgp_name[afi],
+ VTY_NEWLINE);
+ }
+ if (rfg->plist_export_zebra_name[afi])
+ {
+ vty_out (vty, " export zebra %s prefix-list %s%s",
+ afistr, rfg->plist_export_zebra_name[afi],
+ VTY_NEWLINE);
+ }
+ /*
+ * currently we only support redist plists for bgp-direct.
+ * If we later add plist support for redistributing other
+ * protocols, we'll need to loop over protocols here
+ */
+ if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi])
+ {
+ vty_out (vty, " redistribute bgp-direct %s prefix-list %s%s",
+ afistr,
+ rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi],
+ VTY_NEWLINE);
+ }
+ if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT][afi])
+ {
+ vty_out (vty,
+ " redistribute bgp-direct-to-nve-groups %s prefix-list %s%s",
+ afistr,
+ rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT]
+ [afi], VTY_NEWLINE);
+ }
+ }
+
+ if (rfg->routemap_export_bgp_name)
+ {
+ vty_out (vty, " export bgp route-map %s%s",
+ rfg->routemap_export_bgp_name, VTY_NEWLINE);
+ }
+ if (rfg->routemap_export_zebra_name)
+ {
+ vty_out (vty, " export zebra route-map %s%s",
+ rfg->routemap_export_zebra_name, VTY_NEWLINE);
+ }
+ if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT])
+ {
+ vty_out (vty, " redistribute bgp-direct route-map %s%s",
+ rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT],
+ VTY_NEWLINE);
+ }
+ if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT])
+ {
+ vty_out (vty,
+ " redistribute bgp-direct-to-nve-groups route-map %s%s",
+ rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT],
+ VTY_NEWLINE);
+ }
+ vty_out (vty, " exit-vrf-policy%s", VTY_NEWLINE);
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
if (hc->flags & BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP)
{
vty_out (vty, " vnc advertise-un-method encap-safi%s", VTY_NEWLINE);
@@ -3902,6 +4601,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)
}
for (ALL_LIST_ELEMENTS (hc->nve_groups_sequential, node, nnode, rfg))
+ if (rfg->type == RFAPI_GROUP_CFG_NVE)
{
++write;
vty_out (vty, " vnc nve-group %s%s", rfg->name, VTY_NEWLINE);
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.h b/bgpd/rfapi/bgp_rfapi_cfg.h
index 897b4be764..8f93d69f6b 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.h
+++ b/bgpd/rfapi/bgp_rfapi_cfg.h
@@ -41,12 +41,21 @@ struct rfapi_l2_group_cfg
};
DECLARE_QOBJ_TYPE(rfapi_l2_group_cfg)
+typedef enum
+{
+ RFAPI_GROUP_CFG_NVE = 1,
+ RFAPI_GROUP_CFG_VRF,
+ RFAPI_GROUP_CFG_L2,
+ RFAPI_GROUP_CFG_MAX
+} rfapi_group_cfg_type_t;
+
struct rfapi_nve_group_cfg
{
struct route_node *vn_node; /* backref */
struct route_node *un_node; /* backref */
- char *name;
+ rfapi_group_cfg_type_t type; /* NVE|VPN */
+ char *name; /* unique by type! */
struct prefix vn_prefix;
struct prefix un_prefix;
@@ -54,8 +63,9 @@ struct rfapi_nve_group_cfg
uint8_t l2rd; /* 0 = VN addr LSB */
uint32_t response_lifetime;
uint32_t flags;
-#define RFAPI_RFG_RESPONSE_LIFETIME 0x1
+#define RFAPI_RFG_RESPONSE_LIFETIME 0x01 /* bits */
#define RFAPI_RFG_L2RD 0x02
+#define RFAPI_RFG_VPN_NH_SELF 0x04
struct ecommunity *rt_import_list;
struct ecommunity *rt_export_list;
struct rfapi_import_table *rfapi_import_table;
@@ -99,6 +109,9 @@ struct rfapi_nve_group_cfg
char *routemap_redist_name[ZEBRA_ROUTE_MAX];
struct route_map *routemap_redist[ZEBRA_ROUTE_MAX];
+ /* for VRF type groups */
+ uint32_t label;
+ struct rfapi_descriptor *rfd;
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(rfapi_nve_group_cfg)
@@ -288,6 +301,12 @@ bgp_rfapi_cfg_match_group (
struct prefix *vn,
struct prefix *un);
+struct rfapi_nve_group_cfg *
+bgp_rfapi_cfg_match_byname (
+ struct bgp *bgp,
+ const char *name,
+ rfapi_group_cfg_type_t type); /* _MAX = any */
+
extern void
vnc_prefix_list_update (struct bgp *bgp);
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index 25fb7aaf65..1fc2929ef1 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -335,6 +335,9 @@ is_valid_rfd (struct rfapi_descriptor *rfd)
if (!rfd || rfd->bgp == NULL)
return 0;
+ if (CHECK_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF)) /* assume VRF/internal are valid */
+ return 1;
+
if (rfapi_find_handle (rfd->bgp, &rfd->vn_addr, &rfd->un_addr, &hh))
return 0;
@@ -357,6 +360,9 @@ rfapi_check (void *handle)
if (!rfd || rfd->bgp == NULL)
return EINVAL;
+ if (CHECK_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF)) /* assume VRF/internal are valid */
+ return 0;
+
if ((rc = rfapi_find_handle (rfd->bgp, &rfd->vn_addr, &rfd->un_addr, &hh)))
return rc;
@@ -1348,7 +1354,6 @@ rfapi_rfp_set_cb_methods (void *rfp_start_val,
/***********************************************************************
* NVE Sessions
***********************************************************************/
-
/*
* Caller must supply an already-allocated rfd with the "caller"
* fields already set (vn_addr, un_addr, callback, cookie)
@@ -1475,6 +1480,57 @@ rfapi_open_inner (
return 0;
}
+/* moved from rfapi_register */
+int
+rfapi_init_and_open(
+ struct bgp *bgp,
+ struct rfapi_descriptor *rfd,
+ struct rfapi_nve_group_cfg *rfg)
+{
+ struct rfapi *h = bgp->rfapi;
+ char buf_vn[BUFSIZ];
+ char buf_un[BUFSIZ];
+ afi_t afi_vn, afi_un;
+ struct prefix pfx_un;
+ struct route_node *rn;
+
+
+ rfapi_time (&rfd->open_time);
+
+ if (rfg->type == RFAPI_GROUP_CFG_VRF)
+ SET_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF);
+
+ rfapiRfapiIpAddr2Str (&rfd->vn_addr, buf_vn, BUFSIZ);
+ rfapiRfapiIpAddr2Str (&rfd->un_addr, buf_un, BUFSIZ);
+
+ vnc_zlog_debug_verbose ("%s: new RFD with VN=%s UN=%s cookie=%p",
+ __func__, buf_vn, buf_un, rfd->cookie);
+
+ if (rfg->type != RFAPI_GROUP_CFG_VRF) /* unclear if needed for VRF */
+ {
+ listnode_add (&h->descriptors, rfd);
+ if (h->descriptors.count > h->stat.max_descriptors)
+ {
+ h->stat.max_descriptors = h->descriptors.count;
+ }
+
+ /*
+ * attach to UN radix tree
+ */
+ afi_vn = family2afi (rfd->vn_addr.addr_family);
+ afi_un = family2afi (rfd->un_addr.addr_family);
+ assert (afi_vn && afi_un);
+ assert (!rfapiRaddr2Qprefix (&rfd->un_addr, &pfx_un));
+
+ rn = route_node_get (&(h->un[afi_un]), &pfx_un);
+ assert (rn);
+ rfd->next = rn->info;
+ rn->info = rfd;
+ rfd->un_node = rn;
+ }
+ return rfapi_open_inner (rfd, bgp, h, rfg);
+}
+
struct rfapi_vn_option *
rfapiVnOptionsDup (struct rfapi_vn_option *orig)
{
@@ -1992,14 +2048,10 @@ rfapi_open (
struct prefix pfx_vn;
struct prefix pfx_un;
- struct route_node *rn;
int rc;
rfapi_handle hh = NULL;
int reusing_provisional = 0;
- afi_t afi_vn;
- afi_t afi_un;
-
{
char buf[2][INET_ADDRSTRLEN];
vnc_zlog_debug_verbose ("%s: VN=%s UN=%s", __func__,
@@ -2130,40 +2182,7 @@ rfapi_open (
if (!reusing_provisional)
{
- rfapi_time (&rfd->open_time);
-
- {
- char buf_vn[BUFSIZ];
- char buf_un[BUFSIZ];
-
- rfapiRfapiIpAddr2Str (vn, buf_vn, BUFSIZ);
- rfapiRfapiIpAddr2Str (un, buf_un, BUFSIZ);
-
- vnc_zlog_debug_verbose ("%s: new HD with VN=%s UN=%s cookie=%p",
- __func__, buf_vn, buf_un, userdata);
- }
-
- listnode_add (&h->descriptors, rfd);
- if (h->descriptors.count > h->stat.max_descriptors)
- {
- h->stat.max_descriptors = h->descriptors.count;
- }
-
- /*
- * attach to UN radix tree
- */
- afi_vn = family2afi (rfd->vn_addr.addr_family);
- afi_un = family2afi (rfd->un_addr.addr_family);
- assert (afi_vn && afi_un);
- assert (!rfapiRaddr2Qprefix (&rfd->un_addr, &pfx_un));
-
- rn = route_node_get (&(h->un[afi_un]), &pfx_un);
- assert (rn);
- rfd->next = rn->info;
- rn->info = rfd;
- rfd->un_node = rn;
-
- rc = rfapi_open_inner (rfd, bgp, h, rfg);
+ rc = rfapi_init_and_open(bgp, rfd, rfg);
/*
* This can fail only if the VN address is IPv6 and the group
* specified auto-assignment of RDs, which only works for v4,
diff --git a/bgpd/rfapi/rfapi_backend.h b/bgpd/rfapi/rfapi_backend.h
index 788ec73751..9e5b0dc5cb 100644
--- a/bgpd/rfapi/rfapi_backend.h
+++ b/bgpd/rfapi/rfapi_backend.h
@@ -36,15 +36,6 @@ extern void rfapi_delete (struct bgp *);
struct rfapi *bgp_rfapi_new (struct bgp *bgp);
void bgp_rfapi_destroy (struct bgp *bgp, struct rfapi *h);
-struct rfapi_import_table *rfapiImportTableRefAdd (struct bgp *bgp,
- struct ecommunity
- *rt_import_list);
-
-void
-rfapiImportTableRefDelByIt (struct bgp *bgp,
- struct rfapi_import_table *it_target);
-
-
extern void
rfapiProcessUpdate (struct peer *peer,
void *rfd,
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 590691a6b7..8e68eec53a 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -4650,7 +4650,8 @@ bgp_rfapi_destroy (struct bgp *bgp, struct rfapi *h)
}
struct rfapi_import_table *
-rfapiImportTableRefAdd (struct bgp *bgp, struct ecommunity *rt_import_list)
+rfapiImportTableRefAdd (struct bgp *bgp, struct ecommunity *rt_import_list,
+ struct rfapi_nve_group_cfg *rfg)
{
struct rfapi *h;
struct rfapi_import_table *it;
@@ -4676,6 +4677,7 @@ rfapiImportTableRefAdd (struct bgp *bgp, struct ecommunity *rt_import_list)
h->imports = it;
it->rt_import_list = ecommunity_dup (rt_import_list);
+ it->rfg = rfg;
it->monitor_exterior_orphans =
skiplist_new (0, NULL, (void (*)(void *)) prefix_free);
@@ -4949,6 +4951,7 @@ rfapiDeleteRemotePrefixesIt (
* un if set, tunnel must match this prefix
* vn if set, nexthop prefix must match this prefix
* p if set, prefix must match this prefix
+ * it if set, only look in this import table
*
* output
* pARcount number of active routes deleted
@@ -4964,6 +4967,7 @@ rfapiDeleteRemotePrefixes (
struct prefix *un,
struct prefix *vn,
struct prefix *p,
+ struct rfapi_import_table *arg_it,
int delete_active,
int delete_holddown,
uint32_t *pARcount,
@@ -5001,7 +5005,11 @@ rfapiDeleteRemotePrefixes (
* for the afi/safi combination
*/
- for (it = h->imports; it; it = it->next)
+ if (arg_it)
+ it = arg_it;
+ else
+ it = h->imports;
+ for (; it; )
{
vnc_zlog_debug_verbose
@@ -5022,6 +5030,11 @@ rfapiDeleteRemotePrefixes (
&deleted_holddown_nve_count,
uniq_active_nves,
uniq_holddown_nves);
+
+ if (arg_it)
+ it = NULL;
+ else
+ it = it->next;
}
/*
diff --git a/bgpd/rfapi/rfapi_import.h b/bgpd/rfapi/rfapi_import.h
index 3cf55462a1..3ba76539dd 100644
--- a/bgpd/rfapi/rfapi_import.h
+++ b/bgpd/rfapi/rfapi_import.h
@@ -38,6 +38,7 @@
struct rfapi_import_table
{
struct rfapi_import_table *next;
+ struct rfapi_nve_group_cfg *rfg;
struct ecommunity *rt_import_list; /* copied from nve grp */
int refcount; /* nve grps and nves */
uint32_t l2_logical_net_id; /* L2 only: EVPN Eth Seg Id */
@@ -90,6 +91,11 @@ rfapiShowImportTable (
struct route_table *rt,
int isvpn);
+extern struct rfapi_import_table *
+rfapiImportTableRefAdd (
+ struct bgp *bgp,
+ struct ecommunity *rt_import_list,
+ struct rfapi_nve_group_cfg *rfg);
extern void
rfapiImportTableRefDelByIt (
@@ -223,6 +229,7 @@ extern int rfapiEcommunityGetEthernetTag (
* un if set, tunnel must match this prefix
* vn if set, nexthop prefix must match this prefix
* p if set, prefix must match this prefix
+ * it if set, only look in this import table
*
* output
* pARcount number of active routes deleted
@@ -238,6 +245,7 @@ rfapiDeleteRemotePrefixes (
struct prefix *un,
struct prefix *vn,
struct prefix *p,
+ struct rfapi_import_table *it,
int delete_active,
int delete_holddown,
uint32_t *pARcount, /* active routes */
diff --git a/bgpd/rfapi/rfapi_private.h b/bgpd/rfapi/rfapi_private.h
index e3022a565d..8ac2966bfe 100644
--- a/bgpd/rfapi/rfapi_private.h
+++ b/bgpd/rfapi/rfapi_private.h
@@ -136,6 +136,7 @@ struct rfapi_descriptor
#define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_ETHER 0x00000004
#define RFAPI_HD_FLAG_PROVISIONAL 0x00000008
#define RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY 0x00000010
+#define RFAPI_HD_FLAG_IS_VRF 0x00000012
};
#define RFAPI_QUEUED_FLAG(afi) ( \
@@ -434,4 +435,17 @@ DECLARE_MTYPE(RFAPI_L2ADDR_OPT)
DECLARE_MTYPE(RFAPI_AP)
DECLARE_MTYPE(RFAPI_MONITOR_ETH)
+
+/*
+ * Caller must supply an already-allocated rfd with the "caller"
+ * fields already set (vn_addr, un_addr, callback, cookie)
+ * The advertised_prefixes[] array elements should be NULL to
+ * have this function set them to newly-allocated radix trees.
+ */
+extern int
+rfapi_init_and_open(
+ struct bgp *bgp,
+ struct rfapi_descriptor *rfd,
+ struct rfapi_nve_group_cfg *rfg);
+
#endif /* _QUAGGA_BGP_RFAPI_PRIVATE_H */
diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c
index 3a4a159215..8e5d47415f 100644
--- a/bgpd/rfapi/rfapi_rib.c
+++ b/bgpd/rfapi/rfapi_rib.c
@@ -514,9 +514,13 @@ rfapi_info_cmp (struct rfapi_info *a, struct rfapi_info *b)
void
rfapiRibClear (struct rfapi_descriptor *rfd)
{
- struct bgp *bgp = bgp_get_default ();
+ struct bgp *bgp;
afi_t afi;
+ if (rfd->bgp)
+ bgp = rfd->bgp;
+ else
+ bgp = bgp_get_default ();
#if DEBUG_L2_EXTRA
vnc_zlog_debug_verbose ("%s: rfd=%p", __func__, rfd);
#endif
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index ed3155307d..7fbfae2951 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -1446,17 +1446,24 @@ rfapiShowRemoteRegistrationsIt (
if (pLni)
{
- fp (out, "%s[%s] L2VPN Network 0x%x (%u) RT={%s}%s",
- HVTY_NEWLINE, type, *pLni, (*pLni & 0xfff), s,
- HVTY_NEWLINE);
+ fp (out, "%s[%s] L2VPN Network 0x%x (%u) RT={%s}",
+ HVTY_NEWLINE, type, *pLni, (*pLni & 0xfff), s);
}
else
{
- fp (out, "%s[%s] Prefix RT={%s}%s",
- HVTY_NEWLINE, type, s, HVTY_NEWLINE);
+ fp (out, "%s[%s] Prefix RT={%s}",
+ HVTY_NEWLINE, type, s);
}
XFREE (MTYPE_ECOMMUNITY_STR, s);
+ if (it->rfg && it->rfg->name)
+ {
+ fp (out, " %s \"%s\"",
+ (it->rfg->type == RFAPI_GROUP_CFG_VRF ?
+ "VRF" : "NVE group"),
+ it->rfg->name);
+ }
+ fp (out, "%s", HVTY_NEWLINE);
if (show_expiring)
{
#if RFAPI_REGISTRATIONS_REPORT_AGE
@@ -3004,9 +3011,12 @@ struct rfapi_local_reg_delete_arg
/*
* match parameters
*/
+ struct bgp *bgp;
struct rfapi_ip_addr un_address; /* AF==0: wildcard */
struct rfapi_ip_addr vn_address; /* AF==0: wildcard */
struct prefix prefix; /* AF==0: wildcard */
+ struct prefix_rd rd; /* plen!=64: wildcard */
+ struct rfapi_nve_group_cfg *rfg; /* NULL: wildcard */
struct rfapi_l2address_option_match l2o;
@@ -3106,22 +3116,26 @@ nve_addr_cmp (void *k1, void *k2)
static int
parse_deleter_args (
- struct vty *vty,
- struct cmd_token *carg_prefix,
- struct cmd_token *carg_vn,
- struct cmd_token *carg_un,
- struct cmd_token *carg_l2addr,
- struct cmd_token *carg_vni,
- struct rfapi_local_reg_delete_arg *rcdarg)
+ struct vty *vty,
+ struct bgp *bgp,
+ const char *arg_prefix,
+ const char *arg_vn,
+ const char *arg_un,
+ const char *arg_l2addr,
+ const char *arg_vni,
+ const char *arg_rd,
+ struct rfapi_nve_group_cfg *arg_rfg,
+ struct rfapi_local_reg_delete_arg *rcdarg)
{
- const char *arg_prefix = carg_prefix ? carg_prefix->arg : NULL;
- const char *arg_vn = carg_vn ? carg_vn->arg : NULL;
- const char *arg_un = carg_un ? carg_un->arg : NULL;
- const char *arg_l2addr = carg_l2addr ? carg_l2addr->arg : NULL;
- const char *arg_vni = carg_vni ? carg_vni->arg : NULL;
int rc = CMD_WARNING;
- memset (rcdarg, 0, sizeof (struct rfapi_local_reg_delete_arg));
+ memset (rcdarg, 0, sizeof (struct rfapi_local_reg_delete_arg));
+
+ rcdarg->vty = vty;
+ if (bgp == NULL)
+ bgp = bgp_get_default();
+ rcdarg->bgp = bgp;
+ rcdarg->rfg = arg_rfg; /* may be NULL */
if (arg_vn && strcmp (arg_vn, "*"))
{
@@ -3167,7 +3181,41 @@ parse_deleter_args (
rcdarg->l2o.flags |= RFAPI_L2O_LNI;
}
}
- return 0;
+ if (arg_rd)
+ {
+ if (!str2prefix_rd (arg_rd, &rcdarg->rd))
+ {
+ vty_out (vty, "Malformed RD \"%s\"%s",
+ arg_rd, VTY_NEWLINE);
+ return rc;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int
+parse_deleter_tokens (
+ struct vty *vty,
+ struct bgp *bgp,
+ struct cmd_token *carg_prefix,
+ struct cmd_token *carg_vn,
+ struct cmd_token *carg_un,
+ struct cmd_token *carg_l2addr,
+ struct cmd_token *carg_vni,
+ struct cmd_token *carg_rd,
+ struct rfapi_nve_group_cfg *arg_rfg,
+ struct rfapi_local_reg_delete_arg *rcdarg)
+{
+ const char *arg_prefix = carg_prefix ? carg_prefix->arg : NULL;
+ const char *arg_vn = carg_vn ? carg_vn->arg : NULL;
+ const char *arg_un = carg_un ? carg_un->arg : NULL;
+ const char *arg_l2addr = carg_l2addr ? carg_l2addr->arg : NULL;
+ const char *arg_vni = carg_vni ? carg_vni->arg : NULL;
+ const char *arg_rd = carg_rd ? carg_rd->arg : NULL;
+ return parse_deleter_args (vty, bgp,arg_prefix, arg_vn, arg_un,
+ arg_l2addr, arg_vni, arg_rd,
+ arg_rfg, rcdarg);
}
static void
@@ -3271,51 +3319,37 @@ clear_vnc_responses (struct rfapi_local_reg_delete_arg *cda)
* TBD need to count deleted prefixes and nves?
*
* ENXIO BGP or VNC not configured
- */
+ */
static int
-rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
+rfapiDeleteLocalPrefixesByRFD (struct rfapi_local_reg_delete_arg *cda,
+ struct rfapi_descriptor *rfd)
{
- struct rfapi_ip_addr *pUn; /* NULL = wildcard */
- struct rfapi_ip_addr *pVn; /* NULL = wildcard */
- struct prefix *pPrefix; /* NULL = wildcard */
+ struct rfapi_ip_addr *pUn; /* NULL = wildcard */
+ struct rfapi_ip_addr *pVn; /* NULL = wildcard */
+ struct prefix *pPrefix; /* NULL = wildcard */
+ struct prefix_rd *pPrd; /* NULL = wildcard */
- struct rfapi *h;
- struct listnode *node;
- struct rfapi_descriptor *rfd;
struct rfapi_ip_prefix rprefix;
- struct bgp *bgp_default = bgp_get_default ();
struct rfapi_next_hop_entry *head = NULL;
struct rfapi_next_hop_entry *tail = NULL;
- struct rfapi_cfg *rfapi_cfg;
#if DEBUG_L2_EXTRA
- vnc_zlog_debug_verbose ("%s: entry", __func__);
+ vnc_zlog_debug_verbose ("%s: entry", __func__);
#endif
- if (!bgp_default)
- return ENXIO;
-
- pUn = (cda->un_address.addr_family ? &cda->un_address : NULL);
- pVn = (cda->vn_address.addr_family ? &cda->vn_address : NULL);
- pPrefix = (cda->prefix.family ? &cda->prefix : NULL);
-
- h = bgp_default->rfapi;
- rfapi_cfg = bgp_default->rfapi_cfg;
-
- if (!h || !rfapi_cfg)
- return ENXIO;
+ pUn = (cda->un_address.addr_family ? &cda->un_address : NULL);
+ pVn = (cda->vn_address.addr_family ? &cda->vn_address : NULL);
+ pPrefix = (cda->prefix.family ? &cda->prefix : NULL);
+ pPrd = (cda->rd.prefixlen == 64 ? &cda->rd : NULL);
if (pPrefix)
{
rfapiQprefix2Rprefix (pPrefix, &rprefix);
}
-#if DEBUG_L2_EXTRA
- vnc_zlog_debug_verbose ("%s: starting descriptor loop", __func__);
-#endif
-
- for (ALL_LIST_ELEMENTS_RO (&h->descriptors, node, rfd))
+ do /* to preserve old code structure */
{
+ struct rfapi *h=cda->bgp->rfapi;;
struct rfapi_adb *adb;
int rc;
int deleted_from_this_nve;
@@ -3384,6 +3418,17 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
continue;
}
}
+ if (pPrd)
+ {
+ if (memcmp(pPrd->val, adb->u.s.prd.val, 8) != 0)
+ {
+#if DEBUG_L2_EXTRA
+ vnc_zlog_debug_verbose ("%s: adb=%p, RD doesn't match, skipping",
+ __func__, adb);
+#endif
+ continue;
+ }
+ }
if (CHECK_FLAG (cda->l2o.flags, RFAPI_L2O_MACADDR))
{
if (memcmp
@@ -3422,47 +3467,43 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
for (ALL_LIST_ELEMENTS_RO (adb_delete_list, node, adb))
{
-
- struct rfapi_vn_option vn1;
- struct rfapi_vn_option vn2;
- struct rfapi_vn_option *pVn;
int this_advertisement_prefix_count;
+ struct rfapi_vn_option optary[3];
+ struct rfapi_vn_option *opt = NULL;
+ int cur_opt = 0;
this_advertisement_prefix_count = 1;
rfapiQprefix2Rprefix (&adb->u.s.prefix_ip, &rp);
+ memset (optary, 0, sizeof (optary));
+
/* if mac addr present in advert, make l2o vn option */
if (adb->u.s.prefix_eth.family == AF_ETHERNET)
{
- memset (&vn1, 0, sizeof (vn1));
- memset (&vn2, 0, sizeof (vn2));
-
- vn1.type = RFAPI_VN_OPTION_TYPE_L2ADDR;
- vn1.v.l2addr.macaddr = adb->u.s.prefix_eth.u.prefix_eth;
-
- /*
- * use saved RD value instead of trying to invert
- * complex L2-style RD computation in rfapi_register()
- */
- vn2.type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
- vn2.v.internal_rd = adb->u.s.prd;
-
- vn1.next = &vn2;
-
- pVn = &vn1;
+ if (opt != NULL)
+ opt->next = &optary[cur_opt];
+ opt = &optary[cur_opt++];
+ opt->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
+ opt->v.l2addr.macaddr = adb->u.s.prefix_eth.u.prefix_eth;
++this_advertisement_prefix_count;
}
- else
- {
- pVn = NULL;
- }
+ /*
+ * use saved RD value instead of trying to invert
+ * complex RD computation in rfapi_register()
+ */
+ if (opt != NULL)
+ opt->next = &optary[cur_opt];
+ opt = &optary[cur_opt++];
+ opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
+ opt->v.internal_rd = adb->u.s.prd;
#if DEBUG_L2_EXTRA
vnc_zlog_debug_verbose ("%s: ipN killing reg from adb %p ", __func__, adb);
#endif
- rc = rfapi_register (rfd, &rp, 0, NULL, pVn, RFAPI_REGISTER_KILL);
+ rc = rfapi_register (rfd, &rp, 0, NULL,
+ (cur_opt ? optary : NULL), RFAPI_REGISTER_KILL);
if (!rc)
{
cda->pfx_count += this_advertisement_prefix_count;
@@ -3588,11 +3629,44 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
skiplist_insert (cda->nves, hap, hap);
}
}
- }
+ } while (0); /* to preserve old code structure */
return 0;
}
+static int
+rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
+{
+ int rc = 0;
+
+ if (cda->rfg)
+ {
+ if (cda->rfg->rfd) /* if not open, nothing to delete */
+ rc = rfapiDeleteLocalPrefixesByRFD (cda, cda->rfg->rfd);
+ }
+ else
+ {
+ struct bgp *bgp = cda->bgp;
+ struct rfapi *h;
+ struct rfapi_cfg *rfapi_cfg;
+
+ struct listnode *node;
+ struct rfapi_descriptor *rfd;
+ if (!bgp)
+ return ENXIO;
+ h = bgp->rfapi;
+ rfapi_cfg = bgp->rfapi_cfg;
+ if (!h || !rfapi_cfg)
+ return ENXIO;
+ vnc_zlog_debug_verbose ("%s: starting descriptor loop", __func__);
+ for (ALL_LIST_ELEMENTS_RO (&h->descriptors, node, rfd))
+ {
+ rc = rfapiDeleteLocalPrefixesByRFD (cda, rfd);
+ }
+ }
+ return rc;
+}
+
/*
* clear_vnc_prefix
*
@@ -3608,6 +3682,8 @@ clear_vnc_prefix (struct rfapi_local_reg_delete_arg *cda)
struct prefix *pVN = NULL;
struct prefix *pPrefix = NULL;
+ struct rfapi_import_table *it = NULL;
+
/*
* Delete matching remote prefixes in holddown
*/
@@ -3625,7 +3701,11 @@ clear_vnc_prefix (struct rfapi_local_reg_delete_arg *cda)
{
pPrefix = &cda->prefix;
}
- rfapiDeleteRemotePrefixes (pUN, pVN, pPrefix,
+ if (cda->rfg)
+ {
+ it = cda->rfg->rfapi_import_table;
+ }
+ rfapiDeleteRemotePrefixes (pUN, pVN, pPrefix, it,
0, 1, &cda->remote_active_pfx_count,
&cda->remote_active_nve_count,
&cda->remote_holddown_pfx_count,
@@ -3710,7 +3790,7 @@ DEFUN (clear_vnc_nve_all,
struct rfapi_local_reg_delete_arg cda;
int rc;
- if ((rc = parse_deleter_args (vty, NULL, NULL, NULL, NULL, NULL, &cda)))
+ if ((rc = parse_deleter_args (vty, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
@@ -3743,7 +3823,7 @@ DEFUN (clear_vnc_nve_vn_un,
int rc;
if ((rc =
- parse_deleter_args (vty, NULL, argv[4], argv[6], NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, argv[4], argv[6], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
@@ -3776,7 +3856,7 @@ DEFUN (clear_vnc_nve_un_vn,
int rc;
if ((rc =
- parse_deleter_args (vty, NULL, argv[6], argv[4], NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, argv[6], argv[4], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
@@ -3804,7 +3884,7 @@ DEFUN (clear_vnc_nve_vn,
struct rfapi_local_reg_delete_arg cda;
int rc;
- if ((rc = parse_deleter_args (vty, NULL, argv[4], NULL, NULL, NULL, &cda)))
+ if ((rc = parse_deleter_tokens (vty, NULL, NULL, argv[4], NULL, NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
@@ -3831,7 +3911,7 @@ DEFUN (clear_vnc_nve_un,
struct rfapi_local_reg_delete_arg cda;
int rc;
- if ((rc = parse_deleter_args (vty, NULL, NULL, argv[6], NULL, NULL, &cda)))
+ if ((rc = parse_deleter_tokens (vty, NULL, NULL, NULL, argv[6], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
@@ -3874,7 +3954,7 @@ DEFUN (clear_vnc_prefix_vn_un,
int rc;
if ((rc =
- parse_deleter_args (vty, argv[3], argv[5], argv[7], NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, argv[3], argv[5], argv[7], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -3904,7 +3984,7 @@ DEFUN (clear_vnc_prefix_un_vn,
int rc;
if ((rc =
- parse_deleter_args (vty, argv[3], argv[7], argv[5], NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, argv[3], argv[7], argv[5], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -3930,7 +4010,7 @@ DEFUN (clear_vnc_prefix_un,
int rc;
if ((rc =
- parse_deleter_args (vty, argv[3], NULL, argv[5], NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, argv[3], NULL, argv[5], NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -3956,7 +4036,7 @@ DEFUN (clear_vnc_prefix_vn,
int rc;
if ((rc =
- parse_deleter_args (vty, argv[3], argv[5], NULL, NULL, NULL, &cda)))
+ parse_deleter_tokens (vty, NULL, argv[3], argv[5], NULL, NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -3978,7 +4058,7 @@ DEFUN (clear_vnc_prefix_all,
struct rfapi_local_reg_delete_arg cda;
int rc;
- if ((rc = parse_deleter_args (vty, argv[3], NULL, NULL, NULL, NULL, &cda)))
+ if ((rc = parse_deleter_tokens (vty, NULL, argv[3], NULL, NULL, NULL, NULL, NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4020,8 +4100,8 @@ DEFUN (clear_vnc_mac_vn_un,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, NULL, argv[7], argv[9], argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, argv[7], argv[9], argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4054,8 +4134,8 @@ DEFUN (clear_vnc_mac_un_vn,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, NULL, argv[9], argv[7], argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, argv[9], argv[7], argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4084,7 +4164,7 @@ DEFUN (clear_vnc_mac_un,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, NULL, NULL, argv[7], argv[3], argv[5], &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, NULL, argv[7], argv[3], argv[5], NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4113,7 +4193,7 @@ DEFUN (clear_vnc_mac_vn,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, NULL, argv[7], NULL, argv[3], argv[5], &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, argv[7], NULL, argv[3], argv[5], NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4139,7 +4219,7 @@ DEFUN (clear_vnc_mac_all,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, NULL, NULL, NULL, argv[3], argv[5], &cda)))
+ parse_deleter_tokens (vty, NULL, NULL, NULL, NULL, argv[3], argv[5], NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4180,8 +4260,8 @@ DEFUN (clear_vnc_mac_vn_un_prefix,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, argv[11], argv[7], argv[9], argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, argv[11], argv[7], argv[9], argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4222,8 +4302,8 @@ DEFUN (clear_vnc_mac_un_vn_prefix,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, argv[11], argv[9], argv[7], argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, argv[11], argv[9], argv[7], argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4256,8 +4336,8 @@ DEFUN (clear_vnc_mac_un_prefix,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, argv[9], NULL, argv[7], argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, argv[9], NULL, argv[7], argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4290,8 +4370,8 @@ DEFUN (clear_vnc_mac_vn_prefix,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, argv[9], argv[7], NULL, argv[3], argv[5],
- &cda)))
+ parse_deleter_tokens (vty, NULL, argv[9], argv[7], NULL, argv[3], argv[5],
+ NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4320,7 +4400,7 @@ DEFUN (clear_vnc_mac_all_prefix,
/* pfx vn un L2 VNI */
if ((rc =
- parse_deleter_args (vty, argv[7], NULL, NULL, argv[3], argv[5], &cda)))
+ parse_deleter_tokens (vty, NULL, argv[7], NULL, NULL, argv[3], argv[5], NULL, NULL, &cda)))
return rc;
cda.vty = vty;
clear_vnc_prefix (&cda);
@@ -4928,6 +5008,361 @@ notcfg:
return CMD_WARNING;
}
+/************************************************************************
+ * Add prefix with vrf
+ *
+ * add [vrf <vrf-name>] prefix <prefix>
+ * [rd <value>] [label <value>] [local-preference <0-4294967295>]
+ ************************************************************************/
+static int
+vnc_add_vrf_prefix (struct vty *vty,
+ const char *arg_vrf,
+ const char *arg_prefix,
+ const char *arg_rd, /* optional */
+ const char *arg_label, /* optional */
+ const char *arg_pref) /* optional */
+{
+ struct bgp *bgp;
+ struct rfapi_nve_group_cfg *rfg;
+ struct prefix pfx;
+ struct rfapi_ip_prefix rpfx;
+ uint32_t pref = 0;
+ struct rfapi_vn_option optary[3];
+ struct rfapi_vn_option *opt = NULL;
+ int cur_opt = 0;
+
+ bgp = bgp_get_default (); /* assume main instance for now */
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!bgp->rfapi || !bgp->rfapi_cfg)
+ {
+ vty_out (vty, "VRF support not configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ rfg = bgp_rfapi_cfg_match_byname (bgp, arg_vrf, RFAPI_GROUP_CFG_VRF);
+ /* arg checks */
+ if (!rfg)
+ {
+ vty_out (vty, "VRF \"%s\" appears not to be configured.%s",
+ arg_vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!rfg->rt_export_list || !rfg->rfapi_import_table)
+ {
+ vty_out (vty, "VRF \"%s\" is missing RT import/export RT configuration.%s",
+ arg_vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!rfg->rd.family && !arg_rd)
+ {
+ vty_out (vty, "VRF \"%s\" isn't configured with an RD, so RD must be provided.%s",
+ arg_vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (rfg->label > MPLS_LABEL_MAX && !arg_label)
+ {
+ vty_out (vty, "VRF \"%s\" isn't configured with a default labels, so a label must be provided.%s",
+ arg_vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!str2prefix (arg_prefix, &pfx))
+ {
+ vty_out (vty, "Malformed prefix \"%s\"%s",
+ arg_prefix, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ rfapiQprefix2Rprefix (&pfx, &rpfx);
+ memset (optary, 0, sizeof (optary));
+ if (arg_rd)
+ {
+ if (opt != NULL)
+ opt->next = &optary[cur_opt];
+ opt = &optary[cur_opt++];
+ opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
+ if (!str2prefix_rd (arg_rd, &opt->v.internal_rd))
+ {
+ vty_out (vty, "Malformed RD \"%s\"%s",
+ arg_rd, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ if (rfg->label <= MPLS_LABEL_MAX || arg_label)
+ {
+ struct rfapi_l2address_option *l2o;
+ if (opt != NULL)
+ opt->next = &optary[cur_opt];
+ opt = &optary[cur_opt++];
+ opt->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
+ l2o = &opt->v.l2addr;
+ if (arg_label)
+ {
+ int32_t label;
+ VTY_GET_INTEGER_RANGE ("Label value", label, arg_label, 0, MPLS_LABEL_MAX);
+ l2o->label = label;
+ }
+ else
+ l2o->label = rfg->label;
+ }
+ if (arg_pref)
+ {
+ char *endptr = NULL;
+ pref = strtoul (arg_pref, &endptr, 10);
+ if (*endptr != '\0')
+ {
+ vty_out (vty, "%% Invalid local-preference value \"%s\"%s", arg_pref, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ rpfx.cost = 255 - (pref & 255) ;
+ if (rfg->rfd == NULL) /* need new rfapi_handle */
+ {
+ /* based on rfapi_open */
+ struct rfapi_descriptor *rfd;
+ rfd = XCALLOC (MTYPE_RFAPI_DESC, sizeof (struct rfapi_descriptor));
+ rfd->bgp = bgp;
+ rfg->rfd = rfd;
+ /* leave most fields empty as will get from (dynamic) config when needed */
+ rfd->default_tunneltype_option.type = BGP_ENCAP_TYPE_MPLS;
+ rfd->cookie = rfg;
+ if (rfg->vn_prefix.family &&
+ !CHECK_FLAG(rfg->flags, RFAPI_RFG_VPN_NH_SELF))
+ {
+ rfapiQprefix2Raddr(&rfg->vn_prefix, &rfd->vn_addr);
+ }
+ else
+ {
+ memset(&rfd->vn_addr, 0, sizeof(struct rfapi_ip_addr));
+ rfd->vn_addr.addr_family = AF_INET;
+ rfd->vn_addr.addr.v4 = bgp->router_id;
+ }
+ rfd->un_addr = rfd->vn_addr; /* sigh, need something in UN for lookups */
+ vnc_zlog_debug_verbose ("%s: Opening RFD for VRF %s",
+ __func__, rfg->name);
+ rfapi_init_and_open(bgp, rfd, rfg);
+ }
+
+ if (!rfapi_register (rfg->rfd, &rpfx, RFAPI_INFINITE_LIFETIME, NULL,
+ (cur_opt ? optary : NULL), RFAPI_REGISTER_ADD))
+ {
+ struct rfapi_next_hop_entry *head = NULL;
+ struct rfapi_next_hop_entry *tail = NULL;
+ struct rfapi_vn_option *vn_opt_new;
+
+ vnc_zlog_debug_verbose ("%s: rfapi_register succeeded", __func__);
+
+ if (bgp->rfapi->rfp_methods.local_cb)
+ {
+ struct rfapi_descriptor *r = (struct rfapi_descriptor *) rfg->rfd;
+ vn_opt_new = rfapi_vn_options_dup (opt);
+
+ rfapiAddDeleteLocalRfpPrefix (&r->un_addr, &r->vn_addr, &rpfx,
+ 1, RFAPI_INFINITE_LIFETIME,
+ vn_opt_new, &head, &tail);
+ if (head)
+ {
+ bgp->rfapi->flags |= RFAPI_INCALLBACK;
+ (*bgp->rfapi->rfp_methods.local_cb) (head, r->cookie);
+ bgp->rfapi->flags &= ~RFAPI_INCALLBACK;
+ }
+ head = tail = NULL;
+ }
+ vnc_zlog_debug_verbose ("%s completed, count=%d/%d", __func__,
+ rfg->rfapi_import_table->local_count[AFI_IP],
+ rfg->rfapi_import_table->local_count[AFI_IP6]);
+ return CMD_SUCCESS;
+ }
+
+ vnc_zlog_debug_verbose ("%s: rfapi_register failed", __func__);
+ vty_out (vty, "Add failed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+}
+
+DEFUN (add_vrf_prefix_rd_label_pref,
+ add_vrf_prefix_rd_label_pref_cmd,
+ "add vrf NAME prefix <A.B.C.D/M|X:X::X:X/M> [rd ASN:nn_or_IP-address] [label (0-1048575)] [preference (0-4294967295)]",
+ "Add\n"
+ "To a VRF\n"
+ "VRF name\n"
+ "Add/modify prefix related information\n"
+ "IPv4 prefix\n"
+ "IPv6 prefix\n"
+ "Override configured VRF Route Distinguisher\n"
+ "<as-number>:<number> or <ip-address>:<number>\n"
+ "Override configured VRF label"
+ "Label Value <0-1048575>\n"
+ "Set advertised local preference\n"
+ "local preference (higher=more preferred)\n")
+{
+ char *arg_vrf = argv[2]->arg;
+ char *arg_prefix = argv[4]->arg;
+ char *arg_rd = NULL; /* optional */
+ char *arg_label = NULL; /* optional */
+ char *arg_pref = NULL; /* optional */
+ int pargc = 5;
+ argc--; /* don't parse argument */
+ while (pargc < argc)
+ {
+ switch (argv[pargc++]->arg[0])
+ {
+ case 'r':
+ arg_rd = argv[pargc]->arg;
+ break;
+ case 'l':
+ arg_label = argv[pargc]->arg;
+ break;
+ case 'p':
+ arg_pref = argv[pargc]->arg;
+ break;
+ default:
+ break;
+ }
+ pargc ++;
+ }
+
+ return vnc_add_vrf_prefix (vty, arg_vrf, arg_prefix, arg_rd, arg_label, arg_pref);
+}
+
+/************************************************************************
+ * del prefix with vrf
+ *
+ * clear [vrf <vrf-name>] prefix <prefix> [rd <value>]
+ ************************************************************************/
+static int
+rfapi_cfg_group_it_count(struct rfapi_nve_group_cfg *rfg)
+{
+ int count = 0;
+ afi_t afi = AFI_MAX;
+ while (afi-- > 0)
+ {
+ count += rfg->rfapi_import_table->local_count[afi];
+ }
+ return count;
+}
+
+static void
+clear_vnc_vrf_closer (struct rfapi_nve_group_cfg *rfg)
+{
+ struct rfapi_descriptor *rfd = rfg->rfd;
+ afi_t afi;
+
+ if (rfd == NULL)
+ return;
+ /* check if IT is empty */
+ for (afi = 0;
+ afi < AFI_MAX && rfg->rfapi_import_table->local_count[afi] == 0;
+ afi++);
+
+ if (afi == AFI_MAX)
+ {
+ vnc_zlog_debug_verbose ("%s: closing RFD for VRF %s",
+ __func__, rfg->name);
+ rfg->rfd = NULL;
+ rfapi_close(rfd);
+ }
+ else
+ {
+ vnc_zlog_debug_verbose ("%s: VRF %s afi=%d count=%d",
+ __func__, rfg->name, afi,
+ rfg->rfapi_import_table->local_count[afi]);
+ }
+}
+
+static int
+vnc_clear_vrf (struct vty *vty,
+ struct bgp *bgp,
+ const char *arg_vrf,
+ const char *arg_prefix, /* NULL = all */
+ const char *arg_rd) /* optional */
+{
+ struct rfapi_nve_group_cfg *rfg;
+ struct rfapi_local_reg_delete_arg cda;
+ int rc;
+ int start_count;
+
+ if (bgp == NULL)
+ bgp = bgp_get_default (); /* assume main instance for now */
+ if (!bgp)
+ {
+ vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (!bgp->rfapi || !bgp->rfapi_cfg)
+ {
+ vty_out (vty, "VRF support not configured%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ rfg = bgp_rfapi_cfg_match_byname (bgp, arg_vrf, RFAPI_GROUP_CFG_VRF);
+ /* arg checks */
+ if (!rfg)
+ {
+ vty_out (vty, "VRF \"%s\" appears not to be configured.%s",
+ arg_vrf, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ rc = parse_deleter_args (vty, bgp, arg_prefix, NULL, NULL, NULL, NULL,
+ arg_rd, rfg, &cda);
+ if (rc != CMD_SUCCESS) /* parse error */
+ return rc;
+
+ start_count = rfapi_cfg_group_it_count(rfg);
+ clear_vnc_prefix (&cda);
+ clear_vnc_vrf_closer (rfg);
+ vty_out (vty, "Cleared %u out of %d prefixes.%s",
+ cda.pfx_count, start_count, VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
+DEFUN (clear_vrf_prefix_rd,
+ clear_vrf_prefix_rd_cmd,
+ "clear vrf NAME [prefix <A.B.C.D/M|X:X::X:X/M>] [rd ASN:nn_or_IP-address]",
+ "Clear stored data\n"
+ "From a VRF\n"
+ "VRF name\n"
+ "Prefix related information\n"
+ "IPv4 prefix\n"
+ "IPv6 prefix\n"
+ "Specific VRF Route Distinguisher\n"
+ "<as-number>:<number> or <ip-address>:<number>\n")
+{
+ char *arg_vrf = argv[2]->arg;
+ char *arg_prefix = NULL; /* optional */
+ char *arg_rd = NULL; /* optional */
+ int pargc = 3;
+ argc--; /* don't check parameter */
+ while (pargc < argc)
+ {
+ switch (argv[pargc++]->arg[0])
+ {
+ case 'r':
+ arg_rd = argv[pargc]->arg;
+ break;
+ case 'p':
+ arg_prefix = argv[pargc]->arg;
+ break;
+ default:
+ break;
+ }
+ pargc ++;
+ }
+ return vnc_clear_vrf (vty, NULL, arg_vrf, arg_prefix, arg_rd);
+}
+
+DEFUN (clear_vrf_all,
+ clear_vrf_all_cmd,
+ "clear vrf NAME all",
+ "Clear stored data\n"
+ "From a VRF\n"
+ "VRF name\n"
+ "All prefixes\n")
+{
+ char *arg_vrf = argv[2]->arg;
+ return vnc_clear_vrf (vty, NULL, arg_vrf, NULL, NULL);
+}
+
void rfapi_vty_init ()
{
install_element (ENABLE_NODE, &add_vnc_prefix_cost_life_lnh_cmd);
@@ -4951,6 +5386,8 @@ void rfapi_vty_init ()
install_element (ENABLE_NODE, &add_vnc_mac_vni_life_cmd);
install_element (ENABLE_NODE, &add_vnc_mac_vni_cmd);
+ install_element (ENABLE_NODE, &add_vrf_prefix_rd_label_pref_cmd);
+
install_element (ENABLE_NODE, &clear_vnc_nve_all_cmd);
install_element (ENABLE_NODE, &clear_vnc_nve_vn_un_cmd);
install_element (ENABLE_NODE, &clear_vnc_nve_un_vn_cmd);
@@ -4975,6 +5412,9 @@ void rfapi_vty_init ()
install_element (ENABLE_NODE, &clear_vnc_mac_vn_prefix_cmd);
install_element (ENABLE_NODE, &clear_vnc_mac_all_prefix_cmd);
+ install_element (ENABLE_NODE, &clear_vrf_prefix_rd_cmd);
+ install_element (ENABLE_NODE, &clear_vrf_all_cmd);
+
install_element (ENABLE_NODE, &vnc_clear_counters_cmd);
install_element (VIEW_NODE, &vnc_show_summary_cmd);
diff --git a/configure.ac b/configure.ac
index 6ce5d0cc2c..550ac4f926 100755
--- a/configure.ac
+++ b/configure.ac
@@ -1459,6 +1459,7 @@ case "x${quagga_ac_bison_version}" in
x2.7*)
BISON_OPENBRACE='"'
BISON_CLOSEBRACE='"'
+ BISON_VERBOSE=''
AC_MSG_RESULT([$quagga_ac_bison_version - 2.7 or older])
;;
x2.*|x1.*)
@@ -1474,11 +1475,13 @@ case "x${quagga_ac_bison_version}" in
*)
BISON_OPENBRACE='{'
BISON_CLOSEBRACE='}'
+ BISON_VERBOSE='-Dparse.error=verbose'
AC_MSG_RESULT([$quagga_ac_bison_version - 3.0 or newer])
;;
esac
AC_SUBST(BISON_OPENBRACE)
AC_SUBST(BISON_CLOSEBRACE)
+AC_SUBST(BISON_VERBOSE)
if $quagga_ac_bison_missing; then
YACC="$SHELL $missing_dir/missing bison -y"
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 5dd38ee45a..ac1935d731 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -3,7 +3,7 @@
AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
AM_CFLAGS = $(WERROR)
DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
-AM_YFLAGS = -d -Dapi.prefix=@BISON_OPENBRACE@cmd_yy@BISON_CLOSEBRACE@
+AM_YFLAGS = -d -Dapi.prefix=@BISON_OPENBRACE@cmd_yy@BISON_CLOSEBRACE@ @BISON_VERBOSE@
command_lex.h: command_lex.c
@if test ! -f $@; then rm -f command_lex.c; else :; fi
@@ -26,6 +26,7 @@ libzebra_la_SOURCES = \
imsg-buffer.c imsg.c skiplist.c \
qobj.c wheel.c \
event_counter.c \
+ grammar_sandbox.c \
strlcpy.c \
strlcat.c
@@ -54,7 +55,7 @@ noinst_HEADERS = \
noinst_PROGRAMS = grammar_sandbox
-grammar_sandbox_SOURCES = grammar_sandbox.c
+grammar_sandbox_SOURCES = grammar_sandbox_main.c
grammar_sandbox_LDADD = libzebra.la
EXTRA_DIST = \
diff --git a/lib/command.c b/lib/command.c
index b5dae5f28e..9485beddd9 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -43,7 +43,10 @@
DEFINE_MTYPE( LIB, HOST, "Host config")
DEFINE_MTYPE( LIB, STRVEC, "String vector")
-DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc")
+DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens")
+DEFINE_MTYPE_STATIC(LIB, CMD_DESC, "Command Token Text")
+DEFINE_MTYPE_STATIC(LIB, CMD_TEXT, "Command Token Help")
+DEFINE_MTYPE( LIB, CMD_ARG, "Command Argument")
/* Command vector which includes some level of command lists. Normally
each daemon maintains each own cmdvec. */
@@ -523,7 +526,7 @@ compare_completions (const void *fst, const void *snd)
* @param completions linked list of cmd_token
* @return deduplicated and sorted vector with
*/
-static vector
+vector
completions_to_vec (struct list *completions)
{
vector comps = vector_init (VECTOR_MIN_SIZE);
@@ -745,6 +748,7 @@ node_parent ( enum node_type node )
case BGP_VPNV6_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VRF_POLICY_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@@ -1110,6 +1114,7 @@ cmd_exit (struct vty *vty)
case BGP_VPNV6_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VRF_POLICY_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@@ -1173,6 +1178,7 @@ DEFUN (config_end,
case BGP_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VRF_POLICY_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@@ -1272,7 +1278,7 @@ permute (struct graph_node *start, struct vty *vty)
for (ALL_LIST_ELEMENTS_RO (position,ln,gnn))
{
struct cmd_token *tt = gnn->data;
- if (tt->type < SELECTOR_TKN)
+ if (tt->type < SPECIAL_TKN)
vty_out (vty, " %s", tt->text);
}
if (gn == start)
@@ -2402,16 +2408,21 @@ cmd_init (int terminal)
vrf_install_commands ();
}
srandom(time(NULL));
+
+#ifdef DEV_BUILD
+ grammar_sandbox_init();
+#endif
}
struct cmd_token *
-new_cmd_token (enum cmd_token_type type, u_char attr, char *text, char *desc)
+new_cmd_token (enum cmd_token_type type, u_char attr,
+ const char *text, const char *desc)
{
struct cmd_token *token = XCALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_token));
token->type = type;
token->attr = attr;
- token->text = text;
- token->desc = desc;
+ token->text = text ? XSTRDUP (MTYPE_CMD_TEXT, text) : NULL;
+ token->desc = desc ? XSTRDUP (MTYPE_CMD_DESC, desc) : NULL;
token->arg = NULL;
token->allowrepeat = false;
@@ -2424,11 +2435,11 @@ del_cmd_token (struct cmd_token *token)
if (!token) return;
if (token->text)
- XFREE (MTYPE_CMD_TOKENS, token->text);
+ XFREE (MTYPE_CMD_TEXT, token->text);
if (token->desc)
- XFREE (MTYPE_CMD_TOKENS, token->desc);
+ XFREE (MTYPE_CMD_DESC, token->desc);
if (token->arg)
- XFREE (MTYPE_CMD_TOKENS, token->arg);
+ XFREE (MTYPE_CMD_ARG, token->arg);
XFREE (MTYPE_CMD_TOKENS, token);
}
@@ -2439,9 +2450,9 @@ copy_cmd_token (struct cmd_token *token)
struct cmd_token *copy = new_cmd_token (token->type, token->attr, NULL, NULL);
copy->max = token->max;
copy->min = token->min;
- copy->text = token->text ? XSTRDUP (MTYPE_CMD_TOKENS, token->text) : NULL;
- copy->desc = token->desc ? XSTRDUP (MTYPE_CMD_TOKENS, token->desc) : NULL;
- copy->arg = token->arg ? XSTRDUP (MTYPE_CMD_TOKENS, token->arg) : NULL;
+ copy->text = token->text ? XSTRDUP (MTYPE_CMD_TEXT, token->text) : NULL;
+ copy->desc = token->desc ? XSTRDUP (MTYPE_CMD_DESC, token->desc) : NULL;
+ copy->arg = token->arg ? XSTRDUP (MTYPE_CMD_ARG, token->arg) : NULL;
return copy;
}
diff --git a/lib/command.h b/lib/command.h
index 1e1698fc7d..3c3c3ae370 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -31,6 +31,7 @@
#include "hash.h"
DECLARE_MTYPE(HOST)
+DECLARE_MTYPE(CMD_ARG)
/* for test-commands.c */
DECLARE_MTYPE(STRVEC)
@@ -99,6 +100,7 @@ enum node_type
BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */
BGP_ENCAP_NODE, /* BGP ENCAP SAFI */
BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */
+ BGP_VRF_POLICY_NODE, /* BGP VRF policy */
BGP_VNC_DEFAULTS_NODE, /* BGP VNC nve defaults */
BGP_VNC_NVE_GROUP_NODE, /* BGP VNC nve group */
BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */
@@ -176,11 +178,12 @@ enum cmd_token_type
IPV6_PREFIX_TKN, // IPV6 network prefixes
/* plumbing types */
- SELECTOR_TKN, // marks beginning of selector
- OPTION_TKN, // marks beginning of option
- NUL_TKN, // dummy token
+ FORK_TKN, // marks subgraph beginning
+ JOIN_TKN, // marks subgraph end
START_TKN, // first token in line
END_TKN, // last token in line
+
+ SPECIAL_TKN = FORK_TKN,
};
/* Command attributes */
@@ -202,6 +205,8 @@ struct cmd_token
char *desc; // token description
long long min, max; // for ranges
char *arg; // user input that matches this token
+
+ struct graph_node *forkjoin; // paired FORK/JOIN for JOIN/FORK
};
/* Structure of command element. */
@@ -419,14 +424,16 @@ extern void cmd_terminate (void);
extern void cmd_exit (struct vty *vty);
extern int cmd_list_cmds (struct vty *vty, int do_permute);
+/* NOT safe for general use; call this only if DEV_BUILD! */
+extern void grammar_sandbox_init (void);
+
/* memory management for cmd_token */
-struct cmd_token *
-new_cmd_token (enum cmd_token_type, u_char attr, char *, char *);
-void
-del_cmd_token (struct cmd_token *);
-struct cmd_token *
-copy_cmd_token (struct cmd_token *);
+extern struct cmd_token *new_cmd_token (enum cmd_token_type, u_char attr,
+ const char *text, const char *desc);
+extern void del_cmd_token (struct cmd_token *);
+extern struct cmd_token *copy_cmd_token (struct cmd_token *);
+extern vector completions_to_vec (struct list *completions);
extern void command_parse_format (struct graph *graph, struct cmd_element *cmd);
/* Export typical functions. */
diff --git a/lib/command_lex.l b/lib/command_lex.l
index d767926263..2a241abbec 100644
--- a/lib/command_lex.l
+++ b/lib/command_lex.l
@@ -24,6 +24,12 @@
%{
#include "command_parse.h"
+
+#define YY_USER_ACTION yylloc->last_column += yyleng;
+#define LOC_STEP do { if (yylloc) { \
+ yylloc->first_column = yylloc->last_column; \
+ yylloc->first_line = yylloc->last_line; \
+ } } while(0)
%}
WORD (\-|\+)?[a-z0-9\*][-+_a-zA-Z0-9\*]*
@@ -45,9 +51,14 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
%option prefix="cmd_yy"
%option reentrant
%option bison-bridge
+%option bison-locations
%%
-[ /t] /* ignore whitespace */;
+%{
+ LOC_STEP;
+%}
+
+[ \t]+ LOC_STEP /* ignore whitespace */;
{WORD} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return WORD;}
{IPV4} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4;}
{IPV4_PREFIX} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4_PREFIX;}
diff --git a/lib/command_match.c b/lib/command_match.c
index d228563240..bbd9cd091d 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -27,7 +27,6 @@
#include "command_match.h"
#include "memory.h"
-DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens")
DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack")
#define MAXDEPTH 64
@@ -322,7 +321,7 @@ command_match_r (struct graph_node *start, vector vline, unsigned int n,
// copy token, set arg and prepend to currbest
struct cmd_token *token = start->data;
struct cmd_token *copy = copy_cmd_token (token);
- copy->arg = XSTRDUP (MTYPE_CMD_TOKENS, input_token);
+ copy->arg = XSTRDUP (MTYPE_CMD_ARG, input_token);
listnode_add_before (currbest, currbest->head, copy);
matcher_rv = MATCHER_OK;
}
@@ -459,7 +458,7 @@ command_complete (struct graph *graph,
/**
* Adds all children that are reachable by one parser hop to the given list.
- * NUL_TKN, SELECTOR_TKN, and OPTION_TKN nodes are treated as transparent.
+ * special tokens except END_TKN are treated as transparent.
*
* @param[in] list to add the nexthops to
* @param[in] node to start calculating nexthops from
@@ -490,26 +489,24 @@ add_nexthops (struct list *list, struct graph_node *node,
if (j != stackpos)
continue;
}
- switch (token->type)
+ if (token->type >= SPECIAL_TKN && token->type != END_TKN)
{
- case OPTION_TKN:
- case SELECTOR_TKN:
- case NUL_TKN:
- added += add_nexthops (list, child, stack, stackpos);
- break;
- default:
- if (stack)
- {
- nextstack = XMALLOC (MTYPE_CMD_MATCHSTACK,
- (stackpos + 1) * sizeof(struct graph_node *));
- nextstack[0] = child;
- memcpy(nextstack + 1, stack, stackpos * sizeof(struct graph_node *));
+ added += add_nexthops (list, child, stack, stackpos);
+ }
+ else
+ {
+ if (stack)
+ {
+ nextstack = XMALLOC (MTYPE_CMD_MATCHSTACK,
+ (stackpos + 1) * sizeof(struct graph_node *));
+ nextstack[0] = child;
+ memcpy(nextstack + 1, stack, stackpos * sizeof(struct graph_node *));
- listnode_add (list, nextstack);
- }
- else
- listnode_add (list, child);
- added++;
+ listnode_add (list, nextstack);
+ }
+ else
+ listnode_add (list, child);
+ added++;
}
}
diff --git a/lib/command_parse.y b/lib/command_parse.y
index c920e11380..e9d36ca41c 100644
--- a/lib/command_parse.y
+++ b/lib/command_parse.y
@@ -27,6 +27,8 @@
#define YYDEBUG 1
%}
+%locations
+/* define parse.error verbose */
%define api.pure full
/* define api.prefix {cmd_yy} */
@@ -49,14 +51,20 @@
#include "graph.h"
#define YYSTYPE CMD_YYSTYPE
+ #define YYLTYPE CMD_YYLTYPE
struct parser_ctx;
+
+ /* subgraph semantic value */
+ struct subgraph {
+ struct graph_node *start, *end;
+ };
}
%union {
long long number;
char *string;
struct graph_node *node;
- struct subgraph *subgraph;
+ struct subgraph subgraph;
}
%code provides {
@@ -94,28 +102,19 @@
%type <node> literal_token
%type <node> placeholder_token
%type <node> simple_token
-%type <subgraph> option
-%type <subgraph> option_token
-%type <subgraph> option_token_seq
%type <subgraph> selector
%type <subgraph> selector_token
%type <subgraph> selector_token_seq
%type <subgraph> selector_seq_seq
-%type <subgraph> compound_token
%code {
/* bison declarations */
void
- cmd_yyerror (struct parser_ctx *ctx, char const *msg);
-
- /* subgraph semantic value */
- struct subgraph {
- struct graph_node *start, *end;
- };
+ cmd_yyerror (CMD_YYLTYPE *locp, struct parser_ctx *ctx, char const *msg);
/* helper functions for parser */
- static char *
+ static const char *
doc_next (struct parser_ctx *ctx);
static struct graph_node *
@@ -130,11 +129,11 @@
static struct graph_node *
new_token_node (struct parser_ctx *,
enum cmd_token_type type,
- char *text,
- char *doc);
+ const char *text,
+ const char *doc);
static void
- terminate_graph (struct parser_ctx *ctx,
+ terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx,
struct graph_node *);
static void
@@ -173,7 +172,7 @@ start:
cmd_token_seq
{
// tack on the command element
- terminate_graph (ctx, ctx->currnode);
+ terminate_graph (&@1, ctx, ctx->currnode);
}
| cmd_token_seq placeholder_token '.' '.' '.'
{
@@ -187,7 +186,7 @@ start:
add_edge_dedup (ctx->currnode, ctx->currnode);
// tack on the command element
- terminate_graph (ctx, ctx->currnode);
+ terminate_graph (&@1, ctx, ctx->currnode);
}
;
@@ -202,11 +201,10 @@ cmd_token:
if ((ctx->currnode = add_edge_dedup (ctx->currnode, $1)) != $1)
graph_delete_node (ctx->graph, $1);
}
-| compound_token
+| selector
{
- graph_add_edge (ctx->currnode, $1->start);
- ctx->currnode = $1->end;
- free ($1);
+ graph_add_edge (ctx->currnode, $1.start);
+ ctx->currnode = $1.end;
}
;
@@ -215,14 +213,9 @@ simple_token:
| placeholder_token
;
-compound_token:
- selector
-| option
-;
-
literal_token: WORD
{
- $$ = new_token_node (ctx, WORD_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, WORD_TKN, $1, doc_next(ctx));
free ($1);
}
;
@@ -230,32 +223,32 @@ literal_token: WORD
placeholder_token:
IPV4
{
- $$ = new_token_node (ctx, IPV4_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, IPV4_TKN, $1, doc_next(ctx));
free ($1);
}
| IPV4_PREFIX
{
- $$ = new_token_node (ctx, IPV4_PREFIX_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, IPV4_PREFIX_TKN, $1, doc_next(ctx));
free ($1);
}
| IPV6
{
- $$ = new_token_node (ctx, IPV6_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, IPV6_TKN, $1, doc_next(ctx));
free ($1);
}
| IPV6_PREFIX
{
- $$ = new_token_node (ctx, IPV6_PREFIX_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, IPV6_PREFIX_TKN, $1, doc_next(ctx));
free ($1);
}
| VARIABLE
{
- $$ = new_token_node (ctx, VARIABLE_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, VARIABLE_TKN, $1, doc_next(ctx));
free ($1);
}
| RANGE
{
- $$ = new_token_node (ctx, RANGE_TKN, strdup($1), doc_next(ctx));
+ $$ = new_token_node (ctx, RANGE_TKN, $1, doc_next(ctx));
struct cmd_token *token = $$->data;
// get the numbers out
@@ -265,7 +258,7 @@ placeholder_token:
token->max = strtoll (yylval.string, &yylval.string, 10);
// validate range
- if (token->min > token->max) cmd_yyerror (ctx, "Invalid range.");
+ if (token->min > token->max) cmd_yyerror (&@1, ctx, "Invalid range.");
free ($1);
}
@@ -273,141 +266,66 @@ placeholder_token:
/* <selector|set> productions */
selector: '<' selector_seq_seq '>'
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = new_token_node (ctx, SELECTOR_TKN, NULL, NULL);
- $$->end = new_token_node (ctx, NUL_TKN, NULL, NULL);
- for (unsigned int i = 0; i < vector_active ($2->start->to); i++)
- {
- struct graph_node *sn = vector_slot ($2->start->to, i),
- *en = vector_slot ($2->end->from, i);
- graph_add_edge ($$->start, sn);
- graph_add_edge (en, $$->end);
- }
- graph_delete_node (ctx->graph, $2->start);
- graph_delete_node (ctx->graph, $2->end);
- free ($2);
+ $$ = $2;
};
selector_seq_seq:
selector_seq_seq '|' selector_token_seq
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = graph_new_node (ctx->graph, NULL, NULL);
- $$->end = graph_new_node (ctx->graph, NULL, NULL);
-
- // link in last sequence
- graph_add_edge ($$->start, $3->start);
- graph_add_edge ($3->end, $$->end);
-
- for (unsigned int i = 0; i < vector_active ($1->start->to); i++)
- {
- struct graph_node *sn = vector_slot ($1->start->to, i),
- *en = vector_slot ($1->end->from, i);
- graph_add_edge ($$->start, sn);
- graph_add_edge (en, $$->end);
- }
- graph_delete_node (ctx->graph, $1->start);
- graph_delete_node (ctx->graph, $1->end);
- free ($1);
- free ($3);
+ $$ = $1;
+ graph_add_edge ($$.start, $3.start);
+ graph_add_edge ($3.end, $$.end);
}
-| selector_token_seq '|' selector_token_seq
+| selector_token_seq
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = graph_new_node (ctx->graph, NULL, NULL);
- $$->end = graph_new_node (ctx->graph, NULL, NULL);
- graph_add_edge ($$->start, $1->start);
- graph_add_edge ($1->end, $$->end);
- graph_add_edge ($$->start, $3->start);
- graph_add_edge ($3->end, $$->end);
- free ($1);
- free ($3);
+ $$.start = new_token_node (ctx, FORK_TKN, NULL, NULL);
+ $$.end = new_token_node (ctx, JOIN_TKN, NULL, NULL);
+ ((struct cmd_token *)$$.start->data)->forkjoin = $$.end;
+ ((struct cmd_token *)$$.end->data)->forkjoin = $$.start;
+
+ graph_add_edge ($$.start, $1.start);
+ graph_add_edge ($1.end, $$.end);
}
;
/* {keyword} productions */
selector: '{' selector_seq_seq '}'
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = new_token_node (ctx, SELECTOR_TKN, NULL, NULL);
- $$->end = new_token_node (ctx, NUL_TKN, NULL, NULL);
- graph_add_edge ($$->start, $$->end);
- for (unsigned int i = 0; i < vector_active ($2->start->to); i++)
- {
- struct graph_node *sn = vector_slot ($2->start->to, i),
- *en = vector_slot ($2->end->from, i);
- graph_add_edge ($$->start, sn);
- graph_add_edge (en, $$->start);
- }
- graph_delete_node (ctx->graph, $2->start);
- graph_delete_node (ctx->graph, $2->end);
- free ($2);
+ $$ = $2;
+ graph_add_edge ($$.end, $$.start);
+ /* there is intentionally no start->end link, for two reasons:
+ * 1) this allows "at least 1 of" semantics, which are otherwise impossible
+ * 2) this would add a start->end->start loop in the graph that the current
+ * loop-avoidal fails to handle
+ * just use [{a|b}] if neccessary, that will work perfectly fine, and reason
+ * #1 is good enough to keep it this way. */
};
-selector_token_seq:
- simple_token
-{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = $$->end = $1;
-}
-| selector_token_seq selector_token
-{
- $$ = malloc (sizeof (struct subgraph));
- graph_add_edge ($1->end, $2->start);
- $$->start = $1->start;
- $$->end = $2->end;
- free ($1);
- free ($2);
-}
-;
-
selector_token:
simple_token
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = $$->end = $1;
+ $$.start = $$.end = $1;
}
-| option
| selector
;
-/* [option] productions */
-option: '[' option_token_seq ']'
+selector_token_seq:
+ selector_token_seq selector_token
{
- // make a new option
- $$ = malloc (sizeof (struct subgraph));
- $$->start = new_token_node (ctx, OPTION_TKN, NULL, NULL);
- $$->end = new_token_node (ctx, NUL_TKN, NULL, NULL);
- // add a path through the sequence to the end
- graph_add_edge ($$->start, $2->start);
- graph_add_edge ($2->end, $$->end);
- // add a path directly from the start to the end
- graph_add_edge ($$->start, $$->end);
- free ($2);
+ graph_add_edge ($1.end, $2.start);
+ $$.start = $1.start;
+ $$.end = $2.end;
}
+| selector_token
;
-option_token_seq:
- option_token
-| option_token_seq option_token
-{
- $$ = malloc (sizeof (struct subgraph));
- graph_add_edge ($1->end, $2->start);
- $$->start = $1->start;
- $$->end = $2->end;
- free ($1);
- free ($2);
-}
-;
-
-option_token:
- simple_token
+/* [option] productions */
+selector: '[' selector_seq_seq ']'
{
- $$ = malloc (sizeof (struct subgraph));
- $$->start = $$->end = $1;
+ $$ = $2;
+ graph_add_edge ($$.start, $$.end);
}
-| compound_token
;
%%
@@ -437,11 +355,39 @@ command_parse_format (struct graph *graph, struct cmd_element *cmd)
/* parser helper functions */
void
-yyerror (struct parser_ctx *ctx, char const *msg)
+yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
{
+ char *tmpstr = strdup(ctx->el->string);
+ char *line, *eol;
+ char spacing[256];
+ int lineno = 0;
+
zlog_err ("%s: FATAL parse error: %s", __func__, msg);
- zlog_err ("while parsing this command definition: \n\t%s\n", ctx->el->string);
- //exit(EXIT_FAILURE);
+ zlog_err ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
+
+ line = tmpstr;
+ do {
+ lineno++;
+ eol = strchr(line, '\n');
+ if (eol)
+ *eol++ = '\0';
+
+ zlog_err ("%s: | %s", __func__, line);
+ if (lineno == loc->first_line && lineno == loc->last_line
+ && loc->first_column < (int)sizeof(spacing) - 1
+ && loc->last_column < (int)sizeof(spacing) - 1) {
+
+ int len = loc->last_column - loc->first_column;
+ if (len == 0)
+ len = 1;
+
+ memset(spacing, ' ', loc->first_column - 1);
+ memset(spacing + loc->first_column - 1, '^', len);
+ spacing[loc->first_column - 1 + len] = '\0';
+ zlog_err ("%s: | %s", __func__, spacing);
+ }
+ } while ((line = eol));
+ free(tmpstr);
}
static void
@@ -456,27 +402,25 @@ cleanup (struct parser_ctx *ctx)
}
static void
-terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode)
+terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx,
+ struct graph_node *finalnode)
{
// end of graph should look like this
// * -> finalnode -> END_TKN -> cmd_element
struct cmd_element *element = ctx->el;
struct graph_node *end_token_node =
- new_token_node (ctx,
- END_TKN,
- strdup (CMD_CR_TEXT),
- strdup (""));
+ new_token_node (ctx, END_TKN, CMD_CR_TEXT, "");
struct graph_node *end_element_node =
graph_new_node (ctx->graph, element, NULL);
if (node_adjacent (finalnode, end_token_node))
- cmd_yyerror (ctx, "Duplicate command.");
+ cmd_yyerror (locp, ctx, "Duplicate command.");
graph_add_edge (finalnode, end_token_node);
graph_add_edge (end_token_node, end_element_node);
}
-static char *
+static const char *
doc_next (struct parser_ctx *ctx)
{
const char *piece = ctx->docstr ? strsep (&ctx->docstr, "\n") : "";
@@ -486,12 +430,12 @@ doc_next (struct parser_ctx *ctx)
piece = "";
}
- return strdup (piece);
+ return piece;
}
static struct graph_node *
new_token_node (struct parser_ctx *ctx, enum cmd_token_type type,
- char *text, char *doc)
+ const char *text, const char *doc)
{
struct cmd_token *token = new_cmd_token (type, ctx->el->attr, text, doc);
return graph_new_node (ctx->graph, token, (void (*)(void *)) &del_cmd_token);
@@ -575,8 +519,7 @@ cmp_token (struct cmd_token *first, struct cmd_token *second)
* cases; ultimately this forks the graph, but the matcher can handle
* this regardless
*/
- case SELECTOR_TKN:
- case OPTION_TKN:
+ case FORK_TKN:
return 0;
/* end nodes are always considered equal, since each node may only
@@ -584,7 +527,7 @@ cmp_token (struct cmd_token *first, struct cmd_token *second)
*/
case START_TKN:
case END_TKN:
- case NUL_TKN:
+ case JOIN_TKN:
default:
break;
}
diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c
index 0239ca44ac..315bd4d59c 100644
--- a/lib/grammar_sandbox.c
+++ b/lib/grammar_sandbox.c
@@ -3,11 +3,6 @@
*
* This unit defines a number of commands in the old engine that can
* be used to test and interact with the new engine.
- *
- * This shim should be removed upon integration. It is currently hooked in
- * vtysh/vtysh.c. It has no header, vtysh.c merely includes this entire unit
- * since it clutters up the makefiles less and this is only a temporary shim.
- *
* --
* Copyright (C) 2016 Cumulus Networks, Inc.
*
@@ -45,15 +40,15 @@ void
grammar_sandbox_init (void);
void
pretty_print_graph (struct vty *vty, struct graph_node *, int, int, struct graph_node **, size_t);
+static void
+pretty_print_dot (FILE *ofd, unsigned opts, struct graph_node *start,
+ struct graph_node **stack, size_t stackpos,
+ struct graph_node **visited, size_t *visitpos);
void
init_cmdgraph (struct vty *, struct graph **);
-vector
-completions_to_vec (struct list *);
-int
-compare_completions (const void *, const void *);
/** shim interface commands **/
-struct graph *nodegraph;
+struct graph *nodegraph = NULL, *nodegraph_free = NULL;
DEFUN (grammar_test,
grammar_test_cmd,
@@ -240,17 +235,77 @@ DEFUN (grammar_test_show,
return CMD_SUCCESS;
}
+DEFUN (grammar_test_dot,
+ grammar_test_dot_cmd,
+ "grammar dotfile OUTNAME",
+ GRAMMAR_STR
+ "print current graph for dot\n"
+ ".dot filename\n")
+{
+ struct graph_node *stack[MAXDEPTH];
+ struct graph_node *visited[MAXDEPTH*MAXDEPTH];
+ size_t vpos = 0;
+
+ if (!nodegraph) {
+ vty_out(vty, "nodegraph uninitialized\r\n");
+ return CMD_SUCCESS;
+ }
+ FILE *ofd = fopen(argv[2]->arg, "w");
+ if (!ofd) {
+ vty_out(vty, "%s: %s\r\n", argv[2]->arg, strerror(errno));
+ return CMD_SUCCESS;
+ }
+
+ fprintf(ofd, "digraph {\n graph [ rankdir = LR ];\n node [ fontname = \"Fira Mono\", fontsize = 9 ];\n\n");
+ pretty_print_dot (ofd, 0,
+ vector_slot (nodegraph->nodes, 0),
+ stack, 0, visited, &vpos);
+ fprintf(ofd, "}\n");
+ fclose(ofd);
+ return CMD_SUCCESS;
+}
+
DEFUN (grammar_init_graph,
grammar_init_graph_cmd,
"grammar init",
GRAMMAR_STR
"(re)initialize graph\n")
{
- graph_delete_graph (nodegraph);
+ if (nodegraph_free)
+ graph_delete_graph (nodegraph_free);
+ nodegraph_free = NULL;
+
init_cmdgraph (vty, &nodegraph);
return CMD_SUCCESS;
}
+extern vector cmdvec;
+
+DEFUN (grammar_access,
+ grammar_access_cmd,
+ "grammar access (0-65535)",
+ GRAMMAR_STR
+ "access node graph\n"
+ "node number\n")
+{
+ if (nodegraph_free)
+ graph_delete_graph (nodegraph_free);
+ nodegraph_free = NULL;
+
+ struct cmd_node *cnode;
+
+ cnode = vector_slot (cmdvec, atoi (argv[2]->arg));
+ if (!cnode)
+ {
+ vty_out (vty, "%% no such node%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty_out (vty, "node %d%s", (int)cnode->node, VTY_NEWLINE);
+ nodegraph = cnode->cmdgraph;
+ return CMD_SUCCESS;
+}
+
/* this is called in vtysh.c to set up the testing shim */
void grammar_sandbox_init(void) {
init_cmdgraph (NULL, &nodegraph);
@@ -258,10 +313,12 @@ void grammar_sandbox_init(void) {
// install all enable elements
install_element (ENABLE_NODE, &grammar_test_cmd);
install_element (ENABLE_NODE, &grammar_test_show_cmd);
+ install_element (ENABLE_NODE, &grammar_test_dot_cmd);
install_element (ENABLE_NODE, &grammar_test_match_cmd);
install_element (ENABLE_NODE, &grammar_test_complete_cmd);
install_element (ENABLE_NODE, &grammar_test_doc_cmd);
install_element (ENABLE_NODE, &grammar_init_graph_cmd);
+ install_element (ENABLE_NODE, &grammar_access_cmd);
}
#define item(x) { x, #x }
@@ -275,9 +332,8 @@ struct message tokennames[] = {
item(IPV6_PREFIX_TKN), // IPV6 network prefixes
/* plumbing types */
- item(SELECTOR_TKN), // marks beginning of selector
- item(OPTION_TKN), // marks beginning of option
- item(NUL_TKN), // dummy token
+ item(FORK_TKN),
+ item(JOIN_TKN),
item(START_TKN), // first token in line
item(END_TKN), // last token in line
{ 0, NULL }
@@ -292,7 +348,7 @@ size_t tokennames_max = array_size(tokennames);
*/
void
pretty_print_graph (struct vty *vty, struct graph_node *start, int level,
- int desc, struct graph_node **stack, size_t stackpos)
+ int desc, struct graph_node **stack, size_t stackpos)
{
// print this node
char tokennum[32];
@@ -346,92 +402,92 @@ pretty_print_graph (struct vty *vty, struct graph_node *start, int level,
vty_out(vty, "%s", VTY_NEWLINE);
}
-/** stuff that should go in command.c + command.h */
-void
-init_cmdgraph (struct vty *vty, struct graph **graph)
-{
- // initialize graph, add start noe
- *graph = graph_new ();
- struct cmd_token *token = new_cmd_token (START_TKN, 0, NULL, NULL);
- graph_new_node (*graph, token, (void (*)(void *)) &del_cmd_token);
- if (vty)
- vty_out (vty, "initialized graph%s", VTY_NEWLINE);
-}
-
-int
-compare_completions (const void *fst, const void *snd)
+static void
+pretty_print_dot (FILE *ofd, unsigned opts, struct graph_node *start,
+ struct graph_node **stack, size_t stackpos,
+ struct graph_node **visited, size_t *visitpos)
{
- struct cmd_token *first = *(struct cmd_token **) fst,
- *secnd = *(struct cmd_token **) snd;
- return strcmp (first->text, secnd->text);
-}
+ // print this node
+ char tokennum[32];
+ struct cmd_token *tok = start->data;
+ const char *color;
-vector
-completions_to_vec (struct list *completions)
-{
- vector comps = vector_init (VECTOR_MIN_SIZE);
-
- struct listnode *ln;
- struct cmd_token *token;
- unsigned int i, exists;
- for (ALL_LIST_ELEMENTS_RO(completions,ln,token))
- {
- // linear search for token in completions vector
- exists = 0;
- for (i = 0; i < vector_active (comps) && !exists; i++)
- {
- struct cmd_token *curr = vector_slot (comps, i);
- exists = !strcmp (curr->text, token->text) &&
- !strcmp (curr->desc, token->desc);
- }
+ for (size_t i = 0; i < (*visitpos); i++)
+ if (visited[i] == start)
+ return;
+ visited[(*visitpos)++] = start;
+ if ((*visitpos) == MAXDEPTH*MAXDEPTH)
+ return;
- if (!exists)
- vector_set (comps, copy_cmd_token (token));
+ snprintf(tokennum, sizeof(tokennum), "%d?", tok->type);
+ fprintf(ofd, " n%016llx [ shape=box, label=<", (unsigned long long)start);
+
+ fprintf(ofd, "<b>%s</b>", LOOKUP_DEF(tokennames, tok->type, tokennum));
+ if (tok->attr == CMD_ATTR_DEPRECATED)
+ fprintf(ofd, " (d)");
+ else if (tok->attr == CMD_ATTR_HIDDEN)
+ fprintf(ofd, " (h)");
+ if (tok->text) {
+ if (tok->type == WORD_TKN)
+ fprintf(ofd, "<br/>\"<font color=\"#0055ff\" point-size=\"11\"><b>%s</b></font>\"", tok->text);
+ else
+ fprintf(ofd, "<br/>%s", tok->text);
}
+/* if (desc)
+ fprintf(ofd, " ?'%s'", tok->desc); */
+ switch (tok->type) {
+ case START_TKN: color = "#ccffcc"; break;
+ case FORK_TKN: color = "#aaddff"; break;
+ case JOIN_TKN: color = "#ddaaff"; break;
+ case WORD_TKN: color = "#ffffff"; break;
+ default: color = "#ffffff"; break;
+ }
+ fprintf(ofd, ">, style = filled, fillcolor = \"%s\" ];\n", color);
- // sort completions
- qsort (comps->index,
- vector_active (comps),
- sizeof (void *),
- &compare_completions);
-
- return comps;
-}
+ if (stackpos == MAXDEPTH)
+ return;
+ stack[stackpos++] = start;
-static void vty_do_exit(void)
-{
- printf ("\nend.\n");
- exit (0);
+ for (unsigned int i = 0; i < vector_active (start->to); i++)
+ {
+ struct graph_node *adj = vector_slot (start->to, i);
+ // if this node is a vararg, just print *
+ if (adj == start) {
+ fprintf(ofd, " n%016llx -> n%016llx;\n",
+ (unsigned long long)start,
+ (unsigned long long)start);
+ } else if (((struct cmd_token *)adj->data)->type == END_TKN) {
+ //struct cmd_token *et = adj->data;
+ fprintf(ofd, " n%016llx -> end%016llx;\n",
+ (unsigned long long)start,
+ (unsigned long long)adj);
+ fprintf(ofd, " end%016llx [ shape=box, label=<end>, style = filled, fillcolor = \"#ffddaa\" ];\n",
+ (unsigned long long)adj);
+ } else {
+ fprintf(ofd, " n%016llx -> n%016llx;\n",
+ (unsigned long long)start,
+ (unsigned long long)adj);
+ size_t k;
+ for (k = 0; k < stackpos; k++)
+ if (stack[k] == adj)
+ break;
+ if (k == stackpos) {
+ pretty_print_dot (ofd, opts, adj, stack, stackpos, visited, visitpos);
+ }
+ }
+ }
}
-struct thread_master *master;
-int main(int argc, char **argv)
+/** stuff that should go in command.c + command.h */
+void
+init_cmdgraph (struct vty *vty, struct graph **graph)
{
- struct thread thread;
-
- master = thread_master_create ();
-
- zlog_default = openzlog ("grammar_sandbox", ZLOG_NONE, 0,
- LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
- zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
- zlog_set_level (NULL, ZLOG_DEST_STDOUT, LOG_DEBUG);
- zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
-
- /* Library inits. */
- cmd_init (1);
- host.name = strdup ("test");
-
- vty_init (master);
- memory_init ();
- grammar_sandbox_init();
-
- vty_stdio (vty_do_exit);
-
- /* Fetch next active thread. */
- while (thread_fetch (master, &thread))
- thread_call (&thread);
-
- /* Not reached. */
- exit (0);
+ // initialize graph, add start noe
+ *graph = graph_new ();
+ nodegraph_free = *graph;
+ struct cmd_token *token = new_cmd_token (START_TKN, 0, NULL, NULL);
+ graph_new_node (*graph, token, (void (*)(void *)) &del_cmd_token);
+ if (vty)
+ vty_out (vty, "initialized graph%s", VTY_NEWLINE);
}
diff --git a/lib/grammar_sandbox.h b/lib/grammar_sandbox.h
deleted file mode 100644
index 5da0b05d09..0000000000
--- a/lib/grammar_sandbox.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef _GRAMMAR_SANDBOX_H
-#define _GRAMMAR_SANDBOX_H
-
-/**
- * Houses functionality for testing shim as well as code that should go into
- * command.h and command.c during integration.
- */
-#include "memory.h"
-
-#define CMD_CR_TEXT "<cr>"
-
-void
-grammar_sandbox_init (void);
-
-/**
- * Types for tokens.
- *
- * The type determines what kind of data the token can match (in the
- * matching use case) or hold (in the argv use case).
- */
-enum cmd_token_type_t
-{
- WORD_TKN, // words
- NUMBER_TKN, // integral numbers
- VARIABLE_TKN, // almost anything
- RANGE_TKN, // integer range
- IPV4_TKN, // IPV4 addresses
- IPV4_PREFIX_TKN, // IPV4 network prefixes
- IPV6_TKN, // IPV6 prefixes
- IPV6_PREFIX_TKN, // IPV6 network prefixes
-
- /* plumbing types */
- SELECTOR_TKN, // marks beginning of selector
- OPTION_TKN, // marks beginning of option
- NUL_TKN, // dummy token
- START_TKN, // first token in line
- END_TKN, // last token in line
-};
-
-/**
- * Token struct.
- */
-struct cmd_token_t
-{
- enum cmd_token_type_t type; // token type
-
- char *text; // token text
- char *desc; // token description
-
- long long value; // for numeric types
- long long min, max; // for ranges
-
- char *arg; // user input that matches this token
-};
-
-#endif /* _GRAMMAR_SANDBOX_H */
diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c
new file mode 100644
index 0000000000..5deef406c1
--- /dev/null
+++ b/lib/grammar_sandbox_main.c
@@ -0,0 +1,64 @@
+/*
+ * Testing shim and API examples for the new CLI backend.
+ *
+ * Minimal main() to run grammar_sandbox standalone.
+ * [split off grammar_sandbox.c 2017-01-23]
+ * --
+ * Copyright (C) 2016 Cumulus Networks, Inc.
+ * Copyright (C) 2017 David Lamparter for NetDEF, Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR).
+ *
+ * FRR 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.
+ *
+ * FRR 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 FRR; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "command.h"
+#include "memory_vty.h"
+
+static void vty_do_exit(void)
+{
+ printf ("\nend.\n");
+ exit (0);
+}
+
+struct thread_master *master;
+
+int main(int argc, char **argv)
+{
+ struct thread thread;
+
+ master = thread_master_create ();
+
+ zlog_default = openzlog ("grammar_sandbox", ZLOG_NONE, 0,
+ LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
+ zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
+ zlog_set_level (NULL, ZLOG_DEST_STDOUT, LOG_DEBUG);
+ zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
+
+ /* Library inits. */
+ cmd_init (1);
+ host.name = strdup ("test");
+
+ vty_init (master);
+ memory_init ();
+
+ vty_stdio (vty_do_exit);
+
+ /* Fetch next active thread. */
+ while (thread_fetch (master, &thread))
+ thread_call (&thread);
+
+ /* Not reached. */
+ exit (0);
+}
diff --git a/lib/routemap.c b/lib/routemap.c
index 74bae1fd76..70f3069a36 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -710,6 +710,7 @@ enum route_map_dep_type
ROUTE_MAP_DEP_RMAP = 1,
ROUTE_MAP_DEP_CLIST,
ROUTE_MAP_DEP_ECLIST,
+ ROUTE_MAP_DEP_LCLIST,
ROUTE_MAP_DEP_PLIST,
ROUTE_MAP_DEP_ASPATH,
ROUTE_MAP_DEP_FILTER,
@@ -1819,6 +1820,7 @@ route_map_dep_update (struct hash *dephash, const char *dep_name,
case RMAP_EVENT_CLIST_ADDED:
case RMAP_EVENT_ECLIST_ADDED:
case RMAP_EVENT_ASLIST_ADDED:
+ case RMAP_EVENT_LLIST_ADDED:
case RMAP_EVENT_CALL_ADDED:
case RMAP_EVENT_FILTER_ADDED:
if (rmap_debug)
@@ -1840,6 +1842,7 @@ route_map_dep_update (struct hash *dephash, const char *dep_name,
case RMAP_EVENT_CLIST_DELETED:
case RMAP_EVENT_ECLIST_DELETED:
case RMAP_EVENT_ASLIST_DELETED:
+ case RMAP_EVENT_LLIST_DELETED:
case RMAP_EVENT_CALL_DELETED:
case RMAP_EVENT_FILTER_DELETED:
if (rmap_debug)
@@ -1902,6 +1905,10 @@ route_map_get_dep_hash (route_map_event_t event)
case RMAP_EVENT_ASLIST_DELETED:
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
break;
+ case RMAP_EVENT_LLIST_ADDED:
+ case RMAP_EVENT_LLIST_DELETED:
+ upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
+ break;
case RMAP_EVENT_CALL_ADDED:
case RMAP_EVENT_CALL_DELETED:
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
diff --git a/lib/routemap.h b/lib/routemap.h
index b52f7289b0..b378c64eae 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -84,6 +84,8 @@ typedef enum
RMAP_EVENT_CLIST_DELETED,
RMAP_EVENT_ECLIST_ADDED,
RMAP_EVENT_ECLIST_DELETED,
+ RMAP_EVENT_LLIST_ADDED,
+ RMAP_EVENT_LLIST_DELETED,
RMAP_EVENT_ASLIST_ADDED,
RMAP_EVENT_ASLIST_DELETED,
RMAP_EVENT_FILTER_ADDED,
diff --git a/lib/vty.c b/lib/vty.c
index a435706d1f..9413d003ef 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -742,6 +742,7 @@ vty_end_config (struct vty *vty)
case BGP_VPNV6_NODE:
case BGP_ENCAP_NODE:
case BGP_ENCAPV6_NODE:
+ case BGP_VRF_POLICY_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
diff --git a/lib/zclient.c b/lib/zclient.c
index a4c5fa4afb..42fa41c9c8 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1626,6 +1626,7 @@ zclient_read (struct thread *thread)
case ZEBRA_REDISTRIBUTE_IPV6_DEL:
if (zclient->redistribute_route_ipv6_del)
(*zclient->redistribute_route_ipv6_del) (command, zclient, length, vrf_id);
+ break;
case ZEBRA_INTERFACE_LINK_PARAMS:
if (zclient->interface_link_params)
(*zclient->interface_link_params) (command, zclient, length);
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 85baa4eafe..b8bb694b78 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -2578,7 +2578,8 @@ DEFUN (show_ip_pim_join,
SHOW_STR
IP_STR
PIM_STR
- "PIM interface join information\n")
+ "PIM interface join information\n"
+ JSON_STR)
{
u_char uj = use_json(argc, argv);
pim_show_join(vty, uj);
@@ -2592,7 +2593,8 @@ DEFUN (show_ip_pim_local_membership,
SHOW_STR
IP_STR
PIM_STR
- "PIM interface local-membership\n")
+ "PIM interface local-membership\n"
+ JSON_STR)
{
u_char uj = use_json(argc, argv);
pim_show_membership(vty, uj);
@@ -3134,7 +3136,8 @@ DEFUN (show_ip_mroute,
"show ip mroute [json]",
SHOW_STR
IP_STR
- MROUTE_STR)
+ MROUTE_STR
+ JSON_STR)
{
u_char uj = use_json(argc, argv);
show_mroute(vty, uj);
@@ -3443,7 +3446,8 @@ DEFUN (ip_pim_packets,
"ip pim packets <1-100>",
IP_STR
"pim multicast routing\n"
- "Number of packets to process at one time per fd\n")
+ "packets to process at one time per fd\n"
+ "Number of packets\n")
{
qpim_packet_process = atoi (argv[3]->arg);
return CMD_SUCCESS;
@@ -3455,7 +3459,8 @@ DEFUN (no_ip_pim_packets,
NO_STR
IP_STR
"pim multicast routing\n"
- "Number of packets to process at one time per fd\n")
+ "packets to process at one time per fd\n"
+ "Number of packets\n")
{
qpim_packet_process = PIM_DEFAULT_PACKET_PROCESS;
return CMD_SUCCESS;
@@ -3467,7 +3472,8 @@ DEFUN (ip_pim_rp,
IP_STR
"pim multicast routing\n"
"Rendevous Point\n"
- "ip address of RP\n")
+ "ip address of RP\n"
+ "Group Address range to cover\n")
{
int idx_ipv4 = 3;
return pim_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL);
@@ -3520,7 +3526,8 @@ DEFUN (no_ip_pim_rp,
IP_STR
"pim multicast routing\n"
"Rendevous Point\n"
- "ip address of RP\n")
+ "ip address of RP\n"
+ "Group Address range to cover\n")
{
int idx_ipv4 = 4;
return pim_no_rp_cmd_worker (vty, argv[idx_ipv4]->arg, argv[idx_ipv4 + 1]->arg, NULL);
@@ -4093,7 +4100,8 @@ DEFUN (interface_no_ip_igmp_query_max_response_time,
NO_STR
IP_STR
IFACE_IGMP_STR
- IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR)
+ IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR
+ "Time for response in deci-seconds\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct pim_interface *pim_ifp;
@@ -4823,22 +4831,9 @@ DEFUN (no_debug_pim_events,
return CMD_SUCCESS;
}
-
DEFUN (debug_pim_packets,
debug_pim_packets_cmd,
- "debug pim packets",
- DEBUG_STR
- DEBUG_PIM_STR
- DEBUG_PIM_PACKETS_STR)
-{
- PIM_DO_DEBUG_PIM_PACKETS;
- vty_out (vty, "PIM Packet debugging is on %s", VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-DEFUN (debug_pim_packets_filter,
- debug_pim_packets_filter_cmd,
- "debug pim packets <hello|joins|register>",
+ "debug pim packets [<hello|joins|register>]",
DEBUG_STR
DEBUG_PIM_STR
DEBUG_PIM_PACKETS_STR
@@ -4846,66 +4841,60 @@ DEFUN (debug_pim_packets_filter,
DEBUG_PIM_J_P_PACKETS_STR
DEBUG_PIM_PIM_REG_PACKETS_STR)
{
- int idx_hello_join = 3;
- if (strncmp(argv[idx_hello_join]->arg,"h",1) == 0)
+ int idx;
+ if (argv_find (argv, argc, "hello", &idx))
{
PIM_DO_DEBUG_PIM_HELLO;
vty_out (vty, "PIM Hello debugging is on%s", VTY_NEWLINE);
}
- else if (strncmp(argv[idx_hello_join]->arg,"j",1) == 0)
+ else if (argv_find (argv, argc ,"joins", &idx))
{
PIM_DO_DEBUG_PIM_J_P;
vty_out (vty, "PIM Join/Prune debugging is on%s", VTY_NEWLINE);
}
- else if (strncmp(argv[idx_hello_join]->arg,"r",1) == 0)
+ else if (argv_find (argv, argc, "register", &idx))
{
PIM_DO_DEBUG_PIM_REG;
vty_out (vty, "PIM Register debugging is on%s", VTY_NEWLINE);
}
+ else
+ {
+ PIM_DO_DEBUG_PIM_PACKETS;
+ vty_out (vty, "PIM Packet debugging is on %s", VTY_NEWLINE);
+ }
return CMD_SUCCESS;
}
DEFUN (no_debug_pim_packets,
no_debug_pim_packets_cmd,
- "no debug pim packets",
- NO_STR
- DEBUG_STR
- DEBUG_PIM_STR
- DEBUG_PIM_PACKETS_STR
- DEBUG_PIM_HELLO_PACKETS_STR
- DEBUG_PIM_J_P_PACKETS_STR)
-{
- PIM_DONT_DEBUG_PIM_PACKETS;
- vty_out (vty, "PIM Packet debugging is off %s", VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_debug_pim_packets_filter,
- no_debug_pim_packets_filter_cmd,
- "no debug pim packets <hello|joins|register>",
+ "no debug pim packets [<hello|joins|register>]",
NO_STR
DEBUG_STR
DEBUG_PIM_STR
DEBUG_PIM_PACKETS_STR
DEBUG_PIM_HELLO_PACKETS_STR
- DEBUG_PIM_J_P_PACKETS_STR)
+ DEBUG_PIM_J_P_PACKETS_STR
+ DEBUG_PIM_PIM_REG_PACKETS_STR)
{
- int idx_hello_join = 4;
- if (strncmp(argv[idx_hello_join]->arg,"h",1) == 0)
+ int idx = 0;
+ if (argv_find (argv, argc,"hello",&idx))
{
PIM_DONT_DEBUG_PIM_HELLO;
vty_out (vty, "PIM Hello debugging is off %s", VTY_NEWLINE);
}
- else if (strncmp(argv[idx_hello_join]->arg,"j",1) == 0)
+ else if (argv_find (argv, argc, "joins", &idx))
{
PIM_DONT_DEBUG_PIM_J_P;
vty_out (vty, "PIM Join/Prune debugging is off %s", VTY_NEWLINE);
}
- else if (strncmp (argv[idx_hello_join]->arg, "r", 1) == 0)
+ else if (argv_find (argv, argc, "register", &idx))
{
PIM_DONT_DEBUG_PIM_REG;
vty_out (vty, "PIM Register debugging is off%s", VTY_NEWLINE);
}
+ else
+ PIM_DONT_DEBUG_PIM_PACKETS;
+
return CMD_SUCCESS;
}
@@ -5459,6 +5448,7 @@ DEFUN (no_ip_msdp_mesh_group_source,
CFG_MSDP_STR
"Delete MSDP mesh-group source\n"
"mesh group name\n"
+ "mesh group source\n"
"mesh group local address\n")
{
if (argv[6]->arg)
@@ -5954,6 +5944,7 @@ DEFUN (show_ip_msdp_sa_sg,
MSDP_STR
"MSDP active-source information\n"
"source or group ip\n"
+ "group ip\n"
"JavaScript Object Notation\n")
{
u_char uj = use_json(argc, argv);
@@ -6074,9 +6065,7 @@ void pim_cmd_init()
install_element (ENABLE_NODE, &debug_pim_events_cmd);
install_element (ENABLE_NODE, &no_debug_pim_events_cmd);
install_element (ENABLE_NODE, &debug_pim_packets_cmd);
- install_element (ENABLE_NODE, &debug_pim_packets_filter_cmd);
install_element (ENABLE_NODE, &no_debug_pim_packets_cmd);
- install_element (ENABLE_NODE, &no_debug_pim_packets_filter_cmd);
install_element (ENABLE_NODE, &debug_pim_packetdump_send_cmd);
install_element (ENABLE_NODE, &no_debug_pim_packetdump_send_cmd);
install_element (ENABLE_NODE, &debug_pim_packetdump_recv_cmd);
@@ -6116,9 +6105,7 @@ void pim_cmd_init()
install_element (CONFIG_NODE, &debug_pim_events_cmd);
install_element (CONFIG_NODE, &no_debug_pim_events_cmd);
install_element (CONFIG_NODE, &debug_pim_packets_cmd);
- install_element (CONFIG_NODE, &debug_pim_packets_filter_cmd);
install_element (CONFIG_NODE, &no_debug_pim_packets_cmd);
- install_element (CONFIG_NODE, &no_debug_pim_packets_filter_cmd);
install_element (CONFIG_NODE, &debug_pim_trace_cmd);
install_element (CONFIG_NODE, &no_debug_pim_trace_cmd);
install_element (CONFIG_NODE, &debug_ssmpingd_cmd);
@@ -6134,8 +6121,6 @@ void pim_cmd_init()
install_element (CONFIG_NODE, &debug_msdp_packets_cmd);
install_element (CONFIG_NODE, &no_debug_msdp_packets_cmd);
install_element (CONFIG_NODE, &undebug_msdp_packets_cmd);
- install_element (CONFIG_NODE, &ip_msdp_peer_cmd);
- install_element (CONFIG_NODE, &no_ip_msdp_peer_cmd);
install_element (CONFIG_NODE, &ip_msdp_mesh_group_member_cmd);
install_element (CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd);
install_element (CONFIG_NODE, &ip_msdp_mesh_group_source_cmd);
diff --git a/tests/testcli.refout b/tests/testcli.refout
index 088cbdfec4..8b438baee2 100644
--- a/tests/testcli.refout
+++ b/tests/testcli.refout
@@ -188,15 +188,11 @@ test# pat c c x
% [NONE] Unknown command: pat c c x
test#
test# pat d
-cmd8 with 2 args.
-[00]: pat
-[01]: d
+% Command incomplete.
test# pat d
bar baz foo
test# pat d
-cmd8 with 2 args.
-[00]: pat
-[01]: d
+% Command incomplete.
test# pat d foo 1.2.3.4
cmd8 with 4 args.
[00]: pat
diff --git a/tools/permutations.c b/tools/permutations.c
index 8db51ee037..0ca980b259 100644
--- a/tools/permutations.c
+++ b/tools/permutations.c
@@ -70,7 +70,7 @@ permute (struct graph_node *start)
for (ALL_LIST_ELEMENTS_RO (position,ln,gnn))
{
struct cmd_token *tt = gnn->data;
- if (tt->type < SELECTOR_TKN)
+ if (tt->type < SPECIAL_TKN)
fprintf (stdout, "%s ", tt->text);
}
fprintf (stdout, "\n");
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 50677b5685..51b5091c57 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -312,6 +312,10 @@ vtysh_execute_func (const char *line, int pager)
{
vtysh_execute("exit-address-family");
}
+ else if (saved_node == BGP_VRF_POLICY_NODE && (tried == 1))
+ {
+ vtysh_execute("exit-vrf-policy");
+ }
else if ((saved_node == BGP_VNC_DEFAULTS_NODE
|| saved_node == BGP_VNC_NVE_GROUP_NODE
|| saved_node == BGP_VNC_L2_GROUP_NODE) && (tried == 1))
@@ -963,6 +967,11 @@ static struct cmd_node bgp_vnc_nve_group_node =
"%s(config-router-vnc-nve-group)# "
};
+static struct cmd_node bgp_vrf_policy_node = {
+ BGP_VRF_POLICY_NODE,
+ "%s(config-router-vrf-policy)# "
+};
+
static struct cmd_node bgp_vnc_l2_group_node =
{
BGP_VNC_L2_GROUP_NODE,
@@ -1210,6 +1219,17 @@ DEFUNSH (VTYSH_BGPD,
}
DEFUNSH (VTYSH_BGPD,
+ vnc_vrf_policy,
+ vnc_vrf_policy_cmd,
+ "vrf-policy NAME",
+ "Configure a VRF policy group\n"
+ "Group name\n")
+{
+ vty->node = BGP_VRF_POLICY_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUNSH (VTYSH_BGPD,
vnc_l2_group,
vnc_l2_group_cmd,
"vnc l2-group NAME",
@@ -1481,6 +1501,7 @@ vtysh_exit (struct vty *vty)
case BGP_IPV4M_NODE:
case BGP_IPV6_NODE:
case BGP_IPV6M_NODE:
+ case BGP_VRF_POLICY_NODE:
case BGP_VNC_DEFAULTS_NODE:
case BGP_VNC_NVE_GROUP_NODE:
case BGP_VNC_L2_GROUP_NODE:
@@ -1560,6 +1581,17 @@ DEFUNSH (VTYSH_BGPD,
return CMD_SUCCESS;
}
+DEFUNSH (VTYSH_BGPD,
+ exit_vrf_policy,
+ exit_vrf_policy_cmd,
+ "exit-vrf-policy",
+ "Exit from VRF configuration mode\n")
+{
+ if (vty->node == BGP_VRF_POLICY_NODE)
+ vty->node = BGP_NODE;
+ return CMD_SUCCESS;
+}
+
DEFUNSH (VTYSH_RIPD,
vtysh_exit_ripd,
vtysh_exit_ripd_cmd,
@@ -3042,6 +3074,7 @@ vtysh_init_vty (void)
install_node (&bgp_ipv4m_node, NULL);
install_node (&bgp_ipv6_node, NULL);
install_node (&bgp_ipv6m_node, NULL);
+ install_node (&bgp_vrf_policy_node, NULL);
install_node (&bgp_vnc_defaults_node, NULL);
install_node (&bgp_vnc_nve_group_node, NULL);
install_node (&bgp_vnc_l2_group_node, NULL);
@@ -3079,6 +3112,7 @@ vtysh_init_vty (void)
vtysh_install_default (BGP_IPV6_NODE);
vtysh_install_default (BGP_IPV6M_NODE);
#if ENABLE_BGP_VNC
+ vtysh_install_default (BGP_VRF_POLICY_NODE);
vtysh_install_default (BGP_VNC_DEFAULTS_NODE);
vtysh_install_default (BGP_VNC_NVE_GROUP_NODE);
vtysh_install_default (BGP_VNC_L2_GROUP_NODE);
@@ -3150,6 +3184,8 @@ vtysh_init_vty (void)
install_element (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd);
#if defined (ENABLE_BGP_VNC)
+ install_element (BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_exit_bgpd_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_quit_bgpd_cmd);
install_element (BGP_VNC_NVE_GROUP_NODE, &vtysh_exit_bgpd_cmd);
@@ -3191,6 +3227,7 @@ vtysh_init_vty (void)
install_element (BGP_ENCAPV6_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd);
install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
install_element (BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
install_element (BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
@@ -3239,6 +3276,7 @@ vtysh_init_vty (void)
install_element (BGP_NODE, &address_family_encapv4_cmd);
install_element (BGP_NODE, &address_family_encapv6_cmd);
#if defined(ENABLE_BGP_VNC)
+ install_element (BGP_NODE, &vnc_vrf_policy_cmd);
install_element (BGP_NODE, &vnc_defaults_cmd);
install_element (BGP_NODE, &vnc_nve_group_cmd);
install_element (BGP_NODE, &vnc_l2_group_cmd);
@@ -3256,6 +3294,7 @@ vtysh_init_vty (void)
install_element (BGP_IPV6_NODE, &exit_address_family_cmd);
install_element (BGP_IPV6M_NODE, &exit_address_family_cmd);
+ install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);
install_element (BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd);
install_element (BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd);
diff --git a/zebra/zebra_fpm_dt.c b/zebra/zebra_fpm_dt.c
index bd171c89b2..715e250a66 100644
--- a/zebra/zebra_fpm_dt.c
+++ b/zebra/zebra_fpm_dt.c
@@ -42,6 +42,8 @@
#include "vrf.h"
#include "zebra/rib.h"
+#include "zebra/zserv.h"
+#include "zebra/zebra_vrf.h"
#include "zebra_fpm_private.h"