From 57d187bc77f5a07fab335cb0949f3f2e77fc7e6c Mon Sep 17 00:00:00 2001 From: Job Snijders Date: Tue, 15 Nov 2016 19:00:39 +0900 Subject: [PATCH 01/26] Support for BGP Large Communities BGP Large Communities are a novel way to signal information between networks. An example of a Large Community is: "2914:65400:38016". Large BGP Communities are composed of three 4-byte integers, separated by a colon. This is easy to remember and accommodates advanced routing policies in relation to 4-Byte ASNs. This feature was developed by: Keyur Patel (Arrcus, Inc.), Job Snijders (NTT Communications), David Lamparter and Donald Sharp Signed-off-by: Job Snijders Signed-off-by: David Lamparter Signed-off-by: Donald Sharp --- bgpd/Makefile.am | 6 +- bgpd/bgp_attr.c | 101 +++++++- bgpd/bgp_attr.h | 3 + bgpd/bgp_clist.c | 312 +++++++++++++++++++++++ bgpd/bgp_clist.h | 18 +- bgpd/bgp_ecommunity.c | 1 + bgpd/bgp_encap.c | 1 + bgpd/bgp_lcommunity.c | 563 ++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_lcommunity.h | 75 ++++++ bgpd/bgp_memory.c | 4 + bgpd/bgp_memory.h | 3 + bgpd/bgp_mpath.c | 14 ++ bgpd/bgp_packet.c | 1 + bgpd/bgp_route.c | 122 ++++++++- bgpd/bgp_routemap.c | 409 ++++++++++++++++++++++++++++++ bgpd/bgp_vty.c | 445 ++++++++++++++++++++++++++++++++- bgpd/bgpd.c | 27 +- bgpd/bgpd.h | 2 + lib/routemap.c | 7 + lib/routemap.h | 2 + 20 files changed, 2093 insertions(+), 23 deletions(-) create mode 100644 bgpd/bgp_lcommunity.c create mode 100644 bgpd/bgp_lcommunity.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 69c0504af451..6e36a950d664 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 4cf1f0daed7a..fc9440dddc8f 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,6 +1038,10 @@ bgp_attr_unintern_sub (struct attr *attr) if (attr->extra->ecommunity) ecommunity_unintern (&attr->extra->ecommunity); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)); + + if (attr->extra->lcommunity) + lcommunity_unintern (&attr->extra->lcommunity); + UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); if (attr->extra->cluster) cluster_unintern (attr->extra->cluster); @@ -1096,6 +1112,8 @@ bgp_attr_flush (struct attr *attr) if (attre->ecommunity && ! attre->ecommunity->refcnt) ecommunity_free (&attre->ecommunity); + if (attre->lcommunity && ! attre->lcommunity->refcnt) + lcommunity_free (&attre->lcommunity); if (attre->cluster && ! attre->cluster->refcnt) { cluster_free (attre->cluster); @@ -1254,6 +1272,7 @@ const u_int8_t attr_flags_values [] = { [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, + [BGP_ATTR_LARGE_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL }; static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1; @@ -2042,6 +2061,40 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_PROCEED; } +/* Large Community attribute. */ +static bgp_attr_parse_ret_t +bgp_attr_large_community (struct bgp_attr_parser_args *args) +{ + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; + + /* + * Large community follows new attribute format. + */ + if (length == 0) + { + if (attr->extra) + attr->extra->lcommunity = NULL; + /* Empty extcomm doesn't seem to be invalid per se */ + return BGP_ATTR_PARSE_PROCEED; + } + + (bgp_attr_extra_get (attr))->lcommunity = + lcommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); + /* XXX: fix ecommunity_parse to use stream API */ + stream_forward_getp (peer->ibuf, length); + + if (attr->extra && !attr->extra->lcommunity) + return bgp_attr_malformed (args, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + + return BGP_ATTR_PARSE_PROCEED; +} + /* Extended Community attribute. */ static bgp_attr_parse_ret_t bgp_attr_ext_communities (struct bgp_attr_parser_args *args) @@ -2063,7 +2116,7 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args) /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp (peer->ibuf, length); - if (!attr->extra->ecommunity) + if (attr->extra && !attr->extra->ecommunity) return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); @@ -2477,6 +2530,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_COMMUNITIES: ret = bgp_attr_community (&attr_args); break; + case BGP_ATTR_LARGE_COMMUNITIES: + ret = bgp_attr_large_community (&attr_args); + break; case BGP_ATTR_ORIGINATOR_ID: ret = bgp_attr_originator_id (&attr_args); break; @@ -3101,6 +3157,28 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_put (s, attr->community->val, attr->community->size * 4); } + /* + * Large Community attribute. + */ + if (attr->extra && + CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY) + && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES))) + { + if (attr->extra->lcommunity->size * 12 > 255) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); + stream_putw (s, attr->extra->lcommunity->size * 12); + } + else + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); + stream_putc (s, attr->extra->lcommunity->size * 12); + } + stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12); + } + /* Route Reflector. */ if (peer->sort == BGP_PEER_IBGP && from @@ -3333,6 +3411,7 @@ bgp_attr_init (void) attrhash_init (); community_init (); ecommunity_init (); + lcommunity_init (); cluster_init (); transit_init (); encap_init (); @@ -3345,6 +3424,7 @@ bgp_attr_finish (void) attrhash_finish (); community_finish (); ecommunity_finish (); + lcommunity_finish (); cluster_finish (); transit_finish (); encap_finish (); @@ -3448,6 +3528,25 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, stream_put (s, attr->community->val, attr->community->size * 4); } + /* Large Community attribute. */ + if (attr->extra && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)) + { + if (attr->extra->lcommunity->size * 12 > 255) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); + stream_putw (s, attr->extra->lcommunity->size * 12); + } + else + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); + stream_putc (s, attr->extra->lcommunity->size * 12); + } + + stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12); + } + /* Add a MP_NLRI attribute to dump the IPv6 next hop */ if (prefix != NULL && prefix->family == AF_INET6 && attr->extra && (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL || diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 6e639078d60a..9c931051d875 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -92,6 +92,9 @@ struct attr_extra /* Extended Communities attribute. */ struct ecommunity *ecommunity; + + /* Large Communities attribute. */ + struct lcommunity *lcommunity; /* Route-Reflector Cluster attribute */ struct cluster_list *cluster; diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 9032b1e2f4fb..47192f0f03c6 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" @@ -45,6 +46,8 @@ community_list_master_lookup (struct community_list_handler *ch, int master) return &ch->community_list; case EXTCOMMUNITY_LIST_MASTER: return &ch->extcommunity_list; + case LARGE_COMMUNITY_LIST_MASTER: + return &ch->lcommunity_list; } return NULL; } @@ -66,6 +69,10 @@ community_entry_free (struct community_entry *entry) if (entry->u.com) community_free (entry->u.com); break; + case LARGE_COMMUNITY_LIST_STANDARD: + if (entry->u.lcom) + lcommunity_free (&entry->u.lcom); + break; case EXTCOMMUNITY_LIST_STANDARD: /* In case of standard extcommunity-list, configuration string is made by ecommunity_ecom2str(). */ @@ -76,6 +83,7 @@ community_entry_free (struct community_entry *entry) break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: + case LARGE_COMMUNITY_LIST_EXPANDED: if (entry->config) XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config); if (entry->reg) @@ -320,8 +328,13 @@ community_list_entry_lookup (struct community_list *list, const void *arg, if (entry->direct == direct && ecommunity_cmp (entry->u.ecom, arg)) return entry; break; + case LARGE_COMMUNITY_LIST_STANDARD: + if (entry->direct == direct && lcommunity_cmp (entry->u.lcom, arg)) + return entry; + break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: + case LARGE_COMMUNITY_LIST_EXPANDED: if (entry->direct == direct && strcmp (entry->config, arg) == 0) return entry; break; @@ -447,6 +460,91 @@ community_regexp_match (struct community *com, regex_t * reg) return 0; } +static char * +lcommunity_str_get (struct lcommunity *lcom, int i) +{ + struct lcommunity_val lcomval; + u_int32_t globaladmin; + u_int32_t localdata1; + u_int32_t localdata2; + char *str; + u_char *ptr; + char *pnt; + + ptr = lcom->val; + ptr += (i * LCOMMUNITY_SIZE); + + memcpy (&lcomval, ptr, LCOMMUNITY_SIZE); + + /* Allocate memory. 48 bytes taken off bgp_lcommunity.c */ + str = pnt = XMALLOC (MTYPE_LCOMMUNITY_STR, 48); + + ptr = (u_char *)lcomval.val; + globaladmin = (*ptr++ << 24); + globaladmin |= (*ptr++ << 16); + globaladmin |= (*ptr++ << 8); + globaladmin |= (*ptr++); + + localdata1 = (*ptr++ << 24); + localdata1 |= (*ptr++ << 16); + localdata1 |= (*ptr++ << 8); + localdata1 |= (*ptr++); + + localdata2 = (*ptr++ << 24); + localdata2 |= (*ptr++ << 16); + localdata2 |= (*ptr++ << 8); + localdata2 |= (*ptr++); + + sprintf (pnt, "%u:%u:%u", globaladmin, localdata1, localdata2); + pnt += strlen (pnt); + *pnt = '\0'; + + return str; +} + +/* Internal function to perform regular expression match for + * * a single community. */ +static int +lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i) +{ + const char *str; + + /* When there is no communities attribute it is treated as empty + * string. */ + if (lcom == NULL || lcom->size == 0) + str = ""; + else + str = lcommunity_str_get (lcom, i); + + /* Regular expression match. */ + if (regexec (reg, str, 0, NULL, 0) == 0) + return 1; + + /* No match. */ + return 0; +} + +static int +lcommunity_regexp_match (struct lcommunity *com, regex_t * reg) +{ + const char *str; + + /* When there is no communities attribute it is treated as empty + string. */ + if (com == NULL || com->size == 0) + str = ""; + else + str = lcommunity_str (com); + + /* Regular expression match. */ + if (regexec (reg, str, 0, NULL, 0) == 0) + return 1; + + /* No match. */ + return 0; +} + + static int ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg) { @@ -546,6 +644,30 @@ community_list_match (struct community *com, struct community_list *list) return 0; } +int +lcommunity_list_match (struct lcommunity *lcom, struct community_list *list) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + if (entry->any) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + + if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) + { + if (lcommunity_match (lcom, entry->u.lcom)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + } + else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) + { + if (lcommunity_regexp_match (lcom, entry->reg)) + return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + } + } + return 0; +} + int ecommunity_list_match (struct ecommunity *ecom, struct community_list *list) { @@ -694,12 +816,17 @@ community_list_dup_check (struct community_list *list, if (community_cmp (entry->u.com, new->u.com)) return 1; break; + case LARGE_COMMUNITY_LIST_STANDARD: + if (lcommunity_cmp (entry->u.lcom, new->u.lcom)) + return 1; + break; case EXTCOMMUNITY_LIST_STANDARD: if (ecommunity_cmp (entry->u.ecom, new->u.ecom)) return 1; break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: + case LARGE_COMMUNITY_LIST_EXPANDED: if (strcmp (entry->config, new->config) == 0) return 1; break; @@ -817,6 +944,185 @@ community_list_unset (struct community_list_handler *ch, return 0; } +/* Delete all permitted large communities in the list from com. */ +struct lcommunity * +lcommunity_list_match_delete (struct lcommunity *lcom, + struct community_list *list) +{ + struct community_entry *entry; + u_int32_t com_index_to_delete[lcom->size]; + u_char *ptr; + int delete_index = 0; + int i; + + /* Loop over each lcommunity value and evaluate each against the + * community-list. If we need to delete a community value add its index to + * com_index_to_delete. + */ + ptr = lcom->val; + for (i = 0; i < lcom->size; i++) + { + ptr += (i * LCOMMUNITY_SIZE); + for (entry = list->head; entry; entry = entry->next) + { + if (entry->any) + { + if (entry->direct == COMMUNITY_PERMIT) + { + com_index_to_delete[delete_index] = i; + delete_index++; + } + break; + } + + else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) + && lcommunity_include (entry->u.lcom, ptr) ) + { + if (entry->direct == COMMUNITY_PERMIT) + { + com_index_to_delete[delete_index] = i; + delete_index++; + } + break; + } + + else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) + && lcommunity_regexp_include (entry->reg, lcom, i)) + { + if (entry->direct == COMMUNITY_PERMIT) + { + com_index_to_delete[delete_index] = i; + delete_index++; + } + break; + } + } + } + + /* Delete all of the communities we flagged for deletion */ + ptr = lcom->val; + for (i = delete_index-1; i >= 0; i--) + { + ptr += (com_index_to_delete[i] * LCOMMUNITY_SIZE); + lcommunity_del_val (lcom, ptr); + } + + return lcom; +} + +/* Set lcommunity-list. */ +int +lcommunity_list_set (struct community_list_handler *ch, + const char *name, const char *str, int direct, int style) +{ + struct community_entry *entry = NULL; + struct community_list *list; + struct lcommunity *lcom = NULL; + regex_t *regex = NULL; + + /* Get community list. */ + list = community_list_get (ch, name, LARGE_COMMUNITY_LIST_MASTER); + + /* When community-list already has entry, new entry should have same + style. If you want to have mixed style community-list, you can + comment out this check. */ + if (!community_list_empty_p (list)) + { + struct community_entry *first; + + first = list->head; + + if (style != first->style) + { + return (first->style == COMMUNITY_LIST_STANDARD + ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT + : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); + } + } + + if (str) + { + if (style == LARGE_COMMUNITY_LIST_STANDARD) + lcom = lcommunity_str2com (str); + else + regex = bgp_regcomp (str); + + if (! lcom && ! regex) + return COMMUNITY_LIST_ERR_MALFORMED_VAL; + } + + entry = community_entry_new (); + entry->direct = direct; + entry->style = style; + entry->any = (str ? 0 : 1); + entry->u.lcom = lcom; + entry->reg = regex; + if (lcom) + entry->config = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST); + else if (regex) + entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str); + else + entry->config = NULL; + + /* Do not put duplicated community entry. */ + if (community_list_dup_check (list, entry)) + community_entry_free (entry); + else + community_list_entry_add (list, entry); + + return 0; +} + +/* Unset community-list. When str is NULL, delete all of + community-list entry belongs to the specified name. */ +int +lcommunity_list_unset (struct community_list_handler *ch, + const char *name, const char *str, + int direct, int style) +{ + struct community_entry *entry = NULL; + struct community_list *list; + struct lcommunity *lcom = NULL; + regex_t *regex = NULL; + + /* Lookup community list. */ + list = community_list_lookup (ch, name, LARGE_COMMUNITY_LIST_MASTER); + if (list == NULL) + return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + + /* Delete all of entry belongs to this community-list. */ + if (!str) + { + community_list_delete (list); + return 0; + } + + if (style == LARGE_COMMUNITY_LIST_STANDARD) + lcom = lcommunity_str2com (str); + else + regex = bgp_regcomp (str); + + if (! lcom && ! regex) + return COMMUNITY_LIST_ERR_MALFORMED_VAL; + + if (lcom) + entry = community_list_entry_lookup (list, lcom, direct); + else + entry = community_list_entry_lookup (list, str, direct); + + if (lcom) + lcommunity_free (&lcom); + if (regex) + bgp_regex_free (regex); + + if (!entry) + return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + + community_list_entry_delete (list, entry, style); + + return 0; +} + /* Set extcommunity-list. */ int extcommunity_list_set (struct community_list_handler *ch, @@ -959,6 +1265,12 @@ community_list_terminate (struct community_list_handler *ch) while ((list = cm->str.head) != NULL) community_list_delete (list); + cm = &ch->lcommunity_list; + while ((list = cm->num.head) != NULL) + community_list_delete (list); + while ((list = cm->str.head) != NULL) + community_list_delete (list); + cm = &ch->extcommunity_list; while ((list = cm->num.head) != NULL) community_list_delete (list); diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h index 277ab7226c53..68e45c8f7bcd 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 b65af9e1fabb..6689883d94ef 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 75a348e3fe86..418f2873c9e3 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 000000000000..a4b6d96ed362 --- /dev/null +++ b/bgpd/bgp_lcommunity.c @@ -0,0 +1,563 @@ +/* BGP Large Communities Attribute + +Copyright (C) 2016 Keyur Patel + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "hash.h" +#include "memory.h" +#include "prefix.h" +#include "command.h" +#include "filter.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_lcommunity.h" +#include "bgpd/bgp_aspath.h" + +/* Hash of community attribute. */ +static struct hash *lcomhash; + +/* Allocate a new lcommunities. */ +static struct lcommunity * +lcommunity_new (void) +{ + return (struct lcommunity *) XCALLOC (MTYPE_LCOMMUNITY, + sizeof (struct lcommunity)); +} + +/* Allocate lcommunities. */ +void +lcommunity_free (struct lcommunity **lcom) +{ + if ((*lcom)->val) + XFREE (MTYPE_LCOMMUNITY_VAL, (*lcom)->val); + if ((*lcom)->str) + XFREE (MTYPE_LCOMMUNITY_STR, (*lcom)->str); + XFREE (MTYPE_LCOMMUNITY, *lcom); + lcom = NULL; +} + +/* Add a new Large Communities value to Large Communities + Attribute structure. When the value is already exists in the + structure, we don't add the value. Newly added value is sorted by + numerical order. When the value is added to the structure return 1 + else return 0. */ +static int +lcommunity_add_val (struct lcommunity *lcom, struct lcommunity_val *lval) +{ + u_int8_t *p; + int ret; + int c; + + /* When this is fist value, just add it. */ + if (lcom->val == NULL) + { + lcom->size++; + lcom->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom_length (lcom)); + memcpy (lcom->val, lval->val, LCOMMUNITY_SIZE); + return 1; + } + + /* If the value already exists in the structure return 0. */ + c = 0; + for (p = lcom->val; c < lcom->size; p += LCOMMUNITY_SIZE, c++) + { + ret = memcmp (p, lval->val, LCOMMUNITY_SIZE); + if (ret == 0) + return 0; + if (ret > 0) + break; + } + + /* Add the value to the structure with numerical sorting. */ + lcom->size++; + lcom->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom->val, lcom_length (lcom)); + + memmove (lcom->val + (c + 1) * LCOMMUNITY_SIZE, + lcom->val + c * LCOMMUNITY_SIZE, + (lcom->size - 1 - c) * LCOMMUNITY_SIZE); + memcpy (lcom->val + c * LCOMMUNITY_SIZE, lval->val, LCOMMUNITY_SIZE); + + return 1; +} + +/* This function takes pointer to Large Communites strucutre then + create a new Large Communities structure by uniq and sort each + Large Communities value. */ +struct lcommunity * +lcommunity_uniq_sort (struct lcommunity *lcom) +{ + int i; + struct lcommunity *new; + struct lcommunity_val *lval; + + if (! lcom) + return NULL; + + new = lcommunity_new (); + + for (i = 0; i < lcom->size; i++) + { + lval = (struct lcommunity_val *) (lcom->val + (i * LCOMMUNITY_SIZE)); + lcommunity_add_val (new, lval); + } + return new; +} + +/* Parse Large Communites Attribute in BGP packet. */ +struct lcommunity * +lcommunity_parse (u_int8_t *pnt, u_short length) +{ + struct lcommunity tmp; + struct lcommunity *new; + + /* Length check. */ + if (length % LCOMMUNITY_SIZE) + return NULL; + + /* Prepare tmporary structure for making a new Large Communities + Attribute. */ + tmp.size = length / LCOMMUNITY_SIZE; + tmp.val = pnt; + + /* Create a new Large Communities Attribute by uniq and sort each + Large Communities value */ + new = lcommunity_uniq_sort (&tmp); + + return lcommunity_intern (new); +} + +/* Duplicate the Large Communities Attribute structure. */ +struct lcommunity * +lcommunity_dup (struct lcommunity *lcom) +{ + struct lcommunity *new; + + new = XCALLOC (MTYPE_LCOMMUNITY, sizeof (struct lcommunity)); + new->size = lcom->size; + if (new->size) + { + new->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom->size * LCOMMUNITY_SIZE); + memcpy (new->val, lcom->val, lcom->size * LCOMMUNITY_SIZE); + } + else + new->val = NULL; + return new; +} + +/* Retrun string representation of communities attribute. */ +char * +lcommunity_str (struct lcommunity *lcom) +{ + if (! lcom->str) + lcom->str = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_DISPLAY); + return lcom->str; +} + +/* Merge two Large Communities Attribute structure. */ +struct lcommunity * +lcommunity_merge (struct lcommunity *lcom1, struct lcommunity *lcom2) +{ + if (lcom1->val) + lcom1->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom1->val, + (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE); + else + lcom1->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, + (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE); + + memcpy (lcom1->val + (lcom1->size * LCOMMUNITY_SIZE), + lcom2->val, lcom2->size * LCOMMUNITY_SIZE); + lcom1->size += lcom2->size; + + return lcom1; +} + +/* Intern Large Communities Attribute. */ +struct lcommunity * +lcommunity_intern (struct lcommunity *lcom) +{ + struct lcommunity *find; + + assert (lcom->refcnt == 0); + + find = (struct lcommunity *) hash_get (lcomhash, lcom, hash_alloc_intern); + + if (find != lcom) + lcommunity_free (&lcom); + + find->refcnt++; + + if (! find->str) + find->str = lcommunity_lcom2str (find, LCOMMUNITY_FORMAT_DISPLAY); + + return find; +} + +/* Unintern Large Communities Attribute. */ +void +lcommunity_unintern (struct lcommunity **lcom) +{ + struct lcommunity *ret; + + if ((*lcom)->refcnt) + (*lcom)->refcnt--; + + /* Pull off from hash. */ + if ((*lcom)->refcnt == 0) + { + /* Large community must be in the hash. */ + ret = (struct lcommunity *) hash_release (lcomhash, *lcom); + assert (ret != NULL); + + lcommunity_free (lcom); + } +} + +/* Utility function to make hash key. */ +unsigned int +lcommunity_hash_make (void *arg) +{ + const struct lcommunity *lcom = arg; + int size = lcom->size * LCOMMUNITY_SIZE; + u_int8_t *pnt = lcom->val; + unsigned int key = 0; + int c; + + for (c = 0; c < size; c += LCOMMUNITY_SIZE) + { + key += pnt[c]; + key += pnt[c + 1]; + key += pnt[c + 2]; + key += pnt[c + 3]; + key += pnt[c + 4]; + key += pnt[c + 5]; + key += pnt[c + 6]; + key += pnt[c + 7]; + key += pnt[c + 8]; + key += pnt[c + 9]; + key += pnt[c + 10]; + key += pnt[c + 11]; + } + + return key; +} + +/* Compare two Large Communities Attribute structure. */ +int +lcommunity_cmp (const void *arg1, const void *arg2) +{ + const struct lcommunity *lcom1 = arg1; + const struct lcommunity *lcom2 = arg2; + + return (lcom1->size == lcom2->size + && memcmp (lcom1->val, lcom2->val, lcom1->size * LCOMMUNITY_SIZE) == 0); +} + +/* Return communities hash. */ +struct hash * +lcommunity_hash (void) +{ + return lcomhash; +} + +/* Initialize Large Comminities related hash. */ +void +lcommunity_init (void) +{ + lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp); +} + +void +lcommunity_finish (void) +{ + hash_free (lcomhash); + lcomhash = NULL; +} + +/* Large Communities token enum. */ +enum lcommunity_token +{ + lcommunity_token_unknown = 0, + lcommunity_token_val, +}; + +/* Get next Large Communities token from the string. */ +static const char * +lcommunity_gettoken (const char *str, struct lcommunity_val *lval, + enum lcommunity_token *token) +{ + const char *p = str; + + /* Skip white space. */ + while (isspace ((int) *p)) + { + p++; + str++; + } + + /* Check the end of the line. */ + if (*p == '\0') + return NULL; + + /* Community value. */ + if (isdigit ((int) *p)) + { + int separator = 0; + int digit = 0; + u_int32_t globaladmin = 0; + u_int32_t localdata1 = 0; + u_int32_t localdata2 = 0; + + while (isdigit ((int) *p) || *p == ':') + { + if (*p == ':') + { + if (separator == 2) + { + *token = lcommunity_token_unknown; + return NULL; + } + else + { + separator++; + digit = 0; + if (separator == 1) { + globaladmin = localdata2; + } else { + localdata1 = localdata2; + } + localdata2 = 0; + } + } + else + { + digit = 1; + localdata2 *= 10; + localdata2 += (*p - '0'); + } + p++; + } + if (! digit) + { + *token = lcommunity_token_unknown; + return NULL; + } + + /* + * Copy the large comm. + */ + lval->val[0] = (globaladmin >> 24) & 0xff; + lval->val[1] = (globaladmin >> 16) & 0xff; + lval->val[2] = (globaladmin >> 8) & 0xff; + lval->val[3] = globaladmin & 0xff; + lval->val[4] = (localdata1 >> 24) & 0xff; + lval->val[5] = (localdata1 >> 16) & 0xff; + lval->val[6] = (localdata1 >> 8) & 0xff; + lval->val[7] = localdata1 & 0xff; + lval->val[8] = (localdata2 >> 24) & 0xff; + lval->val[9] = (localdata2 >> 16) & 0xff; + lval->val[10] = (localdata2 >> 8) & 0xff; + lval->val[11] = localdata2 & 0xff; + + *token = lcommunity_token_val; + return p; + } + *token = lcommunity_token_unknown; + return p; +} + +/* + Convert string to large community attribute. + When type is already known, please specify both str and type. + + When string includes keyword for each large community value. + Please specify keyword_included as non-zero value. +*/ +struct lcommunity * +lcommunity_str2com (const char *str) +{ + struct lcommunity *lcom = NULL; + enum lcommunity_token token = lcommunity_token_unknown; + struct lcommunity_val lval; + + while ((str = lcommunity_gettoken (str, &lval, &token))) + { + switch (token) + { + case lcommunity_token_val: + if (lcom == NULL) + lcom = lcommunity_new (); + lcommunity_add_val (lcom, &lval); + break; + case lcommunity_token_unknown: + default: + if (lcom) + lcommunity_free (&lcom); + return NULL; + } + } + return lcom; +} + +int +lcommunity_include (struct lcommunity *lcom, u_char *ptr) +{ + int i; + u_char *lcom_ptr; + + lcom_ptr = lcom->val; + for (i = 0; i < lcom->size; i++) { + lcom_ptr += (i * LCOMMUNITY_SIZE); + if (memcmp (ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0) + return 1; + } + return 0; +} + +/* Convert large community attribute to string. + The large coms will be in 65535:65531:0 format. +*/ +char * +lcommunity_lcom2str (struct lcommunity *lcom, int format) +{ + int i; + u_int8_t *pnt; +#define LCOMMUNITY_STR_DEFAULT_LEN 40 + int str_size; + int str_pnt; + char *str_buf; + int len = 0; + int first = 1; + u_int32_t globaladmin, localdata1, localdata2; + + if (lcom->size == 0) + { + str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, 1); + str_buf[0] = '\0'; + return str_buf; + } + + /* Prepare buffer. */ + str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, LCOMMUNITY_STR_DEFAULT_LEN + 1); + str_size = LCOMMUNITY_STR_DEFAULT_LEN + 1; + str_pnt = 0; + + for (i = 0; i < lcom->size; i++) + { + /* Make it sure size is enough. */ + while (str_pnt + LCOMMUNITY_STR_DEFAULT_LEN >= str_size) + { + str_size *= 2; + str_buf = XREALLOC (MTYPE_LCOMMUNITY_STR, str_buf, str_size); + } + + /* Space between each value. */ + if (! first) + str_buf[str_pnt++] = ' '; + + pnt = lcom->val + (i * 12); + + globaladmin = (*pnt++ << 24); + globaladmin |= (*pnt++ << 16); + globaladmin |= (*pnt++ << 8); + globaladmin |= (*pnt++); + + localdata1 = (*pnt++ << 24); + localdata1 |= (*pnt++ << 16); + localdata1 |= (*pnt++ << 8); + localdata1 |= (*pnt++); + + localdata2 = (*pnt++ << 24); + localdata2 |= (*pnt++ << 16); + localdata2 |= (*pnt++ << 8); + localdata2 |= (*pnt++); + + len = sprintf( str_buf + str_pnt, "%u:%u:%u", globaladmin, + localdata1, localdata2); + str_pnt += len; + first = 0; + } + return str_buf; +} + +int +lcommunity_match (const struct lcommunity *lcom1, + const struct lcommunity *lcom2) +{ + int i = 0; + int j = 0; + + if (lcom1 == NULL && lcom2 == NULL) + return 1; + + if (lcom1 == NULL || lcom2 == NULL) + return 0; + + if (lcom1->size < lcom2->size) + return 0; + + /* Every community on com2 needs to be on com1 for this to match */ + while (i < lcom1->size && j < lcom2->size) + { + if (memcmp (lcom1->val + (i*12), lcom2->val + (j*12), LCOMMUNITY_SIZE) == 0) + j++; + i++; + } + + if (j == lcom2->size) + return 1; + else + return 0; +} + +/* Delete one lcommunity. */ +void +lcommunity_del_val (struct lcommunity *lcom, u_char *ptr) +{ + int i = 0; + int c = 0; + + if (! lcom->val) + return; + + while (i < lcom->size) + { + if (memcmp (lcom->val + i*LCOMMUNITY_SIZE, ptr, LCOMMUNITY_SIZE) == 0) + { + c = lcom->size -i -1; + + if (c > 0) + memmove (lcom->val + i*LCOMMUNITY_SIZE, lcom->val + (i + 1)*LCOMMUNITY_SIZE, c * LCOMMUNITY_SIZE); + + lcom->size--; + + if (lcom->size > 0) + lcom->val = XREALLOC (MTYPE_COMMUNITY_VAL, lcom->val, + lcom_length (lcom)); + else + { + XFREE (MTYPE_COMMUNITY_VAL, lcom->val); + lcom->val = NULL; + } + return; + } + i++; + } +} diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h new file mode 100644 index 000000000000..7841b4b9a62c --- /dev/null +++ b/bgpd/bgp_lcommunity.h @@ -0,0 +1,75 @@ +/* BGP Large Communities Attribute. + +Copyright (C) 2016 Keyur Patel + +This file is part of GNU Zebra. + +GNU Zebra is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GNU Zebra is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Zebra; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _QUAGGA_BGP_LCOMMUNITY_H +#define _QUAGGA_BGP_LCOMMUNITY_H + +/* Extended communities attribute string format. */ +#define LCOMMUNITY_FORMAT_ROUTE_MAP 0 +#define LCOMMUNITY_FORMAT_COMMUNITY_LIST 1 +#define LCOMMUNITY_FORMAT_DISPLAY 2 + +/* Large Communities value is twelve octets long. */ +#define LCOMMUNITY_SIZE 12 + +/* Large Communities attribute. */ +struct lcommunity +{ + /* Reference counter. */ + unsigned long refcnt; + + /* Size of Extended Communities attribute. */ + int size; + + /* Extended Communities value. */ + u_int8_t *val; + + /* Human readable format string. */ + char *str; +}; + +/* Extended community value is eight octet. */ +struct lcommunity_val +{ + char val[LCOMMUNITY_SIZE]; +}; + +#define lcom_length(X) ((X)->size * LCOMMUNITY_SIZE) + +extern void lcommunity_init (void); +extern void lcommunity_finish (void); +extern void lcommunity_free (struct lcommunity **); +extern struct lcommunity *lcommunity_parse (u_int8_t *, u_short); +extern struct lcommunity *lcommunity_dup (struct lcommunity *); +extern struct lcommunity *lcommunity_merge (struct lcommunity *, struct lcommunity *); +extern struct lcommunity *lcommunity_uniq_sort (struct lcommunity *); +extern struct lcommunity *lcommunity_intern (struct lcommunity *); +extern int lcommunity_cmp (const void *, const void *); +extern void lcommunity_unintern (struct lcommunity **); +extern unsigned int lcommunity_hash_make (void *); +extern struct hash *lcommunity_hash (void); +extern struct lcommunity *lcommunity_str2com (const char *); +extern char *lcommunity_lcom2str (struct lcommunity *, int); +extern int lcommunity_match (const struct lcommunity *, const struct lcommunity *); +extern char *lcommunity_str (struct lcommunity *); +extern int lcommunity_include (struct lcommunity *lcom, u_char *ptr); +extern void lcommunity_del_val (struct lcommunity *lcom, u_char *ptr); +#endif /* _QUAGGA_BGP_LCOMMUNITY_H */ diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 72c0311c1710..85e32645ee45 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 a4ce8b891b22..341fb235d00c 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 1701c7044148..f564ff16916d 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_packet.c b/bgpd/bgp_packet.c index 38470a3c7e9f..4c95f1b8f5a3 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 26c500af1b4d..33b7bc1251d4 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 This file is part of GNU Zebra. @@ -46,6 +47,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_regex.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_clist.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_filter.h" @@ -7059,7 +7061,12 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, } } - /* Line 6 display Originator, Cluster-id */ + /* Line 6 display Large community */ + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) + vty_out (vty, " Large Community: %s%s", + attr->extra->lcommunity->str, VTY_NEWLINE); + + /* Line 7 display Originator, Cluster-id */ if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) || (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) { @@ -7115,7 +7122,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (binfo->extra && binfo->extra->damp_info) bgp_damp_info_vty (vty, binfo, json_path); - /* Line 7 display Addpath IDs */ + /* Line 8 display Addpath IDs */ if (binfo->addpath_rx_id || binfo->addpath_tx_id) { if (json_paths) @@ -7170,7 +7177,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, } } - /* Line 8 display Uptime */ + /* Line 9 display Uptime */ tbuf = time(NULL) - (bgp_clock() - binfo->uptime); if (json_paths) { @@ -7227,6 +7234,9 @@ enum bgp_show_type bgp_show_type_community_exact, bgp_show_type_community_list, bgp_show_type_community_list_exact, + bgp_show_type_lcommunity_all, + bgp_show_type_lcommunity, + bgp_show_type_lcommunity_list, bgp_show_type_flap_statistics, bgp_show_type_flap_neighbor, bgp_show_type_dampend_paths, @@ -7416,6 +7426,32 @@ bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table, if (! community_list_exact_match (ri->attr->community, list)) continue; } + if (type == bgp_show_type_community_all) + { + if (! ri->attr->community) + continue; + } + if (type == bgp_show_type_lcommunity) + { + struct lcommunity *lcom = output_arg; + + if (! ri->attr->extra || ! ri->attr->extra->lcommunity || + ! lcommunity_match (ri->attr->extra->lcommunity, lcom)) + continue; + } + if (type == bgp_show_type_lcommunity_list) + { + struct community_list *list = output_arg; + + if (! ri->attr->extra || + ! lcommunity_list_match (ri->attr->extra->lcommunity, list)) + continue; + } + if (type == bgp_show_type_lcommunity_all) + { + if (! ri->attr->extra || ! ri->attr->extra->lcommunity) + continue; + } if (type == bgp_show_type_dampend_paths || type == bgp_show_type_damp_neighbor) { @@ -7832,6 +7868,63 @@ bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str, use_json); } +static int +bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc, + struct cmd_token **argv, afi_t afi, safi_t safi, u_char uj) +{ + struct lcommunity *lcom; + struct buffer *b; + int i; + char *str; + int first = 0; + + b = buffer_new (1024); + for (i = 0; i < argc; i++) + { + if (first) + buffer_putc (b, ' '); + else + { + if (strmatch (argv[i]->text, "")) + { + first = 1; + buffer_putstr (b, argv[i]->arg); + } + } + } + buffer_putc (b, '\0'); + + str = buffer_getstr (b); + buffer_free (b); + + lcom = lcommunity_str2com (str); + XFREE (MTYPE_TMP, str); + if (! lcom) + { + vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity, lcom, uj); +} + +static int +bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom, + afi_t afi, safi_t safi, u_char uj) +{ + struct community_list *list; + + list = community_list_lookup (bgp_clist, lcom, LARGE_COMMUNITY_LIST_MASTER); + if (list == NULL) + { + vty_out (vty, "%% %s is not a valid large-community-list name%s", lcom, + VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_list, list, uj); +} + /* BGP route print out function. */ DEFUN (show_ip_bgp_ipv4, show_ip_bgp_ipv4_cmd, @@ -7844,6 +7937,8 @@ DEFUN (show_ip_bgp_ipv4, |filter-list WORD\ |community [ [exact-match]]\ |community-list <(1-500)|WORD> [exact-match]\ + |large-community [...]\ + |large-community-list <(1-500)|WORD>\ |A.B.C.D/M longer-prefixes\ |X:X::X:X/M longer-prefixes>\ ] [json]", @@ -7878,6 +7973,14 @@ DEFUN (show_ip_bgp_ipv4, "community-list number\n" "community-list name\n" "Exact match of the communities\n" + "Display routes matching the large-communities\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "large-community number\n" + "Display routes matching the large-community-list\n" + "large-community-list number\n" + "large-community-list name\n" "IPv4 prefix\n" "Display route and more specific routes\n" "IPv6 prefix\n" @@ -7967,6 +8070,17 @@ DEFUN (show_ip_bgp_ipv4, exact_match = 1; return bgp_show_community_list (vty, vrf, clist_number_or_name, exact_match, afi, safi); } + else if (strmatch(argv[idx]->text, "large-community")) + { + if (strmatch(argv[idx+1]->text, "")) + return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj); + else + return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj); + } + else if (strmatch(argv[idx]->text, "large-community-list")) + { + return bgp_show_lcommunity_list (vty, bgp, argv[idx+1]->arg, afi, safi, uj); + } /* prefix-longer */ else if (argv[idx]->type == IPV4_TKN || argv[idx]->type == IPV6_TKN) return bgp_show_prefix_longer (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_longer); @@ -10527,6 +10641,7 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); install_element (VIEW_NODE, &show_ip_bgp_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd); + install_element (VIEW_NODE, &show_ip_bgp_instance_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); @@ -10537,6 +10652,7 @@ bgp_route_init (void) /* BGP dampening clear commands */ install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd); + install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 4f7f51fbbb87..c4b3ddee36b2 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,225 @@ struct route_map_rule_cmd route_set_community_cmd = route_set_community_free, }; +/* `set community COMMUNITY' */ +struct rmap_lcom_set +{ + struct lcommunity *lcom; + int additive; + int none; +}; + + +/* For lcommunity set mechanism. */ +static route_map_result_t +route_set_lcommunity (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct rmap_lcom_set *rcs; + struct bgp_info *binfo; + struct attr *attr; + struct lcommunity *new = NULL; + struct lcommunity *old; + struct lcommunity *merge; + + if (type == RMAP_BGP) + { + rcs = rule; + binfo = object; + attr = binfo->attr; + old = (attr->extra) ? attr->extra->lcommunity : NULL; + + /* "none" case. */ + if (rcs->none) + { + attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); + if (attr->extra) { + attr->extra->lcommunity = NULL; + } + /* See the longer comment down below. */ + if (old && old->refcnt == 0) + lcommunity_free(&old); + return RMAP_OKAY; + } + + if (rcs->additive && old) + { + merge = lcommunity_merge (lcommunity_dup (old), rcs->lcom); + + /* HACK: if the old large-community is not intern'd, + * we should free it here, or all reference to it may be lost. + * Really need to cleanup attribute caching sometime. + */ + if (old->refcnt == 0) + lcommunity_free (&old); + new = lcommunity_uniq_sort (merge); + lcommunity_free (&merge); + } + else + new = lcommunity_dup (rcs->lcom); + + /* will be interned by caller if required */ + if (attr->extra) { + attr->extra->lcommunity = new; + } + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + } + + return RMAP_OKAY; +} + +/* Compile function for set community. */ +static void * +route_set_lcommunity_compile (const char *arg) +{ + struct rmap_lcom_set *rcs; + struct lcommunity *lcom = NULL; + char *sp; + int additive = 0; + int none = 0; + + if (strcmp (arg, "none") == 0) + none = 1; + else + { + sp = strstr (arg, "additive"); + + if (sp && sp > arg) + { + /* "additive" keyworkd is included. */ + additive = 1; + *(sp - 1) = '\0'; + } + + lcom = lcommunity_str2com (arg); + + if (additive) + *(sp - 1) = ' '; + + if (! lcom) + return NULL; + } + + rcs = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set)); + rcs->lcom = lcom; + rcs->additive = additive; + rcs->none = none; + + return rcs; +} + +/* Free function for set lcommunity. */ +static void +route_set_lcommunity_free (void *rule) +{ + struct rmap_lcom_set *rcs = rule; + + if (rcs->lcom) { + lcommunity_free (&rcs->lcom); + } + XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_lcommunity_cmd = +{ + "large-community", + route_set_lcommunity, + route_set_lcommunity_compile, + route_set_lcommunity_free, +}; + +/* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */ + +/* For large community set mechanism. */ +static route_map_result_t +route_set_lcommunity_delete (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct community_list *list; + struct lcommunity *merge; + struct lcommunity *new; + struct lcommunity *old; + struct bgp_info *binfo; + + if (type == RMAP_BGP) + { + if (! rule) + return RMAP_OKAY; + + binfo = object; + list = community_list_lookup (bgp_clist, rule, + LARGE_COMMUNITY_LIST_MASTER); + old = ((binfo->attr->extra) ? binfo->attr->extra->lcommunity : NULL); + + if (list && old) + { + merge = lcommunity_list_match_delete (lcommunity_dup (old), list); + new = lcommunity_uniq_sort (merge); + lcommunity_free (&merge); + + /* HACK: if the old community is not intern'd, + * we should free it here, or all reference to it may be lost. + * Really need to cleanup attribute caching sometime. + */ + if (old->refcnt == 0) + lcommunity_free (&old); + + if (new->size == 0) + { + binfo->attr->extra->lcommunity = NULL; + binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + lcommunity_free (&new); + } + else + { + binfo->attr->extra->lcommunity = new; + binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + } + } + } + + return RMAP_OKAY; +} + +/* Compile function for set lcommunity. */ +static void * +route_set_lcommunity_delete_compile (const char *arg) +{ + char *p; + char *str; + int len; + + p = strchr (arg, ' '); + if (p) + { + len = p - arg; + str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); + memcpy (str, arg, len); + } + else + str = NULL; + + return str; +} + +/* Free function for set lcommunity. */ +static void +route_set_lcommunity_delete_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set lcommunity rule structure. */ +struct route_map_rule_cmd route_set_lcommunity_delete_cmd = +{ + "large-comm-list", + route_set_lcommunity_delete, + route_set_lcommunity_delete_compile, + route_set_lcommunity_delete_free, +}; + + /* `set comm-list (<1-99>|<100-500>|WORD) delete' */ /* For community set mechanism. */ @@ -3114,7 +3408,32 @@ DEFUN (no_match_community, RMAP_EVENT_CLIST_DELETED); } +DEFUN (match_lcommunity, + match_lcommunity_cmd, + "match large-community [(1-99)|(100-500)|WORD]", + MATCH_STR + "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n") +{ + return bgp_route_match_add (vty, "large-community", argv[2]->arg, + RMAP_EVENT_LLIST_ADDED); +} +DEFUN (no_match_lcommunity, + no_match_lcommunity_cmd, + "no match large-community [(1-99)|(100-500)|WORD]", + NO_STR + MATCH_STR + "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n") +{ + return bgp_route_match_delete (vty, "large-community", NULL, + RMAP_EVENT_LLIST_DELETED); +} DEFUN (match_ecommunity, match_ecommunity_cmd, @@ -3547,6 +3866,86 @@ DEFUN (no_set_community_delete, "comm-list", NULL); } +DEFUN (set_lcommunity, + set_lcommunity_cmd, + "set large-community AA:BB:CC...", + SET_STR + "BGP large community attribute\n" + "Large Community number in aa:bb:cc format or additive\n") +{ + int ret; + char *str; + + str = argv_concat (argv, argc, 2); + ret = generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), "large-community", str); + XFREE (MTYPE_TMP, str); + + return ret; +} + +DEFUN (set_lcommunity_none, + set_lcommunity_none_cmd, + "set large-community none", + SET_STR + "BGP large community attribute\n" + "No large community attribute\n") +{ + return generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), + "large-community", "none"); +} + +DEFUN (no_set_lcommunity, + no_set_lcommunity_cmd, + "no set large-community ", + NO_STR + SET_STR + "BGP large community attribute\n" + "No community attribute\n" + "Large community\n" + "Large community in AA:BB:CC... format or additive\n") +{ + return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index), + "large-community", NULL); +} + + +DEFUN (set_lcommunity_delete, + set_lcommunity_delete_cmd, + "set large-comm-list <(1-99)|(100-500)|WORD> delete", + SET_STR + "set BGP large community list (for deletion)\n" + "Large Community-list number (standard)\n" + "Large Communitly-list number (expanded)\n" + "Large Community-list name\n" + "Delete matching large communities\n") +{ + char *str; + + str = XCALLOC (MTYPE_TMP, strlen (argv[2]->arg) + strlen (" delete") + 1); + strcpy (str, argv[2]->arg); + strcpy (str + strlen (argv[2]->arg), " delete"); + + generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), + "large-comm-list", str); + + XFREE (MTYPE_TMP, str); + return CMD_SUCCESS; +} + +DEFUN (no_set_lcommunity_delete, + no_set_lcommunity_delete_cmd, + "no set large-comm-list [<(1-99|(100-500)|word)> delete]", + NO_STR + SET_STR + "set BGP large community list (for deletion)\n" + "Large Community-list number (standard)\n" + "Large Communitly-list number (expanded)\n" + "Large Community-list name\n" + "Delete matching large communities\n") +{ + return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index), + "large-comm-list", NULL); +} DEFUN (set_ecommunity_rt, set_ecommunity_rt_cmd, @@ -4002,6 +4401,7 @@ bgp_route_map_init (void) route_map_install_match (&route_match_ip_route_source_prefix_list_cmd); route_map_install_match (&route_match_aspath_cmd); route_map_install_match (&route_match_community_cmd); + route_map_install_match (&route_match_lcommunity_cmd); route_map_install_match (&route_match_ecommunity_cmd); route_map_install_match (&route_match_local_pref_cmd); route_map_install_match (&route_match_metric_cmd); @@ -4021,6 +4421,8 @@ bgp_route_map_init (void) route_map_install_set (&route_set_aggregator_as_cmd); route_map_install_set (&route_set_community_cmd); route_map_install_set (&route_set_community_delete_cmd); + route_map_install_set (&route_set_lcommunity_cmd); + route_map_install_set (&route_set_lcommunity_delete_cmd); route_map_install_set (&route_set_vpnv4_nexthop_cmd); route_map_install_set (&route_set_originator_id_cmd); route_map_install_set (&route_set_ecommunity_rt_cmd); @@ -4042,6 +4444,8 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &match_community_cmd); install_element (RMAP_NODE, &match_community_exact_cmd); install_element (RMAP_NODE, &no_match_community_cmd); + install_element (RMAP_NODE, &match_lcommunity_cmd); + install_element (RMAP_NODE, &no_match_lcommunity_cmd); install_element (RMAP_NODE, &match_ecommunity_cmd); install_element (RMAP_NODE, &no_match_ecommunity_cmd); install_element (RMAP_NODE, &match_origin_cmd); @@ -4071,6 +4475,11 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &no_set_community_cmd); install_element (RMAP_NODE, &set_community_delete_cmd); install_element (RMAP_NODE, &no_set_community_delete_cmd); + install_element (RMAP_NODE, &set_lcommunity_cmd); + install_element (RMAP_NODE, &set_lcommunity_none_cmd); + install_element (RMAP_NODE, &no_set_lcommunity_cmd); + install_element (RMAP_NODE, &set_lcommunity_delete_cmd); + install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd); install_element (RMAP_NODE, &set_ecommunity_rt_cmd); install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd); install_element (RMAP_NODE, &set_ecommunity_soo_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 6d23af03e4c2..0797756f6525 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 send-community ", + "neighbor send-community ", 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 send-community ", + "no neighbor send-community ", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n" "Send Standard and Extended Community attributes\n" + "Send Standard, Large and Extended Community attributes\n" "Send Extended Community attributes\n" - "Send Standard Community attributes\n") + "Send Standard Community attributes\n" + "Send Large Community attributes\n") { int idx_peer = 2; int idx_type = 4; @@ -3795,11 +3808,21 @@ DEFUN (no_neighbor_send_community_type, return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_EXT_COMMUNITY); + if (strncmp (argv[idx_type]->arg, "l", 1) == 0) + return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_LARGE_COMMUNITY); + if (strncmp (argv[idx_type]->arg, "b", 1) == 0) + return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty), + bgp_node_safi (vty), + PEER_FLAG_SEND_COMMUNITY | + PEER_FLAG_SEND_EXT_COMMUNITY); return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty), bgp_node_safi (vty), (PEER_FLAG_SEND_COMMUNITY | - PEER_FLAG_SEND_EXT_COMMUNITY)); + PEER_FLAG_SEND_EXT_COMMUNITY| + PEER_FLAG_SEND_LARGE_COMMUNITY)); } /* neighbor soft-reconfig. */ @@ -6132,6 +6155,12 @@ DEFUN (show_bgp_memory, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct ecommunity)), VTY_NEWLINE); + if ((count = mtype_stats_alloc (MTYPE_LCOMMUNITY))) + vty_out (vty, "%ld BGP large-community entries, using %s of memory%s", + count, + mtype_memstr (memstrbuf, sizeof (memstrbuf), + count * sizeof (struct lcommunity)), + VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_CLUSTER))) vty_out (vty, "%ld Cluster lists, using %s of memory%s", count, @@ -7109,12 +7138,16 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi, if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) vty_out (vty, " MED is propagated unchanged to this neighbor%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) - || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) + || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) + || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)) { vty_out (vty, " Community attribute sent to this neighbor"); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) - && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) - vty_out (vty, "(both)%s", VTY_NEWLINE); + && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) + && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)) + vty_out (vty, "(all)%s", VTY_NEWLINE); + else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)) + vty_out (vty, "(large)%s", VTY_NEWLINE); else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, "(extended)%s", VTY_NEWLINE); else @@ -8637,6 +8670,36 @@ DEFUN (show_ip_bgp_community_info, return CMD_SUCCESS; } +static void +lcommunity_show_all_iterator (struct hash_backet *backet, struct vty *vty) +{ + struct lcommunity *lcom; + + lcom = (struct lcommunity *) backet->data; + vty_out (vty, "[%p] (%ld) %s%s", (void *)backet, lcom->refcnt, + lcommunity_str (lcom), VTY_NEWLINE); +} + +/* Show BGP's community internal data. */ +DEFUN (show_ip_bgp_lcommunity_info, + show_ip_bgp_lcommunity_info_cmd, + "show ip bgp large-community-info", + SHOW_STR + IP_STR + BGP_STR + "List all bgp large-community information\n") +{ + vty_out (vty, "Address Refcnt Large-community%s", VTY_NEWLINE); + + hash_iterate (lcommunity_hash (), + (void (*) (struct hash_backet *, void *)) + lcommunity_show_all_iterator, + vty); + + return CMD_SUCCESS; +} + + DEFUN (show_ip_bgp_attr_info, show_ip_bgp_attr_info_cmd, "show [ip] bgp attribute-info", @@ -10738,6 +10801,8 @@ bgp_vty_init (void) /* "show [ip] bgp community" commands. */ install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd); + /* "show ip bgp large-community" commands. */ + install_element (VIEW_NODE, &show_ip_bgp_lcommunity_info_cmd); /* "show [ip] bgp attribute-info" commands. */ install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd); @@ -11070,6 +11135,324 @@ DEFUN (show_ip_community_list_arg, return CMD_SUCCESS; } +/* + * Large Community code. + */ +static int +lcommunity_list_set_vty (struct vty *vty, int argc, struct cmd_token **argv, + int style, int reject_all_digit_name) +{ + int ret; + int direct; + char *str; + int idx = 0; + char *cl_name; + + direct = argv_find (argv, argc, "permit", &idx) ? COMMUNITY_PERMIT : COMMUNITY_DENY; + + /* All digit name check. */ + idx = 0; + argv_find (argv, argc, "WORD", &idx); + argv_find (argv, argc, "(1-99)", &idx); + argv_find (argv, argc, "(100-500)", &idx); + cl_name = argv[idx]->arg; + if (reject_all_digit_name && all_digit (cl_name)) + { + vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE); + return CMD_WARNING; + } + + argv_find (argv, argc, "AA:BB:CC", &idx); + argv_find (argv, argc, "LINE", &idx); + /* Concat community string argument. */ + if (idx) + str = argv_concat (argv, argc, idx); + else + str = NULL; + + ret = lcommunity_list_set (bgp_clist, cl_name, str, direct, style); + + /* Free temporary community list string allocated by + argv_concat(). */ + if (str) + XFREE (MTYPE_TMP, str); + + if (ret < 0) + { + community_list_perror (vty, ret); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + +static int +lcommunity_list_unset_vty (struct vty *vty, int argc, struct cmd_token **argv, + int style) +{ + int ret; + int direct = 0; + char *str = NULL; + int idx = 0; + + argv_find (argv, argc, "permit", &idx); + argv_find (argv, argc, "deny", &idx); + + if (idx) + { + /* Check the list direct. */ + if (strncmp (argv[idx]->arg, "p", 1) == 0) + direct = COMMUNITY_PERMIT; + else + direct = COMMUNITY_DENY; + + idx = 0; + argv_find (argv, argc, "LINE", &idx); + argv_find (argv, argc, "AA:AA:NN", &idx); + /* Concat community string argument. */ + str = argv_concat (argv, argc, idx); + } + + idx = 0; + argv_find (argv, argc, "(1-99)", &idx); + argv_find (argv, argc, "(100-500)", &idx); + argv_find (argv, argc, "WORD", &idx); + + /* Unset community list. */ + ret = lcommunity_list_unset (bgp_clist, argv[idx]->arg, str, direct, style); + + /* Free temporary community list string allocated by + argv_concat(). */ + if (str) + XFREE (MTYPE_TMP, str); + + if (ret < 0) + { + community_list_perror (vty, ret); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* "large-community-list" keyword help string. */ +#define LCOMMUNITY_LIST_STR "Add a large community list entry\n" +#define LCOMMUNITY_VAL_STR "large community in 'aa:bb:cc' format\n" + +DEFUN (ip_lcommunity_list_standard, + ip_lcommunity_list_standard_cmd, + "ip large-community-list (1-99) [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) 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 [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 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) 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) 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 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 LINE...", + NO_STR + IP_STR + LCOMMUNITY_LIST_STR + "Specify expanded large-community-list\n" + "Large community list name\n" + "Specify large community to reject\n" + "Specify large community to accept\n" + "An ordered list as a regular-expression\n") +{ + return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); +} + +static void +lcommunity_list_show (struct vty *vty, struct community_list *list) +{ + struct community_entry *entry; + + for (entry = list->head; entry; entry = entry->next) + { + if (entry == list->head) + { + if (all_digit (list->name)) + vty_out (vty, "Large community %s list %s%s", + entry->style == EXTCOMMUNITY_LIST_STANDARD ? + "standard" : "(expanded) access", + list->name, VTY_NEWLINE); + else + vty_out (vty, "Named large community %s list %s%s", + entry->style == EXTCOMMUNITY_LIST_STANDARD ? + "standard" : "expanded", + list->name, VTY_NEWLINE); + } + if (entry->any) + vty_out (vty, " %s%s", + community_direct_str (entry->direct), VTY_NEWLINE); + else + vty_out (vty, " %s %s%s", + community_direct_str (entry->direct), + entry->style == EXTCOMMUNITY_LIST_STANDARD ? + entry->u.ecom->str : entry->config, + VTY_NEWLINE); + } +} + +DEFUN (show_ip_lcommunity_list, + show_ip_lcommunity_list_cmd, + "show ip large-community-list", + SHOW_STR + IP_STR + "List large-community list\n") +{ + struct community_list *list; + struct community_list_master *cm; + + cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER); + if (! cm) + return CMD_SUCCESS; + + for (list = cm->num.head; list; list = list->next) + lcommunity_list_show (vty, list); + + for (list = cm->str.head; list; list = list->next) + lcommunity_list_show (vty, list); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_lcommunity_list_arg, + show_ip_lcommunity_list_arg_cmd, + "show ip large-community-list <(1-500)|WORD>", + SHOW_STR + IP_STR + "List large-community list\n" + "large-community-list number\n" + "large-community-list name\n") +{ + struct community_list *list; + + list = community_list_lookup (bgp_clist, argv[3]->arg, LARGE_COMMUNITY_LIST_MASTER); + if (! list) + { + vty_out (vty, "%% Can't find extcommunity-list%s", VTY_NEWLINE); + return CMD_WARNING; + } + + lcommunity_list_show (vty, list); + + return CMD_SUCCESS; +} + /* "extcommunity-list" keyword help string. */ #define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n" #define EXTCOMMUNITY_VAL_STR "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n" @@ -11379,6 +11762,30 @@ community_list_config_write (struct vty *vty) community_list_config_str (entry), VTY_NEWLINE); write++; } + + + /* lcommunity-list. */ + cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER); + + for (list = cm->num.head; list; list = list->next) + for (entry = list->head; entry; entry = entry->next) + { + vty_out (vty, "ip large-community-list %s %s %s%s", + list->name, community_direct_str (entry->direct), + community_list_config_str (entry), VTY_NEWLINE); + write++; + } + for (list = cm->str.head; list; list = list->next) + for (entry = list->head; entry; entry = entry->next) + { + vty_out (vty, "ip large-community-list %s %s %s %s%s", + entry->style == LARGE_COMMUNITY_LIST_STANDARD + ? "standard" : "expanded", + list->name, community_direct_str (entry->direct), + community_list_config_str (entry), VTY_NEWLINE); + write++; + } + return write; } @@ -11409,4 +11816,18 @@ community_list_vty (void) install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd); install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd); install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd); + + /* Large Community List */ + install_element (CONFIG_NODE, &ip_lcommunity_list_standard_cmd); + install_element (CONFIG_NODE, &ip_lcommunity_list_expanded_cmd); + install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd); + install_element (CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_all_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_cmd); + install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_cmd); + install_element (VIEW_NODE, &show_ip_lcommunity_list_cmd); + install_element (VIEW_NODE, &show_ip_lcommunity_list_arg_cmd); } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5457822f3be6..968eebd2998c 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 2718805130c6..814bb506c814 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/lib/routemap.c b/lib/routemap.c index 74bae1fd7615..70f3069a3630 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 b52f7289b061..b378c64eae62 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, From 52951b630a4f85db81f598d2bc759c6387ff2801 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 20 Jan 2017 10:43:08 -0500 Subject: [PATCH 02/26] bgpd: Fix cli for large-communities The original commit for large communities broke 'show ip bgp' and 'show bgp ipv4 unicast' and their ilk. This commit fixes this as well as some vtysh parse errors identified. Signed-off-by: Donald Sharp --- bgpd/bgp_route.c | 120 ++++++++++++++++++++++++++++++++++++-------- bgpd/bgp_routemap.c | 24 ++++++--- bgpd/bgp_vty.c | 32 +++++++++++- 3 files changed, 146 insertions(+), 30 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 33b7bc1251d4..330e7ed52ed2 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7925,6 +7925,101 @@ bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom, 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 [ WORD] [ []] 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 [ WORD] [ []] 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, @@ -7937,8 +8032,6 @@ DEFUN (show_ip_bgp_ipv4, |filter-list WORD\ |community [ [exact-match]]\ |community-list <(1-500)|WORD> [exact-match]\ - |large-community [...]\ - |large-community-list <(1-500)|WORD>\ |A.B.C.D/M longer-prefixes\ |X:X::X:X/M longer-prefixes>\ ] [json]", @@ -7973,14 +8066,6 @@ DEFUN (show_ip_bgp_ipv4, "community-list number\n" "community-list name\n" "Exact match of the communities\n" - "Display routes matching the large-communities\n" - "large-community number\n" - "large-community number\n" - "large-community number\n" - "large-community number\n" - "Display routes matching the large-community-list\n" - "large-community-list number\n" - "large-community-list name\n" "IPv4 prefix\n" "Display route and more specific routes\n" "IPv6 prefix\n" @@ -8070,17 +8155,6 @@ DEFUN (show_ip_bgp_ipv4, exact_match = 1; return bgp_show_community_list (vty, vrf, clist_number_or_name, exact_match, afi, safi); } - else if (strmatch(argv[idx]->text, "large-community")) - { - if (strmatch(argv[idx+1]->text, "")) - return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj); - else - return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj); - } - else if (strmatch(argv[idx]->text, "large-community-list")) - { - return bgp_show_lcommunity_list (vty, bgp, argv[idx+1]->arg, afi, safi, uj); - } /* prefix-longer */ else if (argv[idx]->type == IPV4_TKN || argv[idx]->type == IPV6_TKN) return bgp_show_prefix_longer (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_longer); @@ -10720,6 +10794,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_routemap.c b/bgpd/bgp_routemap.c index c4b3ddee36b2..693a807c89a0 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3410,7 +3410,7 @@ DEFUN (no_match_community, DEFUN (match_lcommunity, match_lcommunity_cmd, - "match large-community [(1-99)|(100-500)|WORD]", + "match large-community [<(1-99)|(100-500)|WORD>]", MATCH_STR "Match BGP large community list\n" "Large Community-list number (standard)\n" @@ -3423,7 +3423,7 @@ DEFUN (match_lcommunity, DEFUN (no_match_lcommunity, no_match_lcommunity_cmd, - "no match large-community [(1-99)|(100-500)|WORD]", + "no match large-community [<(1-99)|(100-500)|WORD>]", NO_STR MATCH_STR "Match BGP large community list\n" @@ -3896,18 +3896,27 @@ DEFUN (set_lcommunity_none, DEFUN (no_set_lcommunity, no_set_lcommunity_cmd, - "no set large-community ", + "no set large-community none", NO_STR SET_STR "BGP large community attribute\n" - "No community attribute\n" - "Large community\n" - "Large community in AA:BB:CC... format or additive\n") + "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, @@ -3934,7 +3943,7 @@ DEFUN (set_lcommunity_delete, DEFUN (no_set_lcommunity_delete, no_set_lcommunity_delete_cmd, - "no set large-comm-list [<(1-99|(100-500)|word)> delete]", + "no set large-comm-list <(1-99|(100-500)|WORD)> [delete]", NO_STR SET_STR "set BGP large community list (for deletion)\n" @@ -4478,6 +4487,7 @@ bgp_route_map_init (void) 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); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 0797756f6525..b3eaaaf1113f 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -11240,7 +11240,20 @@ lcommunity_list_unset_vty (struct vty *vty, int argc, struct cmd_token **argv, DEFUN (ip_lcommunity_list_standard, ip_lcommunity_list_standard_cmd, - "ip large-community-list (1-99) [AA:BB:CC...]", + "ip large-community-list (1-99) ", + 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) AA:BB:CC...", IP_STR LCOMMUNITY_LIST_STR "Large Community list number (standard)\n" @@ -11266,7 +11279,20 @@ DEFUN (ip_lcommunity_list_expanded, DEFUN (ip_lcommunity_list_name_standard, ip_lcommunity_list_name_standard_cmd, - "ip large-community-list standard WORD [AA:BB.CC...]", + "ip large-community-list standard WORD ", + 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 AA:BB:CC...", IP_STR LCOMMUNITY_LIST_STR "Specify standard large-community-list\n" @@ -11819,8 +11845,10 @@ community_list_vty (void) /* 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); From cedb5a712431fcb6b1c2eb80d01dc3e0b9ea19f9 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Sun, 15 Jan 2017 16:43:20 -0500 Subject: [PATCH 03/26] bgpd rfapi: fix issue where advertised prefixes were not being disambiguated by RD Signed-off-by: Lou Berger --- bgpd/rfapi/rfapi.c | 2 +- bgpd/rfapi/rfapi_ap.c | 60 +++++++++++++++++--------------------- bgpd/rfapi/rfapi_ap.h | 1 + bgpd/rfapi/rfapi_private.h | 19 ------------ bgpd/rfapi/rfapi_rib.c | 18 +++++++++++- bgpd/rfapi/rfapi_rib.h | 33 +++++++++++++++++++++ bgpd/rfapi/rfapi_vty.c | 27 +++++++++-------- 7 files changed, 92 insertions(+), 68 deletions(-) diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 61da18a3084d..6353f7dacf62 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -2777,7 +2777,7 @@ rfapi_register ( NULL, action == RFAPI_REGISTER_KILL); - if (0 == rfapiApDelete (bgp, rfd, &p, pfx_mac, &adv_tunnel)) + if (0 == rfapiApDelete (bgp, rfd, &p, pfx_mac, &prd, &adv_tunnel)) { if (adv_tunnel) rfapiTunnelRouteAnnounce (bgp, rfd, &rfd->max_prefix_lifetime); diff --git a/bgpd/rfapi/rfapi_ap.c b/bgpd/rfapi/rfapi_ap.c index 4b8eb9511b36..4c415504fa3f 100644 --- a/bgpd/rfapi/rfapi_ap.c +++ b/bgpd/rfapi/rfapi_ap.c @@ -103,12 +103,11 @@ sl_adb_lifetime_cmp (void *adb1, void *adb2) return 0; } - void rfapiApInit (struct rfapi_advertised_prefixes *ap) { - ap->ipN_by_prefix = skiplist_new (0, vnc_prefix_cmp, NULL); - ap->ip0_by_ether = skiplist_new (0, vnc_prefix_cmp, NULL); + ap->ipN_by_prefix = skiplist_new (0, rfapi_rib_key_cmp, NULL); + ap->ip0_by_ether = skiplist_new (0, rfapi_rib_key_cmp, NULL); ap->by_lifetime = skiplist_new (0, sl_adb_lifetime_cmp, NULL); } @@ -192,7 +191,7 @@ rfapiApReadvertiseAll (struct bgp *bgp, struct rfapi_descriptor *rfd) * TBD this is not quite right. When pfx_ip is 0/32 or 0/128, * we need to substitute the VN address as the prefix */ - add_vnc_route (rfd, bgp, SAFI_MPLS_VPN, &adb->prefix_ip, &prd, /* RD to use (0 for ENCAP) */ + add_vnc_route (rfd, bgp, SAFI_MPLS_VPN, &adb->u.s.prefix_ip, &prd, /* RD to use (0 for ENCAP) */ &rfd->vn_addr, /* nexthop */ &local_pref, &adb->lifetime, NULL, NULL, /* struct rfapi_un_option */ NULL, /* struct rfapi_vn_option */ @@ -221,11 +220,11 @@ rfapiApWithdrawAll (struct bgp *bgp, struct rfapi_descriptor *rfd) struct prefix pfx_vn_buf; struct prefix *pfx_ip; - if (!(RFAPI_0_PREFIX (&adb->prefix_ip) && - RFAPI_HOST_PREFIX (&adb->prefix_ip))) + if (!(RFAPI_0_PREFIX (&adb->u.s.prefix_ip) && + RFAPI_HOST_PREFIX (&adb->u.s.prefix_ip))) { - pfx_ip = &adb->prefix_ip; + pfx_ip = &adb->u.s.prefix_ip; } else @@ -247,7 +246,7 @@ rfapiApWithdrawAll (struct bgp *bgp, struct rfapi_descriptor *rfd) } } - del_vnc_route (rfd, rfd->peer, bgp, SAFI_MPLS_VPN, pfx_ip ? pfx_ip : &pfx_vn_buf, &adb->prd, /* RD to use (0 for ENCAP) */ + del_vnc_route (rfd, rfd->peer, bgp, SAFI_MPLS_VPN, pfx_ip ? pfx_ip : &pfx_vn_buf, &adb->u.s.prd, /* RD to use (0 for ENCAP) */ ZEBRA_ROUTE_BGP, BGP_ROUTE_RFP, NULL, 0); } } @@ -404,19 +403,19 @@ rfapiApAdjustLifetimeStats ( { void *cursor; - struct prefix *prefix; - struct rfapi_adb *adb; + struct rfapi_rib_key rk; + struct rfapi_adb *adb; int rc; vnc_zlog_debug_verbose ("%s: walking to find new min/max", __func__); cursor = NULL; for (rc = skiplist_next (rfd->advertised.ipN_by_prefix, - (void **) &prefix, (void **) &adb, + (void **) &rk, (void **) &adb, &cursor); !rc; rc = skiplist_next (rfd->advertised.ipN_by_prefix, - (void **) &prefix, (void **) &adb, &cursor)) + (void **) &rk, (void **) &adb, &cursor)) { uint32_t lt = adb->lifetime; @@ -428,10 +427,10 @@ rfapiApAdjustLifetimeStats ( } cursor = NULL; for (rc = skiplist_next (rfd->advertised.ip0_by_ether, - (void **) &prefix, (void **) &adb, + (void **) &rk, (void **) &adb, &cursor); !rc; rc = - skiplist_next (rfd->advertised.ip0_by_ether, (void **) &prefix, + skiplist_next (rfd->advertised.ip0_by_ether, (void **) &rk, (void **) &adb, &cursor)) { @@ -483,14 +482,15 @@ rfapiApAdd ( struct rfapi_adb *adb; uint32_t old_lifetime = 0; int use_ip0 = 0; + struct rfapi_rib_key rk; + rfapi_rib_key_init(pfx_ip, prd, pfx_eth, &rk); if (RFAPI_0_PREFIX (pfx_ip) && RFAPI_HOST_PREFIX (pfx_ip)) { use_ip0 = 1; assert (pfx_eth); - rc = - skiplist_search (rfd->advertised.ip0_by_ether, pfx_eth, + skiplist_search (rfd->advertised.ip0_by_ether, &rk, (void **) &adb); } @@ -499,7 +499,7 @@ rfapiApAdd ( /* find prefix in advertised prefixes list */ rc = - skiplist_search (rfd->advertised.ipN_by_prefix, pfx_ip, + skiplist_search (rfd->advertised.ipN_by_prefix, &rk, (void **) &adb); } @@ -510,19 +510,17 @@ rfapiApAdd ( adb = XCALLOC (MTYPE_RFAPI_ADB, sizeof (struct rfapi_adb)); assert (adb); adb->lifetime = lifetime; - adb->prefix_ip = *pfx_ip; - if (pfx_eth) - adb->prefix_eth = *pfx_eth; + adb->u.key = rk; if (use_ip0) { assert (pfx_eth); - skiplist_insert (rfd->advertised.ip0_by_ether, &adb->prefix_eth, + skiplist_insert (rfd->advertised.ip0_by_ether, &adb->u.key, adb); } else { - skiplist_insert (rfd->advertised.ipN_by_prefix, &adb->prefix_ip, + skiplist_insert (rfd->advertised.ipN_by_prefix, &adb->u.key, adb); } @@ -537,19 +535,12 @@ rfapiApAdd ( adb->lifetime = lifetime; assert (!skiplist_insert (rfd->advertised.by_lifetime, adb, adb)); } - - if (!use_ip0 && pfx_eth && prefix_cmp (&adb->prefix_eth, pfx_eth)) - { - /* mac address changed */ - adb->prefix_eth = *pfx_eth; - } } adb->cost = cost; if (l2o) adb->l2o = *l2o; else memset (&adb->l2o, 0, sizeof (struct rfapi_l2address_option)); - adb->prd = *prd; if (rfapiApAdjustLifetimeStats (rfd, (rc ? NULL : &old_lifetime), &lifetime)) @@ -568,16 +559,19 @@ rfapiApDelete ( struct rfapi_descriptor *rfd, struct prefix *pfx_ip, struct prefix *pfx_eth, + struct prefix_rd *prd, int *advertise_tunnel) /* out */ { int rc; struct rfapi_adb *adb; uint32_t old_lifetime; int use_ip0 = 0; + struct rfapi_rib_key rk; if (advertise_tunnel) *advertise_tunnel = 0; + rfapi_rib_key_init(pfx_ip, prd, pfx_eth, &rk); /* find prefix in advertised prefixes list */ if (RFAPI_0_PREFIX (pfx_ip) && RFAPI_HOST_PREFIX (pfx_ip)) { @@ -585,7 +579,7 @@ rfapiApDelete ( assert (pfx_eth); rc = - skiplist_search (rfd->advertised.ip0_by_ether, pfx_eth, + skiplist_search (rfd->advertised.ip0_by_ether, &rk, (void **) &adb); } @@ -594,7 +588,7 @@ rfapiApDelete ( /* find prefix in advertised prefixes list */ rc = - skiplist_search (rfd->advertised.ipN_by_prefix, pfx_ip, + skiplist_search (rfd->advertised.ipN_by_prefix, &rk, (void **) &adb); } @@ -607,11 +601,11 @@ rfapiApDelete ( if (use_ip0) { - rc = skiplist_delete (rfd->advertised.ip0_by_ether, pfx_eth, NULL); + rc = skiplist_delete (rfd->advertised.ip0_by_ether, &rk, NULL); } else { - rc = skiplist_delete (rfd->advertised.ipN_by_prefix, pfx_ip, NULL); + rc = skiplist_delete (rfd->advertised.ipN_by_prefix, &rk, NULL); } assert (!rc); diff --git a/bgpd/rfapi/rfapi_ap.h b/bgpd/rfapi/rfapi_ap.h index f2805f49cba5..8a59f05274af 100644 --- a/bgpd/rfapi/rfapi_ap.h +++ b/bgpd/rfapi/rfapi_ap.h @@ -93,6 +93,7 @@ rfapiApDelete ( struct rfapi_descriptor *rfd, struct prefix *pfx_ip, struct prefix *pfx_eth, + struct prefix_rd *prd, int *advertise_tunnel); /* out */ diff --git a/bgpd/rfapi/rfapi_private.h b/bgpd/rfapi/rfapi_private.h index 33390c4f55f2..00f90e35fc82 100644 --- a/bgpd/rfapi/rfapi_private.h +++ b/bgpd/rfapi/rfapi_private.h @@ -34,21 +34,6 @@ #include "rfapi.h" -/* - * RFAPI Advertisement Data Block - * - * Holds NVE prefix advertisement information - */ -struct rfapi_adb -{ - struct prefix prefix_ip; - struct prefix prefix_eth; /* now redundant with l2o */ - struct prefix_rd prd; - uint32_t lifetime; - uint8_t cost; - struct rfapi_l2address_option l2o; -}; - /* * Lists of rfapi_adb. Each rfapi_adb is referenced twice: * @@ -62,7 +47,6 @@ struct rfapi_advertised_prefixes struct skiplist *by_lifetime; /* all */ }; - struct rfapi_descriptor { struct route_node *un_node; /* backref to un table */ @@ -378,9 +362,6 @@ rfp_cost_to_localpref (uint8_t cost); extern int rfapi_set_autord_from_vn (struct prefix_rd *rd, struct rfapi_ip_addr *vn); -extern void -rfapiAdbFree (struct rfapi_adb *adb); - extern struct rfapi_nexthop * rfapi_nexthop_new (struct rfapi_nexthop *copyme); diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 6aae35e6354d..3a4a1592155a 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -405,10 +405,26 @@ rfapiRibStartTimer ( assert (ri->timer); } +extern void +rfapi_rib_key_init (struct prefix *prefix, /* may be NULL */ + struct prefix_rd *rd, /* may be NULL */ + struct prefix *aux, /* may be NULL */ + struct rfapi_rib_key *rk) + +{ + memset((void *)rk, 0, sizeof(struct rfapi_rib_key)); + if (prefix) + rk->vn = *prefix; + if (rd) + rk->rd = *rd; + if (aux) + rk->aux_prefix = *aux; +} + /* * Compares two s */ -static int +int rfapi_rib_key_cmp (void *k1, void *k2) { struct rfapi_rib_key *a = (struct rfapi_rib_key *) k1; diff --git a/bgpd/rfapi/rfapi_rib.h b/bgpd/rfapi/rfapi_rib.h index 2a111946f7d8..74331a28d021 100644 --- a/bgpd/rfapi/rfapi_rib.h +++ b/bgpd/rfapi/rfapi_rib.h @@ -45,6 +45,27 @@ struct rfapi_rib_key */ struct prefix aux_prefix; }; +#include "rfapi.h" + +/* + * RFAPI Advertisement Data Block + * + * Holds NVE prefix advertisement information + */ +struct rfapi_adb +{ + union { + struct { + struct prefix prefix_ip; + struct prefix_rd prd; + struct prefix prefix_eth; + } s; /* mainly for legacy use */ + struct rfapi_rib_key key; + } u; + uint32_t lifetime; + uint8_t cost; + struct rfapi_l2address_option l2o; +}; struct rfapi_info { @@ -151,4 +172,16 @@ rfapiRibCheckCounts ( #define RFAPI_RIB_CHECK_COUNTS(checkstats, offset) #endif +extern void +rfapi_rib_key_init (struct prefix *prefix, /* may be NULL */ + struct prefix_rd *rd, /* may be NULL */ + struct prefix *aux, /* may be NULL */ + struct rfapi_rib_key *rk); + +extern int +rfapi_rib_key_cmp (void *k1, void *k2); + +extern void +rfapiAdbFree (struct rfapi_adb *adb); + #endif /* QUAGGA_HGP_RFAPI_RIB_H */ diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 3e179b7f7283..ed3155307d69 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -1846,14 +1846,14 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd) { /* group like family prefixes together in output */ - if (family != adb->prefix_ip.family) + if (family != adb->u.s.prefix_ip.family) continue; - prefix2str (&adb->prefix_ip, buf, BUFSIZ); + prefix2str (&adb->u.s.prefix_ip, buf, BUFSIZ); buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */ vty_out (vty, " Adv Pfx: %s%s", buf, HVTY_NEWLINE); - rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->prefix_ip); + rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->u.s.prefix_ip); } } for (rc = @@ -1864,14 +1864,14 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd) &cursor)) { - prefix2str (&adb->prefix_eth, buf, BUFSIZ); + prefix2str (&adb->u.s.prefix_eth, buf, BUFSIZ); buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */ vty_out (vty, " Adv Pfx: %s%s", buf, HVTY_NEWLINE); /* TBD update the following function to print ethernet info */ /* Also need to pass/use rd */ - rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->prefix_ip); + rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->u.s.prefix_ip); } vty_out (vty, "%s", HVTY_NEWLINE); } @@ -3375,7 +3375,7 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda) if (pPrefix) { - if (!prefix_same (pPrefix, &adb->prefix_ip)) + if (!prefix_same (pPrefix, &adb->u.s.prefix_ip)) { #if DEBUG_L2_EXTRA vnc_zlog_debug_verbose ("%s: adb=%p, prefix doesn't match, skipping", @@ -3388,7 +3388,7 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda) { if (memcmp (cda->l2o.o.macaddr.octet, - adb->prefix_eth.u.prefix_eth.octet, ETHER_ADDR_LEN)) + adb->u.s.prefix_eth.u.prefix_eth.octet, ETHER_ADDR_LEN)) { #if DEBUG_L2_EXTRA vnc_zlog_debug_verbose ("%s: adb=%p, macaddr doesn't match, skipping", @@ -3430,24 +3430,23 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda) this_advertisement_prefix_count = 1; - rfapiQprefix2Rprefix (&adb->prefix_ip, &rp); + rfapiQprefix2Rprefix (&adb->u.s.prefix_ip, &rp); /* if mac addr present in advert, make l2o vn option */ - if (adb->prefix_eth.family == AF_ETHERNET) + 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->prefix_eth.u.prefix_eth; + 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->prd; + vn2.v.internal_rd = adb->u.s.prd; vn1.next = &vn2; @@ -3499,7 +3498,7 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda) if (CHECK_FLAG (cda->l2o.flags, RFAPI_L2O_MACADDR)) { if (memcmp (cda->l2o.o.macaddr.octet, - adb->prefix_eth.u.prefix_eth.octet, + adb->u.s.prefix_eth.u.prefix_eth.octet, ETHER_ADDR_LEN)) { @@ -3526,7 +3525,7 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda) struct rfapi_vn_option vn; - rfapiQprefix2Rprefix (&adb->prefix_ip, &rp); + rfapiQprefix2Rprefix (&adb->u.s.prefix_ip, &rp); memset (&vn, 0, sizeof (vn)); vn.type = RFAPI_VN_OPTION_TYPE_L2ADDR; From 5ff06872e924383e2139b63e9f6e8344b183c283 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Thu, 12 Jan 2017 08:30:17 -0500 Subject: [PATCH 04/26] bgpd: add vrf-policy config using existing vnc code add add/clear vrf prefix + Modified for FRR master parser Signed-off-by: Lou Berger --- bgpd/bgp_mplsvpn.h | 8 +- bgpd/rfapi/bgp_rfapi_cfg.c | 1094 +++++++++++++++++++++++++++++------- bgpd/rfapi/bgp_rfapi_cfg.h | 23 +- bgpd/rfapi/rfapi.c | 97 ++-- bgpd/rfapi/rfapi_import.c | 13 +- bgpd/rfapi/rfapi_import.h | 2 + bgpd/rfapi/rfapi_private.h | 14 + bgpd/rfapi/rfapi_rib.c | 6 +- bgpd/rfapi/rfapi_vty.c | 623 ++++++++++++++++---- lib/command.c | 3 + lib/command.h | 1 + lib/vty.c | 1 + vtysh/vtysh.c | 39 ++ 13 files changed, 1588 insertions(+), 336 deletions(-) diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 336b73616995..234cf9baa299 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -30,6 +30,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] */ @@ -45,7 +49,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/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index ab9a24e831cf..a2b0be3cc6ce 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; @@ -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, @@ -3238,238 +3251,198 @@ static struct cmd_node bgp_vnc_nve_group_node = { }; /*------------------------------------------------------------------------- - * vnc-l2-group + * VNC nve-group + * Note there are two types of NVEs, one for VPNs one for RFP NVEs *-----------------------------------------------------------------------*/ - -DEFUN (vnc_l2_group, - vnc_l2_group_cmd, - "vnc l2-group NAME", - VNC_CONFIG_STR "Configure a L2 group\n" "Group name\n") +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); - struct rfapi_l2_group_cfg *rfg; + + 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 = bgp_rfapi_cfg_match_byname (bgp, argv[1]->arg, RFAPI_GROUP_CFG_VRF); if (!rfg) { - rfg = rfapi_l2_group_new (); + 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 L2 group%s", VTY_NEWLINE); + 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->l2_groups, rfg); } - /* * 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_VNC_L2_GROUP_NODE, rfg); - return CMD_SUCCESS; -} - -static void -bgp_rfapi_delete_l2_group ( - struct vty *vty, /* NULL = no output */ - struct bgp *bgp, - struct rfapi_l2_group_cfg *rfg) -{ - /* delete it */ - free (rfg->name); - if (rfg->rt_import_list) - ecommunity_free (&rfg->rt_import_list); - if (rfg->rt_export_list) - ecommunity_free (&rfg->rt_export_list); - if (rfg->labels) - list_delete (rfg->labels); - if (rfg->rfp_cfg) - XFREE (MTYPE_RFAPI_RFP_GROUP_CFG, rfg->rfp_cfg); - listnode_delete (bgp->rfapi_cfg->l2_groups, rfg); - - rfapi_l2_group_del (rfg); -} - -static int -bgp_rfapi_delete_named_l2_group ( - struct vty *vty, /* NULL = no output */ - struct bgp *bgp, - const char *rfg_name) /* NULL = any */ -{ - struct rfapi_l2_group_cfg *rfg = NULL; - struct listnode *node, *nnode; - - /* Search for name */ - if (rfg_name) - { - rfg = rfapi_l2_group_lookup_byname (bgp, rfg_name); - if (!rfg) - { - if (vty) - vty_out (vty, "No L2 group named \"%s\"%s", rfg_name, - VTY_NEWLINE); - return CMD_WARNING; - } - } + VTY_PUSH_CONTEXT_SUB (BGP_VRF_POLICY_NODE, rfg); - if (rfg) - bgp_rfapi_delete_l2_group (vty, bgp, rfg); - else /* must be delete all */ - for (ALL_LIST_ELEMENTS (bgp->rfapi_cfg->l2_groups, node, nnode, rfg)) - bgp_rfapi_delete_l2_group (vty, bgp, rfg); return CMD_SUCCESS; } -DEFUN (vnc_no_l2_group, - vnc_no_l2_group_cmd, - "no vnc l2-group NAME", +DEFUN (vnc_no_vrf_policy, + vnc_no_vrf_policy_cmd, + "no vrf-policy NAME", NO_STR - VNC_CONFIG_STR - "Configure a L2 group\n" - "Group name\n") + "Remove a VRF policy group\n" + "VRF name\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); - return bgp_rfapi_delete_named_l2_group (vty, bgp, argv[3]->arg); + 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_l2_group_lni, - vnc_l2_group_lni_cmd, - "logical-network-id (0-4294967295)", - "Specify Logical Network ID associated with group\n" - "value\n") +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); - VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); + + 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)) + if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg)) { /* Not in list anymore */ - vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE); + vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE); return CMD_WARNING; } - VTY_GET_INTEGER ("logical-network-id", rfg->logical_net_id, argv[1]->arg); + 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_l2_group_labels, - vnc_l2_group_labels_cmd, - "labels LABELLIST...", - "Specify label values associated with group\n" - "Space separated list of label values <0-1048575>\n") +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); - VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); - struct list *ll; /* make sure it's still in list */ - if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg)) + if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg)) { /* Not in list anymore */ - vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE); + vty_out (vty, "Current VRF group no longer exists%s", VTY_NEWLINE); return CMD_WARNING; } - ll = rfg->labels; - if (ll == NULL) + if (bgp->rfapi_cfg->rfg_redist == rfg) { - ll = list_new (); - rfg->labels = ll; + vnc_redistribute_prechange (bgp); } - argc -= 1; - argv += 1; - for (; argc; --argc, ++argv) + rfg->label = MPLS_LABEL_ILLEGAL; + + if (bgp->rfapi_cfg->rfg_redist == rfg) { - uint32_t label; - VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, 1048575); - if (!listnode_lookup (ll, (void *) (uintptr_t) label)) - listnode_add (ll, (void *) (uintptr_t) label); + vnc_redistribute_postchange (bgp); } - return CMD_SUCCESS; } -DEFUN (vnc_l2_group_no_labels, - vnc_l2_group_no_labels_cmd, - "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") +DEFUN (vnc_vrf_policy_nexthop, + vnc_vrf_policy_nexthop_cmd, + "nexthop ", + "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); - VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); - struct list *ll; /* make sure it's still in list */ - if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg)) + if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg)) { /* Not in list anymore */ - vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE); + vty_out (vty, "Current VRF no longer exists%s", VTY_NEWLINE); return CMD_WARNING; } - ll = rfg->labels; - if (ll == NULL) + if (bgp->rfapi_cfg->rfg_redist == rfg) { - vty_out (vty, "Label no longer associated with group%s", VTY_NEWLINE); - return CMD_WARNING; + vnc_redistribute_prechange (bgp); } - argc -= 2; - argv += 2; - for (; argc; --argc, ++argv) + if (!str2prefix (argv[1]->arg, &p) && p.family) { - uint32_t label; - VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, 1048575); - listnode_delete (ll, (void *) (uintptr_t) label); + //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; } -DEFUN (vnc_l2_group_rt, - vnc_l2_group_rt_cmd, - "rt ASN:nn_or_IP-address:nn", +/* 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" - "Export+import filters\n" - "Export filters\n" - "Import filters\n" - "A route target\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); - VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); - int rc = CMD_SUCCESS; - int do_import = 0; - int do_export = 0; - - switch (argv[1]->arg[0]) - { - case 'b': - do_export = 1; /* fall through */ - case 'i': - do_import = 1; - break; - case 'e': - do_export = 1; - break; - 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; + int rc; + struct listnode *node; + struct rfapi_rfg_name *rfgn; + int is_export_bgp = 0; + int is_export_zebra = 0; if (!bgp) { @@ -3478,44 +3451,596 @@ DEFUN (vnc_l2_group_rt, } /* make sure it's still in list */ - if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg)) + if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg)) { /* Not in list anymore */ - vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE); + vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE); return CMD_WARNING; } - if (do_import) - 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); - return rc; -} - - -static struct cmd_node bgp_vnc_l2_group_node = { - BGP_VNC_L2_GROUP_NODE, - "%s(config-router-vnc-l2-group)# ", - 1 -}; + rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list); + if (rc != CMD_SUCCESS) + return rc; -struct rfapi_l2_group_cfg * -bgp_rfapi_get_group_by_lni_label ( - struct bgp *bgp, - uint32_t logical_net_id, - uint32_t label) -{ - struct rfapi_l2_group_cfg *rfg; - struct listnode *node; + for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l, + node, rfgn)) + { - if (bgp->rfapi_cfg->l2_groups == NULL) /* not the best place for this */ - return NULL; + if (rfgn->rfg == rfg) + { + is_export_bgp = 1; + break; + } + } - label = label & 0xfffff; /* label is 20 bits! */ + if (is_export_bgp) + vnc_direct_bgp_del_group (bgp, rfg); - for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->l2_groups, node, rfg)) + for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn)) { - if (rfg->logical_net_id == logical_net_id) + + 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); + + 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); + + 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 (: | : | auto:nh: )\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 + *-----------------------------------------------------------------------*/ + + +DEFUN (vnc_l2_group, + vnc_l2_group_cmd, + "vnc l2-group NAME", + VNC_CONFIG_STR "Configure a L2 group\n" "Group name\n") +{ + 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[1]->arg); + + if (!rfg) + { + rfg = rfapi_l2_group_new (); + if (!rfg) + { + /* Error out of memory */ + vty_out (vty, "Can't allocate memory for L2 group%s", VTY_NEWLINE); + return CMD_WARNING; + } + rfg->name = strdup (argv[1]->arg); + /* add to tail of list */ + listnode_add (bgp->rfapi_cfg->l2_groups, rfg); + } + + /* + * 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_VNC_L2_GROUP_NODE, rfg); + return CMD_SUCCESS; +} + +static void +bgp_rfapi_delete_l2_group ( + struct vty *vty, /* NULL = no output */ + struct bgp *bgp, + struct rfapi_l2_group_cfg *rfg) +{ + /* delete it */ + free (rfg->name); + if (rfg->rt_import_list) + ecommunity_free (&rfg->rt_import_list); + if (rfg->rt_export_list) + ecommunity_free (&rfg->rt_export_list); + if (rfg->labels) + list_delete (rfg->labels); + if (rfg->rfp_cfg) + XFREE (MTYPE_RFAPI_RFP_GROUP_CFG, rfg->rfp_cfg); + listnode_delete (bgp->rfapi_cfg->l2_groups, rfg); + + rfapi_l2_group_del (rfg); +} + +static int +bgp_rfapi_delete_named_l2_group ( + struct vty *vty, /* NULL = no output */ + struct bgp *bgp, + const char *rfg_name) /* NULL = any */ +{ + struct rfapi_l2_group_cfg *rfg = NULL; + struct listnode *node, *nnode; + + /* Search for name */ + if (rfg_name) + { + rfg = rfapi_l2_group_lookup_byname (bgp, rfg_name); + if (!rfg) + { + if (vty) + vty_out (vty, "No L2 group named \"%s\"%s", rfg_name, + VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (rfg) + bgp_rfapi_delete_l2_group (vty, bgp, rfg); + else /* must be delete all */ + for (ALL_LIST_ELEMENTS (bgp->rfapi_cfg->l2_groups, node, nnode, rfg)) + bgp_rfapi_delete_l2_group (vty, bgp, rfg); + return CMD_SUCCESS; +} + +DEFUN (vnc_no_l2_group, + vnc_no_l2_group_cmd, + "no vnc l2-group NAME", + NO_STR + VNC_CONFIG_STR + "Configure a L2 group\n" + "Group 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_l2_group (vty, bgp, argv[3]->arg); +} + + +DEFUN (vnc_l2_group_lni, + vnc_l2_group_lni_cmd, + "logical-network-id <0-4294967295>", + "Specify Logical Network ID associated with group\n" + "value\n") +{ + 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)) + { + /* Not in list anymore */ + vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE); + return CMD_WARNING; + } + + VTY_GET_INTEGER ("logical-network-id", rfg->logical_net_id, argv[1]->arg); + + return CMD_SUCCESS; +} + +DEFUN (vnc_l2_group_labels, + vnc_l2_group_labels_cmd, + "labels .LABELLIST", + "Specify label values associated with group\n" + "Space separated list of label values <0-1048575>\n") +{ + 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)) + { + /* Not in list anymore */ + vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ll = rfg->labels; + if (ll == NULL) + { + ll = list_new (); + rfg->labels = ll; + } + argc--; + argv++; + for (; argc; --argc, ++argv) + { + uint32_t label; + 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); + } + + return CMD_SUCCESS; +} + +DEFUN (vnc_l2_group_no_labels, + vnc_l2_group_no_labels_cmd, + "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_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)) + { + /* Not in list anymore */ + vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ll = rfg->labels; + if (ll == NULL) + { + vty_out (vty, "Label no longer associated with group%s", VTY_NEWLINE); + return CMD_WARNING; + } + + argc-=2; + argv+=2; + for (; argc; --argc, ++argv) + { + uint32_t label; + VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, MPLS_LABEL_MAX); + listnode_delete (ll, (void *) (uintptr_t) label); + } + + return CMD_SUCCESS; +} + +DEFUN (vnc_l2_group_rt, + vnc_l2_group_rt_cmd, + "rt ASN:nn_or_IP-address:nn", + "Specify route targets\n" + "Export+import filters\n" + "Export filters\n" + "Import filters\n" + "A route target\n") +{ + 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; + + switch (argv[1]->arg[0]) + { + case 'b': + do_export = 1; /* fall through */ + case 'i': + do_import = 1; + break; + case 'e': + do_export = 1; + break; + default: + vty_out (vty, "Unknown option, %s%s", argv[1]->arg, VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + + } + 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)) + { + /* Not in list anymore */ + vty_out (vty, "Current L2 group no longer exists%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (do_import) + 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); + return rc; +} + + +static struct cmd_node bgp_vnc_l2_group_node = { + BGP_VNC_L2_GROUP_NODE, + "%s(config-router-vnc-l2-group)# ", + 1 +}; + +struct rfapi_l2_group_cfg * +bgp_rfapi_get_group_by_lni_label ( + struct bgp *bgp, + uint32_t logical_net_id, + uint32_t label) +{ + struct rfapi_l2_group_cfg *rfg; + struct listnode *node; + + if (bgp->rfapi_cfg->l2_groups == NULL) /* not the best place for this */ + return NULL; + + label = label & 0xfffff; /* label is 20 bits! */ + + for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->l2_groups, node, rfg)) + { + if (rfg->logical_net_id == logical_net_id) { struct listnode *lnode; void *data; @@ -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 897b4be76441..8f93d69f6b0f 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 6353f7dacf62..c195d09ce7f4 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; @@ -1347,7 +1353,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) @@ -1474,6 +1479,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) { @@ -1991,14 +2047,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__, @@ -2129,40 +2181,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_import.c b/bgpd/rfapi/rfapi_import.c index 26325b5816ff..5ba98e55d078 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -4943,6 +4943,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 @@ -4958,6 +4959,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, @@ -4995,7 +4997,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 @@ -5016,6 +5022,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 3cf55462a1f0..51afa0002f5a 100644 --- a/bgpd/rfapi/rfapi_import.h +++ b/bgpd/rfapi/rfapi_import.h @@ -223,6 +223,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 +239,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 00f90e35fc82..ed83ef1e1f76 100644 --- a/bgpd/rfapi/rfapi_private.h +++ b/bgpd/rfapi/rfapi_private.h @@ -135,6 +135,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) ( \ @@ -433,4 +434,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 3a4a1592155a..8e5d47415f00 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 ed3155307d69..f8142ed299c0 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -3004,9 +3004,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 +3109,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 +3174,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 +3312,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; @@ -3380,6 +3407,17 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda) #if DEBUG_L2_EXTRA vnc_zlog_debug_verbose ("%s: adb=%p, prefix doesn't match, skipping", __func__, adb); +#endif + 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; } @@ -3422,47 +3460,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 +3622,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 +3675,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 +3694,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 +3783,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 +3816,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 +3849,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 +3877,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 +3904,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 +3947,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 +3977,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 +4003,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 +4029,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 +4051,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 +4093,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 +4127,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 +4157,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 +4186,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 +4212,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 +4253,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 +4295,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 +4329,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 +4363,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 +4393,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 +5001,361 @@ DEFUN (vnc_clear_counters, return CMD_WARNING; } +/************************************************************************ + * Add prefix with vrf + * + * add [vrf ] prefix + * [rd ] [label ] [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 [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" + ": or :\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 ] prefix [rd ] + ************************************************************************/ +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 ] [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" + ": or :\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 +5379,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 +5405,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/lib/command.c b/lib/command.c index 6294e994e70c..4ac1d1abe5ff 100644 --- a/lib/command.c +++ b/lib/command.c @@ -741,6 +741,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: @@ -1106,6 +1107,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: @@ -1169,6 +1171,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: diff --git a/lib/command.h b/lib/command.h index 1e1698fc7d12..bc68cc0c849d 100644 --- a/lib/command.h +++ b/lib/command.h @@ -99,6 +99,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 */ diff --git a/lib/vty.c b/lib/vty.c index a435706d1f9d..9413d003efac 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/vtysh/vtysh.c b/vtysh/vtysh.c index 50677b56857d..51b5091c5753 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, @@ -1209,6 +1218,17 @@ DEFUNSH (VTYSH_BGPD, return CMD_SUCCESS; } +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, @@ -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); From ffc50094a6afe5ff4625f952be2873815f1b0944 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Sat, 14 Jan 2017 12:09:12 -0500 Subject: [PATCH 05/26] bgpd rfapi: add NVE/VRF name to show vnc registrations Signed-off-by: Lou Berger --- bgpd/rfapi/bgp_rfapi_cfg.c | 10 +++++----- bgpd/rfapi/rfapi_backend.h | 9 --------- bgpd/rfapi/rfapi_import.c | 4 +++- bgpd/rfapi/rfapi_import.h | 6 ++++++ bgpd/rfapi/rfapi_vty.c | 17 ++++++++++++----- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index a2b0be3cc6ce..10b365c1c87f 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -2463,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); } /* @@ -2903,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); @@ -3010,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); @@ -3494,7 +3494,7 @@ DEFUN (vnc_vrf_policy_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); @@ -3613,7 +3613,7 @@ DEFUN (vnc_vrf_policy_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); diff --git a/bgpd/rfapi/rfapi_backend.h b/bgpd/rfapi/rfapi_backend.h index 788ec73751d3..9e5b0dc5cb51 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 5ba98e55d078..235992d5bf55 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -4644,7 +4644,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; @@ -4670,6 +4671,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); diff --git a/bgpd/rfapi/rfapi_import.h b/bgpd/rfapi/rfapi_import.h index 51afa0002f5a..3ba76539dddb 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 ( diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index f8142ed299c0..7fbfae2951ae 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 From ce8080dbd8e7db3d8d761142e151e3b8018c49ba Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Sun, 22 Jan 2017 20:51:12 -0500 Subject: [PATCH 06/26] bgpd: disambiguate differet forms of show bgp ipv4 vpn address-family ipv4&6 vpn Signed-off-by: Lou Berger --- bgpd/bgp_mplsvpn.c | 8 ++++---- bgpd/bgp_vty.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index bfbddb6c30c6..ae0f0ab1dc77 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -969,7 +969,7 @@ bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd, DEFUN (show_bgp_ip_vpn_rd, show_bgp_ip_vpn_rd_cmd, - "show [ip] bgp "BGP_AFI_CMD_STR" vpn [rd ASN:nn_or_IP-address:nn] [json]", + "show bgp "BGP_AFI_CMD_STR" vpn all [rd ASN:nn_or_IP-address:nn] [json]", SHOW_STR IP_STR BGP_STR @@ -979,7 +979,7 @@ DEFUN (show_bgp_ip_vpn_rd, "VPN Route Distinguisher\n" JSON_STR) { - int idx_ext_community = 5; + int idx_rd = 5; int ret; struct prefix_rd prd; afi_t afi; @@ -987,9 +987,9 @@ DEFUN (show_bgp_ip_vpn_rd, if (argv_find_and_parse_afi (argv, argc, &idx, &afi)) { - if (argv[idx_ext_community]->arg) + if (argc >= 7 && argv[idx_rd]->arg) { - ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); + ret = str2prefix_rd (argv[idx_rd]->arg, &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index fd6718e2ac76..eba4ebf1d17c 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5586,7 +5586,6 @@ DEFUN (address_family_vpnv6, vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; } -#endif /* KEEP_OLD_VPN_COMMANDS */ DEFUN (address_family_ipv4_vpn, address_family_ipv4_vpn_cmd, @@ -5609,6 +5608,7 @@ DEFUN (address_family_ipv6_vpn, vty->node = BGP_VPNV6_NODE; return CMD_SUCCESS; } +#endif /* KEEP_OLD_VPN_COMMANDS */ DEFUN (address_family_encap, address_family_encap_cmd, @@ -10711,9 +10711,9 @@ bgp_vty_init (void) #ifdef KEEP_OLD_VPN_COMMANDS install_element (BGP_NODE, &address_family_vpnv4_cmd); install_element (BGP_NODE, &address_family_vpnv6_cmd); -#endif /* KEEP_OLD_VPN_COMMANDS */ install_element (BGP_NODE, &address_family_ipv4_vpn_cmd); install_element (BGP_NODE, &address_family_ipv6_vpn_cmd); +#endif /* KEEP_OLD_VPN_COMMANDS */ install_element (BGP_NODE, &address_family_encap_cmd); install_element (BGP_NODE, &address_family_encapv6_cmd); From 61617d382e018adf7b148bf4d18d6a0fb1fb8645 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 23 Jan 2017 21:49:21 +0100 Subject: [PATCH 07/26] lib: parser: free Mr. T Mr. T was abducted by the parser and held hostage for ransom. Murdock was called, flew in and replaced him with a Tab character. Signed-off-by: David Lamparter --- lib/command_lex.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/command_lex.l b/lib/command_lex.l index d76792626313..e245fc497668 100644 --- a/lib/command_lex.l +++ b/lib/command_lex.l @@ -47,7 +47,7 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\) %option bison-bridge %% -[ /t] /* ignore whitespace */; +[ \t] /* 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;} From 0bf5b1cbe3812e748d459fa4c4fb6596e072e7bd Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 16 Dec 2016 22:30:36 +0100 Subject: [PATCH 08/26] lib: parser: simplify OPTION_TKN & SELECTOR_TKN These are functionally identical as "fork" tokens. Signed-off-by: David Lamparter --- lib/command.c | 2 +- lib/command.h | 7 +++--- lib/command_match.c | 36 +++++++++++++--------------- lib/command_parse.y | 17 +++++++------ lib/grammar_sandbox.c | 5 ++-- lib/grammar_sandbox.h | 56 ------------------------------------------- tools/permutations.c | 2 +- 7 files changed, 33 insertions(+), 92 deletions(-) delete mode 100644 lib/grammar_sandbox.h diff --git a/lib/command.c b/lib/command.c index 6294e994e70c..cb1f54fbbd1e 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1268,7 +1268,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) diff --git a/lib/command.h b/lib/command.h index 1e1698fc7d12..dd940f0d573f 100644 --- a/lib/command.h +++ b/lib/command.h @@ -176,11 +176,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 */ diff --git a/lib/command_match.c b/lib/command_match.c index d22856324007..c3eec53bbcff 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -459,7 +459,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 +490,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 c920e11380cd..478ba0537c60 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -274,8 +274,8 @@ placeholder_token: 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); + $$->start = new_token_node (ctx, FORK_TKN, NULL, NULL); + $$->end = new_token_node (ctx, JOIN_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), @@ -329,8 +329,8 @@ selector_seq_seq: 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); + $$->start = new_token_node (ctx, FORK_TKN, NULL, NULL); + $$->end = new_token_node (ctx, JOIN_TKN, NULL, NULL); graph_add_edge ($$->start, $$->end); for (unsigned int i = 0; i < vector_active ($2->start->to); i++) { @@ -377,8 +377,8 @@ option: '[' option_token_seq ']' { // 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); + $$->start = new_token_node (ctx, FORK_TKN, NULL, NULL); + $$->end = new_token_node (ctx, JOIN_TKN, NULL, NULL); // add a path through the sequence to the end graph_add_edge ($$->start, $2->start); graph_add_edge ($2->end, $$->end); @@ -575,8 +575,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 +583,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 0239ca44ac9c..b5ac36c41fb5 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -275,9 +275,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 } diff --git a/lib/grammar_sandbox.h b/lib/grammar_sandbox.h deleted file mode 100644 index 5da0b05d09f5..000000000000 --- 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 "" - -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/tools/permutations.c b/tools/permutations.c index 8db51ee0374d..0ca980b2595b 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"); From ab037159286a3241244a6b3e7d1033e3940aa944 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 16 Dec 2016 22:34:35 +0100 Subject: [PATCH 09/26] lib: parser: track matching FORK_TKN & JOIN_TKN This associates pairs of FORK and JOIN tokens, so the merge function can identify where a subgraph begins and ends. Signed-off-by: David Lamparter --- lib/command.h | 2 ++ lib/command_parse.y | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/lib/command.h b/lib/command.h index dd940f0d573f..b71142fdce13 100644 --- a/lib/command.h +++ b/lib/command.h @@ -203,6 +203,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. */ diff --git a/lib/command_parse.y b/lib/command_parse.y index 478ba0537c60..af6497d1287a 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -276,6 +276,8 @@ selector: '<' selector_seq_seq '>' $$ = malloc (sizeof (struct subgraph)); $$->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; for (unsigned int i = 0; i < vector_active ($2->start->to); i++) { struct graph_node *sn = vector_slot ($2->start->to, i), @@ -331,6 +333,8 @@ selector: '{' selector_seq_seq '}' $$ = malloc (sizeof (struct subgraph)); $$->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, $$->end); for (unsigned int i = 0; i < vector_active ($2->start->to); i++) { @@ -379,6 +383,8 @@ option: '[' option_token_seq ']' $$ = malloc (sizeof (struct subgraph)); $$->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; // add a path through the sequence to the end graph_add_edge ($$->start, $2->start); graph_add_edge ($2->end, $$->end); From 2020b1c8a88fc4f0c0dd788261deb06ee0c670a7 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 17 Dec 2016 05:14:49 +0100 Subject: [PATCH 10/26] lib: parser: keep subgraph pointers on stack There's no need to malloc() these, we can just keep them on the stack. The entire struct will get copied around, but replacing a 2-pointer copy with a 1-pointer copy + malloc + free overhead is not quite efficient. Signed-off-by: David Lamparter --- lib/command_parse.y | 150 +++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 86 deletions(-) diff --git a/lib/command_parse.y b/lib/command_parse.y index af6497d1287a..0d3c52a6e010 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -50,13 +50,18 @@ #define YYSTYPE CMD_YYSTYPE 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 { @@ -109,11 +114,6 @@ void cmd_yyerror (struct parser_ctx *ctx, char const *msg); - /* subgraph semantic value */ - struct subgraph { - struct graph_node *start, *end; - }; - /* helper functions for parser */ static char * doc_next (struct parser_ctx *ctx); @@ -204,9 +204,8 @@ cmd_token: } | compound_token { - graph_add_edge (ctx->currnode, $1->start); - ctx->currnode = $1->end; - free ($1); + graph_add_edge (ctx->currnode, $1.start); + ctx->currnode = $1.end; } ; @@ -273,104 +272,89 @@ placeholder_token: /* productions */ selector: '<' selector_seq_seq '>' { - $$ = malloc (sizeof (struct subgraph)); - $$->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; - for (unsigned int i = 0; i < vector_active ($2->start->to); i++) + $$.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; + 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); + 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); + graph_delete_node (ctx->graph, $2.start); + graph_delete_node (ctx->graph, $2.end); }; 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); + $$.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); + graph_add_edge ($$.start, $3.start); + graph_add_edge ($3.end, $$.end); - for (unsigned int i = 0; i < vector_active ($1->start->to); i++) + 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); + 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); + graph_delete_node (ctx->graph, $1.start); + graph_delete_node (ctx->graph, $1.end); } | 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 = 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); } ; /* {keyword} productions */ selector: '{' selector_seq_seq '}' { - $$ = malloc (sizeof (struct subgraph)); - $$->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, $$->end); - for (unsigned int i = 0; i < vector_active ($2->start->to); i++) + $$.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, $$.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); + 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); + graph_delete_node (ctx->graph, $2.start); + graph_delete_node (ctx->graph, $2.end); }; selector_token_seq: simple_token { - $$ = malloc (sizeof (struct subgraph)); - $$->start = $$->end = $1; + $$.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); + graph_add_edge ($1.end, $2.start); + $$.start = $1.start; + $$.end = $2.end; } ; selector_token: simple_token { - $$ = malloc (sizeof (struct subgraph)); - $$->start = $$->end = $1; + $$.start = $$.end = $1; } | option | selector @@ -380,17 +364,15 @@ selector_token: option: '[' option_token_seq ']' { // make a new option - $$ = malloc (sizeof (struct subgraph)); - $$->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; + $$.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; // add a path through the sequence to the end - graph_add_edge ($$->start, $2->start); - graph_add_edge ($2->end, $$->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 ($$.start, $$.end); } ; @@ -398,20 +380,16 @@ 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); + graph_add_edge ($1.end, $2.start); + $$.start = $1.start; + $$.end = $2.end; } ; option_token: simple_token { - $$ = malloc (sizeof (struct subgraph)); - $$->start = $$->end = $1; + $$.start = $$.end = $1; } | compound_token ; From 663982cda7188c03472975ef412e57152744eaa5 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 17 Dec 2016 05:25:36 +0100 Subject: [PATCH 11/26] lib: parser: unify subgraphs & simplify even more This cuts a large piece of complexity from the parser by making the sequences between | the same, no matter whether it's <> () or []. This causes some changes in behaviour: - [foo|bar] is now accepted - is now accepted (yes it's stupid) - {a|b} is now means "at least one of these, in any order"; to allow zero use [{a|b}] instead. Signed-off-by: David Lamparter --- lib/command_parse.y | 117 +++++++++---------------------------------- tests/testcli.refout | 8 +-- 2 files changed, 26 insertions(+), 99 deletions(-) diff --git a/lib/command_parse.y b/lib/command_parse.y index 0d3c52a6e010..db4709172c6a 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -99,14 +99,10 @@ %type literal_token %type placeholder_token %type simple_token -%type option -%type option_token -%type option_token_seq %type selector %type selector_token %type selector_token_seq %type selector_seq_seq -%type compound_token %code { @@ -202,7 +198,7 @@ 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; @@ -214,11 +210,6 @@ simple_token: | placeholder_token ; -compound_token: - selector -| option -; - literal_token: WORD { $$ = new_token_node (ctx, WORD_TKN, strdup($1), doc_next(ctx)); @@ -272,126 +263,66 @@ placeholder_token: /* productions */ selector: '<' selector_seq_seq '>' { - $$.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; - 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); + $$ = $2; }; selector_seq_seq: selector_seq_seq '|' selector_token_seq { - $$.start = graph_new_node (ctx->graph, NULL, NULL); - $$.end = graph_new_node (ctx->graph, NULL, NULL); - - // link in last sequence + $$ = $1; 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); } -| selector_token_seq '|' selector_token_seq +| selector_token_seq { - $$.start = graph_new_node (ctx->graph, NULL, NULL); - $$.end = graph_new_node (ctx->graph, NULL, NULL); + $$.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); - graph_add_edge ($$.start, $3.start); - graph_add_edge ($3.end, $$.end); } ; /* {keyword} productions */ selector: '{' selector_seq_seq '}' { - $$.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, $$.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); + $$ = $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 -{ - $$.start = $$.end = $1; -} -| selector_token_seq selector_token -{ - graph_add_edge ($1.end, $2.start); - $$.start = $1.start; - $$.end = $2.end; -} -; - selector_token: simple_token { $$.start = $$.end = $1; } -| option | selector ; -/* [option] productions */ -option: '[' option_token_seq ']' -{ - // make a new option - $$.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; - // 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); -} -; - -option_token_seq: - option_token -| option_token_seq option_token +selector_token_seq: + selector_token_seq selector_token { graph_add_edge ($1.end, $2.start); $$.start = $1.start; $$.end = $2.end; } +| selector_token ; -option_token: - simple_token +/* [option] productions */ +selector: '[' selector_seq_seq ']' { - $$.start = $$.end = $1; + $$ = $2; + graph_add_edge ($$.start, $$.end); } -| compound_token ; %% diff --git a/tests/testcli.refout b/tests/testcli.refout index 088cbdfec423..8b438baee2aa 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 From 8bb647a8302be446e4ea4d05b98f3c656cb647d7 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sat, 17 Dec 2016 07:32:58 +0100 Subject: [PATCH 12/26] lib: parser: add error location reporting flex+bison have nice capabilities to track the location that is currently being processed; let's enable these and get better warnings for broken CLI specs. Signed-off-by: David Lamparter --- lib/command_lex.l | 12 ++++++++++- lib/command_parse.y | 52 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/lib/command_lex.l b/lib/command_lex.l index e245fc497668..703596b43dbf 100644 --- a/lib/command_lex.l +++ b/lib/command_lex.l @@ -24,6 +24,11 @@ %{ #include "command_parse.h" + +#define YY_USER_ACTION yylloc->last_column += yyleng; +#define LOC_STEP \ + yylloc->first_column = yylloc->last_column; \ + yylloc->first_line = yylloc->last_line; %} WORD (\-|\+)?[a-z0-9\*][-+_a-zA-Z0-9\*]* @@ -45,9 +50,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_parse.y b/lib/command_parse.y index db4709172c6a..cbc7ce97541b 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,6 +51,7 @@ #include "graph.h" #define YYSTYPE CMD_YYSTYPE + #define YYLTYPE CMD_YYLTYPE struct parser_ctx; /* subgraph semantic value */ @@ -108,7 +111,7 @@ /* bison declarations */ void - cmd_yyerror (struct parser_ctx *ctx, char const *msg); + cmd_yyerror (CMD_YYLTYPE *locp, struct parser_ctx *ctx, char const *msg); /* helper functions for parser */ static char * @@ -130,7 +133,7 @@ char *doc); static void - terminate_graph (struct parser_ctx *ctx, + terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx, struct graph_node *); static void @@ -169,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 '.' '.' '.' { @@ -183,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); } ; @@ -255,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); } @@ -352,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 @@ -371,7 +402,8 @@ 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 @@ -385,7 +417,7 @@ terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode) 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); From 818a5168a1c141beaa63fe887d195123a23a012e Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 5 Dec 2016 23:03:57 +0100 Subject: [PATCH 13/26] grammar_sandbox: add .dot file writing capability Writing a .dot graphviz file is very useful to get a graphical representation of the command graph. This code is intended solely for testing & development, it uses some fixed-size array and may unexpectedly crash. Signed-off-by: David Lamparter --- lib/grammar_sandbox.c | 112 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c index b5ac36c41fb5..98c75ca6e3f8 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -45,6 +45,10 @@ 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 @@ -240,6 +244,36 @@ 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", @@ -258,6 +292,7 @@ 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); @@ -345,6 +380,83 @@ pretty_print_graph (struct vty *vty, struct graph_node *start, int level, vty_out(vty, "%s", VTY_NEWLINE); } +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) +{ + // print this node + char tokennum[32]; + struct cmd_token *tok = start->data; + const char *color; + + for (size_t i = 0; i < (*visitpos); i++) + if (visited[i] == start) + return; + visited[(*visitpos)++] = start; + if ((*visitpos) == MAXDEPTH*MAXDEPTH) + return; + + snprintf(tokennum, sizeof(tokennum), "%d?", tok->type); + fprintf(ofd, " n%016llx [ shape=box, label=<", (unsigned long long)start); + + fprintf(ofd, "%s", 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, "
\"%s\"", tok->text); + else + fprintf(ofd, "
%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); + + if (stackpos == MAXDEPTH) + return; + stack[stackpos++] = start; + + 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=, 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); + } + } + } +} + + /** stuff that should go in command.c + command.h */ void init_cmdgraph (struct vty *vty, struct graph **graph) From af2567b646a9bdf22c3f47caeedc8f2de1dac81c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Fri, 16 Dec 2016 08:11:37 +0100 Subject: [PATCH 14/26] grammar_sandbox: add into daemons if DEV_BUILD Also adds "grammar access " to test/dump an existing command node (e.g. BGP_NODE). Signed-off-by: David Lamparter --- lib/Makefile.am | 3 +- lib/command.c | 6 +- lib/command.h | 4 ++ lib/grammar_sandbox.c | 123 ++++++++++--------------------------- lib/grammar_sandbox_main.c | 64 +++++++++++++++++++ 5 files changed, 109 insertions(+), 91 deletions(-) create mode 100644 lib/grammar_sandbox_main.c diff --git a/lib/Makefile.am b/lib/Makefile.am index f2c076c47579..b04872067393 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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 @@ -53,7 +54,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 cb1f54fbbd1e..6fad28ce6c42 100644 --- a/lib/command.c +++ b/lib/command.c @@ -523,7 +523,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); @@ -2398,6 +2398,10 @@ cmd_init (int terminal) vrf_install_commands (); } srandom(time(NULL)); + +#ifdef DEV_BUILD + grammar_sandbox_init(); +#endif } struct cmd_token * diff --git a/lib/command.h b/lib/command.h index b71142fdce13..3da77d3af321 100644 --- a/lib/command.h +++ b/lib/command.h @@ -422,6 +422,9 @@ 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 *); @@ -430,6 +433,7 @@ del_cmd_token (struct cmd_token *); 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/grammar_sandbox.c b/lib/grammar_sandbox.c index 98c75ca6e3f8..f92c78de5579 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. * @@ -51,13 +46,9 @@ pretty_print_dot (FILE *ofd, unsigned opts, struct graph_node *start, 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, @@ -280,11 +271,41 @@ DEFUN (grammar_init_graph, 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); @@ -297,6 +318,7 @@ void grammar_sandbox_init(void) { 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 } @@ -463,86 +485,9 @@ init_cmdgraph (struct vty *vty, struct graph **graph) { // 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); } - -int -compare_completions (const void *fst, const void *snd) -{ - struct cmd_token *first = *(struct cmd_token **) fst, - *secnd = *(struct cmd_token **) snd; - return strcmp (first->text, secnd->text); -} - -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); - } - - if (!exists) - vector_set (comps, copy_cmd_token (token)); - } - - // sort completions - qsort (comps->index, - vector_active (comps), - sizeof (void *), - &compare_completions); - - return comps; -} - -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 (); - grammar_sandbox_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/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c new file mode 100644 index 000000000000..5deef406c130 --- /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); +} From 24d812a9e3547dfd035e6b50d93a1c0ada6e1c43 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Mon, 23 Jan 2017 15:39:04 -0500 Subject: [PATCH 15/26] bgpd: restore show bgp neighbors command --- bgpd/bgp_route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 6faf4742864d..33e565d42741 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -9441,7 +9441,7 @@ peer_adj_routes (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, DEFUN (show_ip_bgp_instance_neighbor_advertised_route, show_ip_bgp_instance_neighbor_advertised_route_cmd, - "show [ip] bgp [ WORD] []|ipv6 []|encap [unicast]|vpnv4 [unicast]>] neighbors [ [route-map WORD]] [json]", + "show [ip] bgp [ WORD] []|ipv6 []|encap [unicast]|vpnv4 [unicast]>] neighbors [route-map WORD] [json]", SHOW_STR IP_STR BGP_STR From 05dbb7df2f2dfbb476f79b0e7a85a3f506f36255 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 23 Jan 2017 23:26:23 +0100 Subject: [PATCH 16/26] build: support bison < 3.0 for parse.error=verbose *sigh* Signed-off-by: David Lamparter --- configure.ac | 3 +++ lib/Makefile.am | 2 +- lib/command_parse.y | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6ce5d0cc2ce6..550ac4f92648 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 b04872067393..08d9dccb9d42 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 diff --git a/lib/command_parse.y b/lib/command_parse.y index cbc7ce97541b..dd8e6fb596d4 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -28,7 +28,7 @@ %} %locations -%define parse.error verbose +/* define parse.error verbose */ %define api.pure full /* define api.prefix {cmd_yy} */ From 14152706b42699d5665cd5291637730841e41b94 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 24 Jan 2017 02:51:00 +0100 Subject: [PATCH 17/26] lib: parser: guard yylloc yylloc seems to be NULL on parser init for some flex+bison combinations... Signed-off-by: David Lamparter --- lib/command_lex.l | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/command_lex.l b/lib/command_lex.l index 703596b43dbf..2a241abbec67 100644 --- a/lib/command_lex.l +++ b/lib/command_lex.l @@ -26,9 +26,10 @@ #include "command_parse.h" #define YY_USER_ACTION yylloc->last_column += yyleng; -#define LOC_STEP \ +#define LOC_STEP do { if (yylloc) { \ yylloc->first_column = yylloc->last_column; \ - yylloc->first_line = yylloc->last_line; + yylloc->first_line = yylloc->last_line; \ + } } while(0) %} WORD (\-|\+)?[a-z0-9\*][-+_a-zA-Z0-9\*]* From b285cf4b74312d94e8c21647205b905926af7dd8 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 23 Jan 2017 23:40:07 +0100 Subject: [PATCH 18/26] grammar_sandbox: detab Signed-off-by: David Lamparter --- lib/grammar_sandbox.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c index f92c78de5579..315bd4d59c98 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -42,8 +42,8 @@ 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); + struct graph_node **stack, size_t stackpos, + struct graph_node **visited, size_t *visitpos); void init_cmdgraph (struct vty *, struct graph **); @@ -258,8 +258,8 @@ DEFUN (grammar_test_dot, 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); + vector_slot (nodegraph->nodes, 0), + stack, 0, visited, &vpos); fprintf(ofd, "}\n"); fclose(ofd); return CMD_SUCCESS; @@ -348,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]; @@ -404,8 +404,8 @@ pretty_print_graph (struct vty *vty, struct graph_node *start, int level, 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 graph_node **stack, size_t stackpos, + struct graph_node **visited, size_t *visitpos) { // print this node char tokennum[32]; @@ -454,19 +454,19 @@ pretty_print_dot (FILE *ofd, unsigned opts, struct graph_node *start, // 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); + (unsigned long long)start, + (unsigned long long)start); } else if (((struct cmd_token *)adj->data)->type == END_TKN) { - //struct cmd_token *et = adj->data; + //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=, style = filled, fillcolor = \"#ffddaa\" ];\n", - (unsigned long long)adj); + (unsigned long long)start, + (unsigned long long)adj); + fprintf(ofd, " end%016llx [ shape=box, label=, 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); + (unsigned long long)start, + (unsigned long long)adj); size_t k; for (k = 0; k < stackpos; k++) if (stack[k] == adj) From 8fd8881c2951f166ca55095e0c01a9820a714e08 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Mon, 23 Jan 2017 23:32:01 +0100 Subject: [PATCH 19/26] zebra: fpm: fix --enable-dev-build I guess no one uses --enable-dev-build... Signed-off-by: David Lamparter --- zebra/zebra_fpm_dt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zebra/zebra_fpm_dt.c b/zebra/zebra_fpm_dt.c index bd171c89b2eb..715e250a665c 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" From 83364d20d5667c3b43e1e672d2166c22b6fd8cf5 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 25 Jan 2017 02:27:29 +0100 Subject: [PATCH 20/26] lib: parser: fix memory management command.c had: DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc") while command_match.c had: DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens") ... which means that there are 2 distinct MTYPE_CMD_TOKENS. (The description text being different does not matter, even with the same text it'd be 2 distinct types.) command_match.c allocates token->arg in command_match_r() while command.c frees it in del_cmd_token(). Therefore with each command being executed, the allocation count goes up on one, down on the other. => clean up parser allocation counting. Also, use separate MTYPEs for the different fields in struct cmd_token. Fixes: #108 / ee9216cf ("lib, ripngd: clean up merge leftovers") Signed-off-by: David Lamparter Cc: Quentin Young --- lib/command.c | 24 ++++++++++++++---------- lib/command.h | 11 +++++------ lib/command_match.c | 3 +-- lib/command_parse.y | 31 ++++++++++++++----------------- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/lib/command.c b/lib/command.c index b5dae5f28e13..781f627bb554 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. */ @@ -2405,13 +2408,14 @@ cmd_init (int terminal) } 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 +2428,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 +2443,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 1e1698fc7d12..1e490cc4cdb2 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) @@ -420,12 +421,10 @@ extern void cmd_exit (struct vty *vty); extern int cmd_list_cmds (struct vty *vty, int do_permute); /* 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 void command_parse_format (struct graph *graph, struct cmd_element *cmd); diff --git a/lib/command_match.c b/lib/command_match.c index d22856324007..aa58313134f5 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; } diff --git a/lib/command_parse.y b/lib/command_parse.y index c920e11380cd..7f98704f9074 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -115,7 +115,7 @@ }; /* helper functions for parser */ - static char * + static const char * doc_next (struct parser_ctx *ctx); static struct graph_node * @@ -130,8 +130,8 @@ 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, @@ -222,7 +222,7 @@ compound_token: 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 +230,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 @@ -462,10 +462,7 @@ terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode) // * -> 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); @@ -476,7 +473,7 @@ terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode) 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 +483,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); From c74e21947484b45ef5a484b6570ac90b4ffcd02c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 25 Jan 2017 08:20:06 -0500 Subject: [PATCH 21/26] pimd: Fix double add of command We were adding the 'ip msdp ...' command to the parser 2x. Some new code added to the parser apparently catches this for us now. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 85baa4eafe99..cfccdeba9829 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6134,8 +6134,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); From 47350fd9f4b56b3e8200ea6c8c9c8b07d0fbb9c6 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 25 Jan 2017 08:26:21 -0500 Subject: [PATCH 22/26] bgpd: Add ability to clean lcommunity hash Ensure that we don't leak any memory on shutdown. Since the bgp_lcommunity.c file mirrors bgp_ecommunity.c Add the same code for shutdown that ecommunity has. Signed-off-by: Donald Sharp --- bgpd/bgp_lcommunity.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index a4b6d96ed362..dc98809f6025 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -54,6 +54,12 @@ lcommunity_free (struct 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 @@ -287,6 +293,7 @@ lcommunity_init (void) void lcommunity_finish (void) { + hash_clean (lcomhash, (void (*)(void *))lcommunity_hash_free); hash_free (lcomhash); lcomhash = NULL; } From 5cd459e86e9df4e7716ace5f997520183f34f3b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Fingen?= Date: Wed, 25 Jan 2017 14:33:01 +0100 Subject: [PATCH 23/26] lib: Fix missing break in zlcient switch --- lib/zclient.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/zclient.c b/lib/zclient.c index a4c5fa4afba4..42fa41c9c82b 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); From a957a05bb47a8bf444ce0aee1b81d786cac9e3a9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 25 Jan 2017 09:13:46 -0500 Subject: [PATCH 24/26] pimd: Cleanup some missing help strings. Signed-off-by: Donald Sharp --- pimd/pim_cmd.c | 89 +++++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 51 deletions(-) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index cfccdeba9829..b8bb694b78d3 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 ", + "debug pim packets []", 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 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 ", - 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); From 2acb4ac250c9c7363a8ee4455677c69764f9f97c Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 25 Jan 2017 22:29:31 +0100 Subject: [PATCH 25/26] bgpd: lcommunity: fix whitespace & copyright (to match surrounding code) "git diff -w" should be almost empty. Copyright edited to say FRR, this is not GNU Zebra :) Signed-off-by: David Lamparter --- bgpd/bgp_attr.c | 48 +++++++-------- bgpd/bgp_attr.h | 2 +- bgpd/bgp_clist.c | 42 ++++++------- bgpd/bgp_lcommunity.c | 37 ++++++----- bgpd/bgp_lcommunity.h | 37 ++++++----- bgpd/bgp_route.c | 72 +++++++++++----------- bgpd/bgp_routemap.c | 140 +++++++++++++++++++++--------------------- bgpd/bgp_vty.c | 76 +++++++++++------------ 8 files changed, 225 insertions(+), 229 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index fc9440dddc8f..3a585466766d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -673,7 +673,7 @@ attrhash_key_make (void *p) if (extra) { if (extra->lcommunity) - MIX(lcommunity_hash_make (extra->lcommunity)); + MIX(lcommunity_hash_make (extra->lcommunity)); if (extra->ecommunity) MIX(ecommunity_hash_make (extra->ecommunity)); if (extra->cluster) @@ -1042,7 +1042,7 @@ bgp_attr_unintern_sub (struct attr *attr) 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)); @@ -1113,7 +1113,7 @@ 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); + lcommunity_free (&attre->lcommunity); if (attre->cluster && ! attre->cluster->refcnt) { cluster_free (attre->cluster); @@ -1272,7 +1272,7 @@ const u_int8_t attr_flags_values [] = { [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, - [BGP_ATTR_LARGE_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL + [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; @@ -3165,17 +3165,17 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, && (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); - } + { + 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_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); } @@ -3532,17 +3532,17 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, 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); - } + { + 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_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); } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 9c931051d875..c5799ccd0dd5 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -95,7 +95,7 @@ struct attr_extra /* 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 47192f0f03c6..b37034bf295b 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -43,11 +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 &ch->lcommunity_list; } return NULL; } @@ -412,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 @@ -503,14 +502,13 @@ lcommunity_str_get (struct lcommunity *lcom, int i) } /* Internal function to perform regular expression match for - * * a single community. */ + * 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. */ + /* When there is no communities attribute it is treated as empty string. */ if (lcom == NULL || lcom->size == 0) str = ""; else @@ -826,7 +824,7 @@ community_list_dup_check (struct community_list *list, break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: - case LARGE_COMMUNITY_LIST_EXPANDED: + case LARGE_COMMUNITY_LIST_EXPANDED: if (strcmp (entry->config, new->config) == 0) return 1; break; @@ -947,7 +945,7 @@ community_list_unset (struct community_list_handler *ch, /* 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_list *list) { struct community_entry *entry; u_int32_t com_index_to_delete[lcom->size]; @@ -1013,7 +1011,7 @@ lcommunity_list_match_delete (struct lcommunity *lcom, /* Set lcommunity-list. */ int lcommunity_list_set (struct community_list_handler *ch, - const char *name, const char *str, int direct, int style) + const char *name, const char *str, int direct, int style) { struct community_entry *entry = NULL; struct community_list *list; @@ -1033,22 +1031,22 @@ lcommunity_list_set (struct community_list_handler *ch, first = list->head; if (style != first->style) - { - return (first->style == COMMUNITY_LIST_STANDARD - ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT - : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); - } + { + 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); + lcom = lcommunity_str2com (str); else - regex = bgp_regcomp (str); + regex = bgp_regcomp (str); if (! lcom && ! regex) - return COMMUNITY_LIST_ERR_MALFORMED_VAL; + return COMMUNITY_LIST_ERR_MALFORMED_VAL; } entry = community_entry_new (); @@ -1077,8 +1075,8 @@ lcommunity_list_set (struct community_list_handler *ch, 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) + const char *name, const char *str, + int direct, int style) { struct community_entry *entry = NULL; struct community_list *list; diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index dc98809f6025..549a2ebad81e 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -1,23 +1,22 @@ /* BGP Large Communities Attribute - -Copyright (C) 2016 Keyur Patel - -This file is part of GNU Zebra. - -GNU Zebra is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -GNU Zebra is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Zebra; see the file COPYING. If not, write to the Free -Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ + * + * Copyright (C) 2016 Keyur Patel + * + * 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 diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h index 7841b4b9a62c..de3697f47722 100644 --- a/bgpd/bgp_lcommunity.h +++ b/bgpd/bgp_lcommunity.h @@ -1,23 +1,22 @@ /* BGP Large Communities Attribute. - -Copyright (C) 2016 Keyur Patel - -This file is part of GNU Zebra. - -GNU Zebra is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -GNU Zebra is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Zebra; see the file COPYING. If not, write to the Free -Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ + * + * Copyright (C) 2016 Keyur Patel + * + * 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 diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 330e7ed52ed2..afcf05d2b3c6 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7063,8 +7063,8 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, /* 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); + 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)) || @@ -7426,32 +7426,32 @@ bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table, if (! community_list_exact_match (ri->attr->community, list)) continue; } - if (type == bgp_show_type_community_all) - { - if (! ri->attr->community) - continue; - } - if (type == bgp_show_type_lcommunity) - { - struct lcommunity *lcom = output_arg; + if (type == bgp_show_type_community_all) + { + if (! ri->attr->community) + continue; + } + if (type == bgp_show_type_lcommunity) + { + struct lcommunity *lcom = output_arg; - if (! ri->attr->extra || ! ri->attr->extra->lcommunity || - ! lcommunity_match (ri->attr->extra->lcommunity, lcom)) - continue; - } - if (type == bgp_show_type_lcommunity_list) - { - struct community_list *list = output_arg; + if (! ri->attr->extra || ! 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 (! 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) { @@ -7870,7 +7870,7 @@ bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str, 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 cmd_token **argv, afi_t afi, safi_t safi, u_char uj) { struct lcommunity *lcom; struct buffer *b; @@ -7884,13 +7884,13 @@ bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc, if (first) buffer_putc (b, ' '); else - { - if (strmatch (argv[i]->text, "")) - { - first = 1; - buffer_putstr (b, argv[i]->arg); - } - } + { + if (strmatch (argv[i]->text, "")) + { + first = 1; + buffer_putstr (b, argv[i]->arg); + } + } } buffer_putc (b, '\0'); @@ -7910,7 +7910,7 @@ bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc, static int bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom, - afi_t afi, safi_t safi, u_char uj) + afi_t afi, safi_t safi, u_char uj) { struct community_list *list; @@ -7918,7 +7918,7 @@ bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom, if (list == NULL) { vty_out (vty, "%% %s is not a valid large-community-list name%s", lcom, - VTY_NEWLINE); + VTY_NEWLINE); return CMD_WARNING; } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 693a807c89a0..58d9b20f908f 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -853,7 +853,7 @@ struct route_map_rule_cmd route_match_community_cmd = /* 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) + route_map_object_t type, void *object) { struct community_list *list; struct bgp_info *bgp_info; @@ -865,13 +865,13 @@ route_match_lcommunity (void *rule, struct prefix *prefix, rcom = rule; list = community_list_lookup (bgp_clist, rcom->name, - LARGE_COMMUNITY_LIST_MASTER); + LARGE_COMMUNITY_LIST_MASTER); if (! list) - return RMAP_NOMATCH; + return RMAP_NOMATCH; if (bgp_info->attr->extra && - lcommunity_list_match (bgp_info->attr->extra->lcommunity, list)) - return RMAP_MATCH; + lcommunity_list_match (bgp_info->attr->extra->lcommunity, list)) + return RMAP_MATCH; } return RMAP_NOMATCH; @@ -1631,7 +1631,7 @@ struct rmap_lcom_set /* For lcommunity set mechanism. */ static route_map_result_t route_set_lcommunity (void *rule, struct prefix *prefix, - route_map_object_t type, void *object) + route_map_object_t type, void *object) { struct rmap_lcom_set *rcs; struct bgp_info *binfo; @@ -1649,37 +1649,37 @@ route_set_lcommunity (void *rule, struct prefix *prefix, /* "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; - } + { + 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); + { + merge = lcommunity_merge (lcommunity_dup (old), rcs->lcom); - /* HACK: if the old large-community is not intern'd, + /* 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); - } + if (old->refcnt == 0) + lcommunity_free (&old); + new = lcommunity_uniq_sort (merge); + lcommunity_free (&merge); + } else - new = lcommunity_dup (rcs->lcom); + new = lcommunity_dup (rcs->lcom); + + /* will be interned by caller if required */ + if (attr->extra) + attr->extra->lcommunity = new; - /* will be interned by caller if required */ - if (attr->extra) { - attr->extra->lcommunity = new; - } attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); } @@ -1703,19 +1703,19 @@ route_set_lcommunity_compile (const char *arg) sp = strstr (arg, "additive"); if (sp && sp > arg) - { - /* "additive" keyworkd is included. */ - additive = 1; - *(sp - 1) = '\0'; - } + { + /* "additive" keyworkd is included. */ + additive = 1; + *(sp - 1) = '\0'; + } lcom = lcommunity_str2com (arg); - if (additive) - *(sp - 1) = ' '; + if (additive) + *(sp - 1) = ' '; - if (! lcom) - return NULL; + if (! lcom) + return NULL; } rcs = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set)); @@ -1752,7 +1752,7 @@ struct route_map_rule_cmd route_set_lcommunity_cmd = /* 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) + route_map_object_t type, void *object) { struct community_list *list; struct lcommunity *merge; @@ -1763,38 +1763,38 @@ route_set_lcommunity_delete (void *rule, struct prefix *prefix, if (type == RMAP_BGP) { if (! rule) - return RMAP_OKAY; + return RMAP_OKAY; binfo = object; list = community_list_lookup (bgp_clist, rule, - LARGE_COMMUNITY_LIST_MASTER); + 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); + { + 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); + /* 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); - } - } + 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; @@ -3418,7 +3418,7 @@ DEFUN (match_lcommunity, "Large Community-list name\n") { return bgp_route_match_add (vty, "large-community", argv[2]->arg, - RMAP_EVENT_LLIST_ADDED); + RMAP_EVENT_LLIST_ADDED); } DEFUN (no_match_lcommunity, @@ -3432,7 +3432,7 @@ DEFUN (no_match_lcommunity, "Large Community-list name\n") { return bgp_route_match_delete (vty, "large-community", NULL, - RMAP_EVENT_LLIST_DELETED); + RMAP_EVENT_LLIST_DELETED); } DEFUN (match_ecommunity, @@ -3891,7 +3891,7 @@ DEFUN (set_lcommunity_none, "No large community attribute\n") { return generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), - "large-community", "none"); + "large-community", "none"); } DEFUN (no_set_lcommunity, @@ -3903,7 +3903,7 @@ DEFUN (no_set_lcommunity, "No community attribute\n") { return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index), - "large-community", NULL); + "large-community", NULL); } DEFUN (no_set_lcommunity1, @@ -3915,7 +3915,7 @@ DEFUN (no_set_lcommunity1, "Large community in AA:BB:CC... format or additive\n") { return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index), - "large-community", NULL); + "large-community", NULL); } DEFUN (set_lcommunity_delete, @@ -3935,7 +3935,7 @@ DEFUN (set_lcommunity_delete, strcpy (str + strlen (argv[2]->arg), " delete"); generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), - "large-comm-list", str); + "large-comm-list", str); XFREE (MTYPE_TMP, str); return CMD_SUCCESS; @@ -3953,7 +3953,7 @@ DEFUN (no_set_lcommunity_delete, "Delete matching large communities\n") { return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index), - "large-comm-list", NULL); + "large-comm-list", NULL); } DEFUN (set_ecommunity_rt, diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index b3eaaaf1113f..aa97586639c0 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6157,7 +6157,7 @@ DEFUN (show_bgp_memory, VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_LCOMMUNITY))) vty_out (vty, "%ld BGP large-community entries, using %s of memory%s", - count, + count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct lcommunity)), VTY_NEWLINE); @@ -8677,7 +8677,7 @@ lcommunity_show_all_iterator (struct hash_backet *backet, struct vty *vty) lcom = (struct lcommunity *) backet->data; vty_out (vty, "[%p] (%ld) %s%s", (void *)backet, lcom->refcnt, - lcommunity_str (lcom), VTY_NEWLINE); + lcommunity_str (lcom), VTY_NEWLINE); } /* Show BGP's community internal data. */ @@ -8692,9 +8692,9 @@ DEFUN (show_ip_bgp_lcommunity_info, vty_out (vty, "Address Refcnt Large-community%s", VTY_NEWLINE); hash_iterate (lcommunity_hash (), - (void (*) (struct hash_backet *, void *)) - lcommunity_show_all_iterator, - vty); + (void (*) (struct hash_backet *, void *)) + lcommunity_show_all_iterator, + vty); return CMD_SUCCESS; } @@ -11140,7 +11140,7 @@ DEFUN (show_ip_community_list_arg, */ static int lcommunity_list_set_vty (struct vty *vty, int argc, struct cmd_token **argv, - int style, int reject_all_digit_name) + int style, int reject_all_digit_name) { int ret; int direct; @@ -11187,7 +11187,7 @@ lcommunity_list_set_vty (struct vty *vty, int argc, struct cmd_token **argv, static int lcommunity_list_unset_vty (struct vty *vty, int argc, struct cmd_token **argv, - int style) + int style) { int ret; int direct = 0; @@ -11201,9 +11201,9 @@ lcommunity_list_unset_vty (struct vty *vty, int argc, struct cmd_token **argv, { /* Check the list direct. */ if (strncmp (argv[idx]->arg, "p", 1) == 0) - direct = COMMUNITY_PERMIT; + direct = COMMUNITY_PERMIT; else - direct = COMMUNITY_DENY; + direct = COMMUNITY_DENY; idx = 0; argv_find (argv, argc, "LINE", &idx); @@ -11409,27 +11409,27 @@ lcommunity_list_show (struct vty *vty, struct community_list *list) 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 (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); + 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); + vty_out (vty, " %s %s%s", + community_direct_str (entry->direct), + entry->style == EXTCOMMUNITY_LIST_STANDARD ? + entry->u.ecom->str : entry->config, + VTY_NEWLINE); } } @@ -11796,20 +11796,20 @@ community_list_config_write (struct vty *vty) 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++; + 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++; + 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; From ed165abf905e10b7d8b9b9989c52d9a405c513f1 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 25 Jan 2017 22:33:29 +0100 Subject: [PATCH 26/26] bgpd: lcommunity: fix minor issues - route_set_lcommunity would do nothing (and leak memory) if attr->extra wasn't up yet - an if() arch in bgp_show_table() was duplicated (with no effect) Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 5 ----- bgpd/bgp_routemap.c | 5 ++--- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index afcf05d2b3c6..06584cf681cb 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -7426,11 +7426,6 @@ bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table, if (! community_list_exact_match (ri->attr->community, list)) continue; } - if (type == bgp_show_type_community_all) - { - if (! ri->attr->community) - continue; - } if (type == bgp_show_type_lcommunity) { struct lcommunity *lcom = output_arg; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 58d9b20f908f..a3c61e21558d 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1676,9 +1676,8 @@ route_set_lcommunity (void *rule, struct prefix *prefix, else new = lcommunity_dup (rcs->lcom); - /* will be interned by caller if required */ - if (attr->extra) - attr->extra->lcommunity = new; + /* 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); }