diff options
| author | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-01-27 11:44:42 -0500 | 
|---|---|---|
| committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2017-01-27 11:44:42 -0500 | 
| commit | c016b6c796fe3a8520fdd0f30ef377cbb73e0037 (patch) | |
| tree | 78c3b29b41860c367390bba20a4a4d16fbaf3469 /bgpd | |
| parent | 75688c44d98af271ca4eb4f3133ede9e7ae709bb (diff) | |
| parent | aceb2285dad63dca7bba7177012aabdb63e1cca5 (diff) | |
Merge remote-tracking branch 'origin/master' into pr/111
Diffstat (limited to 'bgpd')
38 files changed, 4045 insertions, 916 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 69c0504af4..6e36a950d6 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -75,7 +75,8 @@ libbgp_a_SOURCES = \  	bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \  	bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \  	bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ -	bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ +	bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_lcommunity.c \ +	bgp_mplsvpn.c bgp_nexthop.c \  	bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \          bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \  	bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) @@ -85,7 +86,8 @@ noinst_HEADERS = \  	bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \  	bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \  	bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ -	bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ +	bgp_ecommunity.h bgp_lcommunity.h \ +	bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \  	bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \          bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \  	$(BGP_VNC_RFAPI_HD)  diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 87cff44293..f4995faab0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -42,6 +42,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "bgpd/bgp_debug.h"  #include "bgpd/bgp_packet.h"  #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h"  #include "bgpd/bgp_updgrp.h"  #include "bgpd/bgp_encap_types.h"  #if ENABLE_BGP_VNC @@ -76,6 +77,7 @@ static const struct message attr_str [] =  #if ENABLE_BGP_VNC    { BGP_ATTR_VNC,              "VNC" },  #endif +  { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }  };  static const int attr_str_max = array_size(attr_str); @@ -670,6 +672,8 @@ attrhash_key_make (void *p)    if (extra)      { +      if (extra->lcommunity) +        MIX(lcommunity_hash_make (extra->lcommunity));        if (extra->ecommunity)          MIX(ecommunity_hash_make (extra->ecommunity));        if (extra->cluster) @@ -718,6 +722,7 @@ attrhash_cmp (const void *p1, const void *p2)            && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)            && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)            && ae1->ecommunity == ae2->ecommunity +	  && ae1->lcommunity == ae2->lcommunity            && ae1->cluster == ae2->cluster            && ae1->transit == ae2->transit  	  && (ae1->encap_tunneltype == ae2->encap_tunneltype) @@ -836,6 +841,13 @@ bgp_attr_intern (struct attr *attr)              attre->ecommunity->refcnt++;          } +      if (attre->lcommunity) +        { +          if (! attre->lcommunity->refcnt) +            attre->lcommunity = lcommunity_intern (attre->lcommunity); +          else +            attre->lcommunity->refcnt++; +        }        if (attre->cluster)          {            if (! attre->cluster->refcnt) @@ -1026,7 +1038,11 @@ bgp_attr_unintern_sub (struct attr *attr)        if (attr->extra->ecommunity)          ecommunity_unintern (&attr->extra->ecommunity);        UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)); -       + +      if (attr->extra->lcommunity) +        lcommunity_unintern (&attr->extra->lcommunity); +      UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); +        if (attr->extra->cluster)          cluster_unintern (attr->extra->cluster);        UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST)); @@ -1096,6 +1112,8 @@ bgp_attr_flush (struct attr *attr)        if (attre->ecommunity && ! attre->ecommunity->refcnt)          ecommunity_free (&attre->ecommunity); +      if (attre->lcommunity && ! attre->lcommunity->refcnt) +        lcommunity_free (&attre->lcommunity);        if (attre->cluster && ! attre->cluster->refcnt)          {            cluster_free (attre->cluster); @@ -1254,6 +1272,7 @@ const u_int8_t attr_flags_values [] = {    [BGP_ATTR_EXT_COMMUNITIES] =  BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,    [BGP_ATTR_AS4_PATH] =         BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,    [BGP_ATTR_AS4_AGGREGATOR] =   BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, +  [BGP_ATTR_LARGE_COMMUNITIES]= BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,  };  static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1; @@ -1849,7 +1868,8 @@ int  bgp_mp_reach_parse (struct bgp_attr_parser_args *args,                      struct bgp_nlri *mp_update)  { -  afi_t pkt_afi, afi; +  iana_afi_t pkt_afi; +  afi_t  afi;    safi_t pkt_safi, safi;    bgp_size_t nlri_len;    size_t start; @@ -2000,7 +2020,8 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,  		      struct bgp_nlri *mp_withdraw)  {    struct stream *s; -  afi_t pkt_afi, afi; +  iana_afi_t pkt_afi; +  afi_t afi;    safi_t pkt_safi, safi;    u_int16_t withdraw_len;    struct peer *const peer = args->peer;   @@ -2042,6 +2063,40 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,    return BGP_ATTR_PARSE_PROCEED;  } +/* Large Community attribute. */ +static bgp_attr_parse_ret_t +bgp_attr_large_community (struct bgp_attr_parser_args *args) +{ +  struct peer *const peer = args->peer; +  struct attr *const attr = args->attr; +  const bgp_size_t length = args->length; + +  /* +   * Large community follows new attribute format. +   */ +  if (length == 0) +    { +      if (attr->extra) +        attr->extra->lcommunity = NULL; +      /* Empty extcomm doesn't seem to be invalid per se */ +      return BGP_ATTR_PARSE_PROCEED; +    } + +  (bgp_attr_extra_get (attr))->lcommunity = +    lcommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); +  /* XXX: fix ecommunity_parse to use stream API */ +  stream_forward_getp (peer->ibuf, length); + +  if (attr->extra && !attr->extra->lcommunity) +    return bgp_attr_malformed (args, +                               BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, +                               args->total); + +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); + +  return BGP_ATTR_PARSE_PROCEED; +} +  /* Extended Community attribute. */  static bgp_attr_parse_ret_t  bgp_attr_ext_communities (struct bgp_attr_parser_args *args) @@ -2063,7 +2118,7 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args)    /* XXX: fix ecommunity_parse to use stream API */    stream_forward_getp (peer->ibuf, length); -  if (!attr->extra->ecommunity) +  if (attr->extra && !attr->extra->ecommunity)      return bgp_attr_malformed (args,                                 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,                                 args->total); @@ -2477,6 +2532,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,  	case BGP_ATTR_COMMUNITIES:  	  ret = bgp_attr_community (&attr_args);  	  break; +	case BGP_ATTR_LARGE_COMMUNITIES: +	  ret = bgp_attr_large_community (&attr_args); +	  break;  	case BGP_ATTR_ORIGINATOR_ID:  	  ret = bgp_attr_originator_id (&attr_args);  	  break; @@ -2648,7 +2706,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,  			 struct attr *attr)  {    size_t sizep; -  afi_t pkt_afi; +  iana_afi_t pkt_afi;    safi_t pkt_safi;    /* Set extended bit always to encode the attribute length as 2 bytes */ @@ -3104,6 +3162,28 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,        stream_put (s, attr->community->val, attr->community->size * 4);      } +  /* +   * Large Community attribute. +   */ +  if (attr->extra && +      CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY) +      && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES))) +    { +      if (attr->extra->lcommunity->size * 12 > 255) +        { +          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); +          stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); +          stream_putw (s, attr->extra->lcommunity->size * 12); +        } +      else +        { +          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); +          stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); +          stream_putc (s, attr->extra->lcommunity->size * 12); +        } +      stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12); +    } +    /* Route Reflector. */    if (peer->sort == BGP_PEER_IBGP        && from @@ -3282,7 +3362,7 @@ size_t  bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)  {    unsigned long attrlen_pnt; -  afi_t pkt_afi; +  iana_afi_t pkt_afi;    safi_t pkt_safi;    /* Set extended bit always to encode the attribute length as 2 bytes */ @@ -3336,6 +3416,7 @@ bgp_attr_init (void)    attrhash_init ();    community_init ();    ecommunity_init (); +  lcommunity_init ();    cluster_init ();    transit_init ();    encap_init (); @@ -3348,6 +3429,7 @@ bgp_attr_finish (void)    attrhash_finish ();    community_finish ();    ecommunity_finish (); +  lcommunity_finish ();    cluster_finish ();    transit_finish ();    encap_finish (); @@ -3451,6 +3533,25 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,        stream_put (s, attr->community->val, attr->community->size * 4);      } +  /* Large Community attribute. */ +  if (attr->extra && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)) +    { +      if (attr->extra->lcommunity->size * 12 > 255) +        { +          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); +          stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); +          stream_putw (s, attr->extra->lcommunity->size * 12); +        } +      else +        { +          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); +          stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES); +          stream_putc (s, attr->extra->lcommunity->size * 12); +        } + +      stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12); +    } +    /* Add a MP_NLRI attribute to dump the IPv6 next hop */    if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&       (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL || diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 6e639078d6..c5799ccd0d 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -92,7 +92,10 @@ struct attr_extra    /* Extended Communities attribute. */    struct ecommunity *ecommunity; -   + +  /* Large Communities attribute. */ +  struct lcommunity *lcommunity; +    /* Route-Reflector Cluster attribute */    struct cluster_list *cluster; diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 9032b1e2f4..b37034bf29 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "bgpd/bgpd.h"  #include "bgpd/bgp_community.h"  #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h"  #include "bgpd/bgp_aspath.h"  #include "bgpd/bgp_regex.h"  #include "bgpd/bgp_clist.h" @@ -42,9 +43,11 @@ community_list_master_lookup (struct community_list_handler *ch, int master)      switch (master)        {        case COMMUNITY_LIST_MASTER: -	return &ch->community_list; +        return &ch->community_list;        case EXTCOMMUNITY_LIST_MASTER: -	return &ch->extcommunity_list; +        return &ch->extcommunity_list; +      case LARGE_COMMUNITY_LIST_MASTER: +        return &ch->lcommunity_list;        }    return NULL;  } @@ -66,6 +69,10 @@ community_entry_free (struct community_entry *entry)        if (entry->u.com)          community_free (entry->u.com);        break; +    case LARGE_COMMUNITY_LIST_STANDARD: +      if (entry->u.lcom) +        lcommunity_free (&entry->u.lcom); +      break;      case EXTCOMMUNITY_LIST_STANDARD:        /* In case of standard extcommunity-list, configuration string           is made by ecommunity_ecom2str().  */ @@ -76,6 +83,7 @@ community_entry_free (struct community_entry *entry)        break;      case COMMUNITY_LIST_EXPANDED:      case EXTCOMMUNITY_LIST_EXPANDED: +    case LARGE_COMMUNITY_LIST_EXPANDED:        if (entry->config)          XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);        if (entry->reg) @@ -320,8 +328,13 @@ community_list_entry_lookup (struct community_list *list, const void *arg,            if (entry->direct == direct && ecommunity_cmp (entry->u.ecom, arg))              return entry;            break; +        case LARGE_COMMUNITY_LIST_STANDARD: +          if (entry->direct == direct && lcommunity_cmp (entry->u.lcom, arg)) +            return entry; +          break;          case COMMUNITY_LIST_EXPANDED:          case EXTCOMMUNITY_LIST_EXPANDED: +        case LARGE_COMMUNITY_LIST_EXPANDED:            if (entry->direct == direct && strcmp (entry->config, arg) == 0)              return entry;            break; @@ -399,15 +412,14 @@ community_str_get (struct community *com, int i)  }  /* Internal function to perform regular expression match for - *  * a single community. */ + * a single community. */  static int  community_regexp_include (regex_t * reg, struct community *com, int i)  {    char *str;    int rv; -  /* When there is no communities attribute it is treated as empty - *      string.  */ +  /* When there is no communities attribute it is treated as empty string. */    if (com == NULL || com->size == 0)      str = XSTRDUP(MTYPE_COMMUNITY_STR, "");    else @@ -447,6 +459,90 @@ community_regexp_match (struct community *com, regex_t * reg)    return 0;  } +static char * +lcommunity_str_get (struct lcommunity *lcom, int i) +{ +  struct lcommunity_val lcomval; +  u_int32_t globaladmin; +  u_int32_t localdata1; +  u_int32_t localdata2; +  char *str; +  u_char *ptr; +  char *pnt; + +  ptr = lcom->val; +  ptr += (i * LCOMMUNITY_SIZE); + +  memcpy (&lcomval, ptr, LCOMMUNITY_SIZE); + +  /* Allocate memory.  48 bytes taken off bgp_lcommunity.c */ +  str = pnt = XMALLOC (MTYPE_LCOMMUNITY_STR, 48); + +  ptr = (u_char *)lcomval.val; +  globaladmin = (*ptr++ << 24); +  globaladmin |= (*ptr++ << 16); +  globaladmin |= (*ptr++ << 8); +  globaladmin |= (*ptr++); + +  localdata1 = (*ptr++ << 24); +  localdata1 |= (*ptr++ << 16); +  localdata1 |= (*ptr++ << 8); +  localdata1 |= (*ptr++); + +  localdata2 = (*ptr++ << 24); +  localdata2 |= (*ptr++ << 16); +  localdata2 |= (*ptr++ << 8); +  localdata2 |= (*ptr++); + +  sprintf (pnt, "%u:%u:%u", globaladmin, localdata1, localdata2); +  pnt += strlen (pnt); +  *pnt = '\0'; + +  return str; +} + +/* Internal function to perform regular expression match for + * a single community. */ +static int +lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i) +{ +  const char *str; + +  /* When there is no communities attribute it is treated as empty string. */ +  if (lcom == NULL || lcom->size == 0) +    str = ""; +  else +    str = lcommunity_str_get (lcom, i); + +  /* Regular expression match.  */ +  if (regexec (reg, str, 0, NULL, 0) == 0) +    return 1; + +  /* No match.  */ +  return 0; +} + +static int +lcommunity_regexp_match (struct lcommunity *com, regex_t * reg) +{ +  const char *str; + +  /* When there is no communities attribute it is treated as empty +     string.  */ +  if (com == NULL || com->size == 0) +    str = ""; +  else +    str = lcommunity_str (com); + +  /* Regular expression match.  */ +  if (regexec (reg, str, 0, NULL, 0) == 0) +    return 1; + +  /* No match.  */ +  return 0; +} + +  static int  ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)  { @@ -547,6 +643,30 @@ community_list_match (struct community *com, struct community_list *list)  }  int +lcommunity_list_match (struct lcommunity *lcom, struct community_list *list) +{ +  struct community_entry *entry; + +  for (entry = list->head; entry; entry = entry->next) +    { +      if (entry->any) +        return entry->direct == COMMUNITY_PERMIT ? 1 : 0; + +      if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) +        { +          if (lcommunity_match (lcom, entry->u.lcom)) +            return entry->direct == COMMUNITY_PERMIT ? 1 : 0; +        } +      else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) +        { +          if (lcommunity_regexp_match (lcom, entry->reg)) +            return entry->direct == COMMUNITY_PERMIT ? 1 : 0; +        } +    } +  return 0; +} + +int  ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)  {    struct community_entry *entry; @@ -694,12 +814,17 @@ community_list_dup_check (struct community_list *list,            if (community_cmp (entry->u.com, new->u.com))              return 1;            break; +        case LARGE_COMMUNITY_LIST_STANDARD: +          if (lcommunity_cmp (entry->u.lcom, new->u.lcom)) +            return 1; +          break;          case EXTCOMMUNITY_LIST_STANDARD:            if (ecommunity_cmp (entry->u.ecom, new->u.ecom))              return 1;            break;          case COMMUNITY_LIST_EXPANDED:          case EXTCOMMUNITY_LIST_EXPANDED: +        case LARGE_COMMUNITY_LIST_EXPANDED:            if (strcmp (entry->config, new->config) == 0)              return 1;            break; @@ -817,6 +942,185 @@ community_list_unset (struct community_list_handler *ch,    return 0;  } +/* Delete all permitted large communities in the list from com.  */ +struct lcommunity * +lcommunity_list_match_delete (struct lcommunity *lcom, +                              struct community_list *list) +{ +  struct community_entry *entry; +  u_int32_t com_index_to_delete[lcom->size]; +  u_char *ptr; +  int delete_index = 0; +  int i; + +  /* Loop over each lcommunity value and evaluate each against the +   * community-list.  If we need to delete a community value add its index to +   * com_index_to_delete. +   */ +  ptr = lcom->val; +  for (i = 0; i < lcom->size; i++) +    { +      ptr += (i * LCOMMUNITY_SIZE); +      for (entry = list->head; entry; entry = entry->next) +        { +          if (entry->any) +            { +              if (entry->direct == COMMUNITY_PERMIT) +                { +                  com_index_to_delete[delete_index] = i; +                  delete_index++; +                } +              break; +            } + +          else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) +                   && lcommunity_include (entry->u.lcom, ptr) ) +            { +              if (entry->direct == COMMUNITY_PERMIT) +                { +                  com_index_to_delete[delete_index] = i; +                  delete_index++; +                } +              break; +            } + +          else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) +                   && lcommunity_regexp_include (entry->reg, lcom, i)) +            { +              if (entry->direct == COMMUNITY_PERMIT) +                { +                  com_index_to_delete[delete_index] = i; +                  delete_index++; +                } +              break; +            } +         } +     } + +  /* Delete all of the communities we flagged for deletion */ +  ptr = lcom->val; +  for (i = delete_index-1; i >= 0; i--) +    { +      ptr += (com_index_to_delete[i] * LCOMMUNITY_SIZE); +      lcommunity_del_val (lcom, ptr); +    } + +  return lcom; +} + +/* Set lcommunity-list.  */ +int +lcommunity_list_set (struct community_list_handler *ch, +                     const char *name, const char *str, int direct, int style) +{ +  struct community_entry *entry = NULL; +  struct community_list *list; +  struct lcommunity *lcom = NULL; +  regex_t *regex = NULL; + +  /* Get community list. */ +  list = community_list_get (ch, name, LARGE_COMMUNITY_LIST_MASTER); + +  /* When community-list already has entry, new entry should have same +     style.  If you want to have mixed style community-list, you can +     comment out this check.  */ +  if (!community_list_empty_p (list)) +    { +      struct community_entry *first; + +      first = list->head; + +      if (style != first->style) +        { +          return (first->style == COMMUNITY_LIST_STANDARD +                  ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT +                  : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); +        } +    } + +  if (str) +    { +      if (style == LARGE_COMMUNITY_LIST_STANDARD) +        lcom = lcommunity_str2com (str); +      else +        regex = bgp_regcomp (str); + +      if (! lcom && ! regex) +        return COMMUNITY_LIST_ERR_MALFORMED_VAL; +    } + +  entry = community_entry_new (); +  entry->direct = direct; +  entry->style = style; +  entry->any = (str ? 0 : 1); +  entry->u.lcom = lcom; +  entry->reg = regex; +  if (lcom) +    entry->config = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST); +  else if (regex) +    entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str); +  else +    entry->config = NULL; + +  /* Do not put duplicated community entry.  */ +  if (community_list_dup_check (list, entry)) +    community_entry_free (entry); +  else +    community_list_entry_add (list, entry); + +  return 0; +} + +/* Unset community-list.  When str is NULL, delete all of +   community-list entry belongs to the specified name.  */ +int +lcommunity_list_unset (struct community_list_handler *ch, +                       const char *name, const char *str, +                       int direct, int style) +{ +  struct community_entry *entry = NULL; +  struct community_list *list; +  struct lcommunity *lcom = NULL; +  regex_t *regex = NULL; + +  /* Lookup community list.  */ +  list = community_list_lookup (ch, name, LARGE_COMMUNITY_LIST_MASTER); +  if (list == NULL) +    return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + +  /* Delete all of entry belongs to this community-list.  */ +  if (!str) +    { +      community_list_delete (list); +      return 0; +    } + +  if (style == LARGE_COMMUNITY_LIST_STANDARD) +    lcom = lcommunity_str2com (str); +  else +    regex = bgp_regcomp (str); + +  if (! lcom && ! regex) +    return COMMUNITY_LIST_ERR_MALFORMED_VAL; + +  if (lcom) +    entry = community_list_entry_lookup (list, lcom, direct); +  else +    entry = community_list_entry_lookup (list, str, direct); + +  if (lcom) +    lcommunity_free (&lcom); +  if (regex) +    bgp_regex_free (regex); + +  if (!entry) +    return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + +  community_list_entry_delete (list, entry, style); + +  return 0; +} +  /* Set extcommunity-list.  */  int  extcommunity_list_set (struct community_list_handler *ch, @@ -959,6 +1263,12 @@ community_list_terminate (struct community_list_handler *ch)    while ((list = cm->str.head) != NULL)      community_list_delete (list); +  cm = &ch->lcommunity_list; +  while ((list = cm->num.head) != NULL) +    community_list_delete (list); +  while ((list = cm->str.head) != NULL) +    community_list_delete (list); +    cm = &ch->extcommunity_list;    while ((list = cm->num.head) != NULL)      community_list_delete (list); diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h index 277ab7226c..68e45c8f7b 100644 --- a/bgpd/bgp_clist.h +++ b/bgpd/bgp_clist.h @@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  /* Master Community-list. */  #define COMMUNITY_LIST_MASTER          0  #define EXTCOMMUNITY_LIST_MASTER       1 +#define LARGE_COMMUNITY_LIST_MASTER    2  /* Community-list deny and permit.  */  #define COMMUNITY_DENY                 0 @@ -38,6 +39,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #define COMMUNITY_LIST_EXPANDED        1 /* Expanded community-list.  */  #define EXTCOMMUNITY_LIST_STANDARD     2 /* Standard extcommunity-list.  */  #define EXTCOMMUNITY_LIST_EXPANDED     3 /* Expanded extcommunity-list.  */ +#define LARGE_COMMUNITY_LIST_STANDARD  4 /* Standard Large community-list.  */ +#define LARGE_COMMUNITY_LIST_EXPANDED  5 /* Expanded Large community-list.  */  /* Community-list.  */  struct community_list @@ -80,6 +83,7 @@ struct community_entry    {      struct community *com;      struct ecommunity *ecom; +    struct lcommunity *lcom;    } u;    /* Configuration string.  */ @@ -112,6 +116,9 @@ struct community_list_handler    /* Exteded community-list.  */    struct community_list_master extcommunity_list; + +  /* Large community-list.  */ +  struct community_list_master lcommunity_list;  };  /* Error code of community-list.  */ @@ -139,6 +146,12 @@ extern int extcommunity_list_set (struct community_list_handler *ch,  extern int extcommunity_list_unset (struct community_list_handler *ch,  				    const char *name, const char *str,  				    int direct, int style, int delete_all); +extern int lcommunity_list_set (struct community_list_handler *ch, +				const char *name, const char *str, +				int direct, int style); +extern int lcommunity_list_unset (struct community_list_handler *ch, +				  const char *name, const char *str, +				  int direct, int style);  extern struct community_list_master *  community_list_master_lookup (struct community_list_handler *, int); @@ -148,9 +161,12 @@ community_list_lookup (struct community_list_handler *, const char *, int);  extern int community_list_match (struct community *, struct community_list *);  extern int ecommunity_list_match (struct ecommunity *, struct community_list *); +extern int lcommunity_list_match (struct lcommunity *, struct community_list *);  extern int community_list_exact_match (struct community *,  				       struct community_list *);  extern struct community *  community_list_match_delete (struct community *, struct community_list *); - +extern struct lcommunity * +lcommunity_list_match_delete (struct lcommunity *lcom, +			      struct community_list *list);  #endif /* _QUAGGA_BGP_CLIST_H */ diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index b65af9e1fa..6689883d94 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "bgpd/bgpd.h"  #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h"  #include "bgpd/bgp_aspath.h"  /* Hash of community attribute. */ diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c index 201f7bde06..11282a505d 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_encap.h b/bgpd/bgp_encap.h index f06dfc128c..0de737c49b 100644 --- a/bgpd/bgp_encap.h +++ b/bgpd/bgp_encap.h @@ -24,14 +24,8 @@  extern void bgp_encap_init (void);  extern int bgp_nlri_parse_encap (struct peer *, struct attr *, struct bgp_nlri *); -int -bgp_show_encap ( -                struct vty *vty, -                afi_t afi, -                struct prefix_rd *prd, -                enum bgp_show_type type, -                void *output_arg, -                int tags); +extern int bgp_show_encap (struct vty *vty, afi_t afi, struct prefix_rd *prd, +                           enum bgp_show_type type, void *output_arg, int tags);  #include "bgp_encap_types.h"  #endif /* _QUAGGA_BGP_ENCAP_H */ diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c new file mode 100644 index 0000000000..549a2ebad8 --- /dev/null +++ b/bgpd/bgp_lcommunity.c @@ -0,0 +1,569 @@ +/* BGP Large Communities Attribute + * + * Copyright (C) 2016 Keyur Patel <keyur@arrcus.com> + * + * This file is part of FreeRangeRouting (FRR). + * + * FRR is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later version. + * + * FRR is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with FRR; see the file COPYING.  If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <zebra.h> + +#include "hash.h" +#include "memory.h" +#include "prefix.h" +#include "command.h" +#include "filter.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_lcommunity.h" +#include "bgpd/bgp_aspath.h" + +/* Hash of community attribute. */ +static struct hash *lcomhash; + +/* Allocate a new lcommunities.  */ +static struct lcommunity * +lcommunity_new (void) +{ +  return (struct lcommunity *) XCALLOC (MTYPE_LCOMMUNITY, +					sizeof (struct lcommunity)); +} + +/* Allocate lcommunities.  */ +void +lcommunity_free (struct lcommunity **lcom) +{ +  if ((*lcom)->val) +    XFREE (MTYPE_LCOMMUNITY_VAL, (*lcom)->val); +  if ((*lcom)->str) +    XFREE (MTYPE_LCOMMUNITY_STR, (*lcom)->str); +  XFREE (MTYPE_LCOMMUNITY, *lcom); +  lcom = NULL; +} + +static void +lcommunity_hash_free (struct lcommunity *lcom) +{ +  lcommunity_free (&lcom); +} + +/* Add a new Large Communities value to Large Communities +   Attribute structure.  When the value is already exists in the +   structure, we don't add the value.  Newly added value is sorted by +   numerical order.  When the value is added to the structure return 1 +   else return 0.  */ +static int +lcommunity_add_val (struct lcommunity *lcom, struct lcommunity_val *lval) +{ +  u_int8_t *p; +  int ret; +  int c; + +  /* When this is fist value, just add it.  */ +  if (lcom->val == NULL) +    { +      lcom->size++; +      lcom->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom_length (lcom)); +      memcpy (lcom->val, lval->val, LCOMMUNITY_SIZE); +      return 1; +    } + +  /* If the value already exists in the structure return 0.  */ +  c = 0; +  for (p = lcom->val; c < lcom->size; p += LCOMMUNITY_SIZE, c++) +    { +      ret = memcmp (p, lval->val, LCOMMUNITY_SIZE); +      if (ret == 0) +        return 0; +      if (ret > 0) +        break; +    } + +  /* Add the value to the structure with numerical sorting.  */ +  lcom->size++; +  lcom->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom->val, lcom_length (lcom)); + +  memmove (lcom->val + (c + 1) * LCOMMUNITY_SIZE, +	   lcom->val + c * LCOMMUNITY_SIZE, +	   (lcom->size - 1 - c) * LCOMMUNITY_SIZE); +  memcpy (lcom->val + c * LCOMMUNITY_SIZE, lval->val, LCOMMUNITY_SIZE); + +  return 1; +} + +/* This function takes pointer to Large Communites strucutre then +   create a new Large Communities structure by uniq and sort each +   Large Communities value.  */ +struct lcommunity * +lcommunity_uniq_sort (struct lcommunity *lcom) +{ +  int i; +  struct lcommunity *new; +  struct lcommunity_val *lval; + +  if (! lcom) +    return NULL; + +  new = lcommunity_new (); + +  for (i = 0; i < lcom->size; i++) +    { +      lval = (struct lcommunity_val *) (lcom->val + (i * LCOMMUNITY_SIZE)); +      lcommunity_add_val (new, lval); +    } +  return new; +} + +/* Parse Large Communites Attribute in BGP packet.  */ +struct lcommunity * +lcommunity_parse (u_int8_t *pnt, u_short length) +{ +  struct lcommunity tmp; +  struct lcommunity *new; + +  /* Length check.  */ +  if (length % LCOMMUNITY_SIZE) +    return NULL; + +  /* Prepare tmporary structure for making a new Large Communities +     Attribute.  */ +  tmp.size = length / LCOMMUNITY_SIZE; +  tmp.val = pnt; + +  /* Create a new Large Communities Attribute by uniq and sort each +     Large Communities value  */ +  new = lcommunity_uniq_sort (&tmp); + +  return lcommunity_intern (new); +} + +/* Duplicate the Large Communities Attribute structure.  */ +struct lcommunity * +lcommunity_dup (struct lcommunity *lcom) +{ +  struct lcommunity *new; + +  new = XCALLOC (MTYPE_LCOMMUNITY, sizeof (struct lcommunity)); +  new->size = lcom->size; +  if (new->size) +    { +      new->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom->size * LCOMMUNITY_SIZE); +      memcpy (new->val, lcom->val, lcom->size * LCOMMUNITY_SIZE); +    } +  else +    new->val = NULL; +  return new; +} + +/* Retrun string representation of communities attribute. */ +char * +lcommunity_str (struct lcommunity *lcom) +{ +  if (! lcom->str) +    lcom->str = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_DISPLAY); +  return lcom->str; +} + +/* Merge two Large Communities Attribute structure.  */ +struct lcommunity * +lcommunity_merge (struct lcommunity *lcom1, struct lcommunity *lcom2) +{ +  if (lcom1->val) +    lcom1->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom1->val, +			   (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE); +  else +    lcom1->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, +			  (lcom1->size + lcom2->size) * LCOMMUNITY_SIZE); + +  memcpy (lcom1->val + (lcom1->size * LCOMMUNITY_SIZE), +	  lcom2->val, lcom2->size * LCOMMUNITY_SIZE); +  lcom1->size += lcom2->size; + +  return lcom1; +} + +/* Intern Large Communities Attribute.  */ +struct lcommunity * +lcommunity_intern (struct lcommunity *lcom) +{ +  struct lcommunity *find; + +  assert (lcom->refcnt == 0); + +  find = (struct lcommunity *) hash_get (lcomhash, lcom, hash_alloc_intern); + +  if (find != lcom) +    lcommunity_free (&lcom); + +  find->refcnt++; + +  if (! find->str) +    find->str = lcommunity_lcom2str (find, LCOMMUNITY_FORMAT_DISPLAY); + +  return find; +} + +/* Unintern Large Communities Attribute.  */ +void +lcommunity_unintern (struct lcommunity **lcom) +{ +  struct lcommunity *ret; + +  if ((*lcom)->refcnt) +    (*lcom)->refcnt--; + +  /* Pull off from hash.  */ +  if ((*lcom)->refcnt == 0) +    { +      /* Large community must be in the hash.  */ +      ret = (struct lcommunity *) hash_release (lcomhash, *lcom); +      assert (ret != NULL); + +      lcommunity_free (lcom); +    } +} + +/* Utility function to make hash key.  */ +unsigned int +lcommunity_hash_make (void *arg) +{ +  const struct lcommunity *lcom = arg; +  int size = lcom->size * LCOMMUNITY_SIZE; +  u_int8_t *pnt = lcom->val; +  unsigned int key = 0; +  int c; + +  for (c = 0; c < size; c += LCOMMUNITY_SIZE) +    { +      key += pnt[c]; +      key += pnt[c + 1]; +      key += pnt[c + 2]; +      key += pnt[c + 3]; +      key += pnt[c + 4]; +      key += pnt[c + 5]; +      key += pnt[c + 6]; +      key += pnt[c + 7]; +      key += pnt[c + 8]; +      key += pnt[c + 9]; +      key += pnt[c + 10]; +      key += pnt[c + 11]; +    } + +  return key; +} + +/* Compare two Large Communities Attribute structure.  */ +int +lcommunity_cmp (const void *arg1, const void *arg2) +{ +  const struct lcommunity *lcom1 = arg1; +  const struct lcommunity *lcom2 = arg2; + +  return (lcom1->size == lcom2->size +	  && memcmp (lcom1->val, lcom2->val, lcom1->size * LCOMMUNITY_SIZE) == 0); +} + +/* Return communities hash.  */ +struct hash * +lcommunity_hash (void) +{ +  return lcomhash; +} + +/* Initialize Large Comminities related hash. */ +void +lcommunity_init (void) +{ +  lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp); +} + +void +lcommunity_finish (void) +{ +  hash_clean (lcomhash, (void (*)(void *))lcommunity_hash_free); +  hash_free (lcomhash); +  lcomhash = NULL; +} + +/* Large Communities token enum. */ +enum lcommunity_token +{ +  lcommunity_token_unknown = 0, +  lcommunity_token_val, +}; + +/* Get next Large Communities token from the string. */ +static const char * +lcommunity_gettoken (const char *str, struct lcommunity_val *lval, +		     enum lcommunity_token *token) +{ +  const char *p = str; + +  /* Skip white space. */ +  while (isspace ((int) *p)) +    { +      p++; +      str++; +    } + +  /* Check the end of the line. */ +  if (*p == '\0') +    return NULL; + +  /* Community value. */ +  if (isdigit ((int) *p)) +    { +      int separator = 0; +      int digit = 0; +      u_int32_t globaladmin = 0; +      u_int32_t localdata1 = 0; +      u_int32_t localdata2 = 0; + +      while (isdigit ((int) *p) || *p == ':') +	{ +	  if (*p == ':') +	    { +	      if (separator == 2) +		{ +		  *token = lcommunity_token_unknown; +		  return NULL; +		} +	      else +		{ +		  separator++; +		  digit = 0; +		  if (separator == 1) { +		    globaladmin = localdata2; +		  } else { +		    localdata1 = localdata2; +		  } +		  localdata2 = 0; +		} +	    } +	  else +	    { +	      digit = 1; +	      localdata2 *= 10; +	      localdata2 += (*p - '0'); +	    } +	  p++; +	} +      if (! digit) +	{ +	  *token = lcommunity_token_unknown; +	  return NULL; +	} + +      /* +       * Copy the large comm. +       */ +      lval->val[0] = (globaladmin >> 24) & 0xff; +      lval->val[1] = (globaladmin >> 16) & 0xff; +      lval->val[2] = (globaladmin >> 8) & 0xff; +      lval->val[3] = globaladmin & 0xff; +      lval->val[4] = (localdata1 >> 24) & 0xff; +      lval->val[5] = (localdata1 >> 16) & 0xff; +      lval->val[6] = (localdata1 >> 8) & 0xff; +      lval->val[7] = localdata1 & 0xff; +      lval->val[8] = (localdata2 >> 24) & 0xff; +      lval->val[9] = (localdata2 >> 16) & 0xff; +      lval->val[10] = (localdata2 >> 8) & 0xff; +      lval->val[11] = localdata2 & 0xff; + +      *token = lcommunity_token_val; +      return p; +    } +  *token = lcommunity_token_unknown; +  return p; +} + +/* +  Convert string to large community attribute. +  When type is already known, please specify both str and type. + +  When string includes keyword for each large community value. +  Please specify keyword_included as non-zero value. +*/ +struct lcommunity * +lcommunity_str2com (const char *str) +{ +    struct lcommunity *lcom = NULL; +    enum lcommunity_token token = lcommunity_token_unknown; +    struct lcommunity_val lval; + +    while ((str = lcommunity_gettoken (str, &lval, &token))) +    { +        switch (token) +        { +            case lcommunity_token_val: +                if (lcom == NULL) +                    lcom = lcommunity_new (); +                lcommunity_add_val (lcom, &lval); +                break; +            case lcommunity_token_unknown: +            default: +                if (lcom) +                    lcommunity_free (&lcom); +                return NULL; +        } +    } +    return lcom; +} + +int +lcommunity_include (struct lcommunity *lcom, u_char *ptr) +{ +  int i; +  u_char *lcom_ptr; + +  lcom_ptr = lcom->val; +  for (i = 0; i < lcom->size; i++) { +    lcom_ptr += (i * LCOMMUNITY_SIZE); +    if (memcmp (ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0) +      return 1; +  } +  return 0; +} + +/* Convert large community attribute to string. +   The large coms will be in 65535:65531:0 format. +*/ +char * +lcommunity_lcom2str (struct lcommunity *lcom, int format) +{ +  int i; +  u_int8_t *pnt; +#define LCOMMUNITY_STR_DEFAULT_LEN  40 +  int str_size; +  int str_pnt; +  char *str_buf; +  int len = 0; +  int first = 1; +  u_int32_t  globaladmin, localdata1, localdata2; + +  if (lcom->size == 0) +    { +      str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, 1); +      str_buf[0] = '\0'; +      return str_buf; +    } + +  /* Prepare buffer.  */ +  str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, LCOMMUNITY_STR_DEFAULT_LEN + 1); +  str_size = LCOMMUNITY_STR_DEFAULT_LEN + 1; +  str_pnt = 0; + +  for (i = 0; i < lcom->size; i++) +    { +      /* Make it sure size is enough.  */ +      while (str_pnt + LCOMMUNITY_STR_DEFAULT_LEN >= str_size) +	{ +	  str_size *= 2; +	  str_buf = XREALLOC (MTYPE_LCOMMUNITY_STR, str_buf, str_size); +	} + +      /* Space between each value.  */ +      if (! first) +	str_buf[str_pnt++] = ' '; + +      pnt = lcom->val + (i * 12); + +      globaladmin = (*pnt++ << 24); +      globaladmin |= (*pnt++ << 16); +      globaladmin |= (*pnt++ << 8); +      globaladmin |= (*pnt++); + +      localdata1 = (*pnt++ << 24); +      localdata1 |= (*pnt++ << 16); +      localdata1 |= (*pnt++ << 8); +      localdata1 |= (*pnt++); + +      localdata2 = (*pnt++ << 24); +      localdata2 |= (*pnt++ << 16); +      localdata2 |= (*pnt++ << 8); +      localdata2 |= (*pnt++); + +      len = sprintf( str_buf + str_pnt, "%u:%u:%u", globaladmin, +		     localdata1, localdata2); +      str_pnt += len; +      first = 0; +    } +  return str_buf; +} + +int +lcommunity_match (const struct lcommunity *lcom1, +                  const struct lcommunity *lcom2) +{ +  int i = 0; +  int j = 0; + +  if (lcom1 == NULL && lcom2 == NULL) +    return 1; + +  if (lcom1 == NULL || lcom2 == NULL) +    return 0; + +  if (lcom1->size < lcom2->size) +    return 0; + +  /* Every community on com2 needs to be on com1 for this to match */ +  while (i < lcom1->size && j < lcom2->size) +    { +      if (memcmp (lcom1->val + (i*12), lcom2->val + (j*12), LCOMMUNITY_SIZE) == 0) +        j++; +      i++; +    } + +  if (j == lcom2->size) +    return 1; +  else +    return 0; +} + +/* Delete one lcommunity. */ +void +lcommunity_del_val (struct lcommunity *lcom, u_char *ptr) +{ +  int i = 0; +  int c = 0; + +  if (! lcom->val) +    return; + +  while (i < lcom->size) +    { +      if (memcmp (lcom->val + i*LCOMMUNITY_SIZE, ptr, LCOMMUNITY_SIZE) == 0) +	{ +	  c = lcom->size -i -1; + +	  if (c > 0) +	    memmove (lcom->val + i*LCOMMUNITY_SIZE, lcom->val + (i + 1)*LCOMMUNITY_SIZE, c * LCOMMUNITY_SIZE); + +	  lcom->size--; + +	  if (lcom->size > 0) +	    lcom->val = XREALLOC (MTYPE_COMMUNITY_VAL, lcom->val, +				 lcom_length (lcom)); +	  else +	    { +	      XFREE (MTYPE_COMMUNITY_VAL, lcom->val); +	      lcom->val = NULL; +	    } +	  return; +	} +      i++; +    } +} diff --git a/bgpd/bgp_lcommunity.h b/bgpd/bgp_lcommunity.h new file mode 100644 index 0000000000..de3697f477 --- /dev/null +++ b/bgpd/bgp_lcommunity.h @@ -0,0 +1,74 @@ +/* BGP Large Communities Attribute. + * + * Copyright (C) 2016 Keyur Patel <keyur@arrcus.com> + * + * This file is part of FreeRangeRouting (FRR). + * + * FRR is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later version. + * + * FRR is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with FRR; see the file COPYING.  If not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _QUAGGA_BGP_LCOMMUNITY_H +#define _QUAGGA_BGP_LCOMMUNITY_H + +/* Extended communities attribute string format.  */ +#define LCOMMUNITY_FORMAT_ROUTE_MAP            0 +#define LCOMMUNITY_FORMAT_COMMUNITY_LIST       1 +#define LCOMMUNITY_FORMAT_DISPLAY              2 + +/* Large Communities value is twelve octets long.  */ +#define LCOMMUNITY_SIZE                        12 + +/* Large Communities attribute.  */ +struct lcommunity +{ +  /* Reference counter.  */ +  unsigned long refcnt; + +  /* Size of Extended Communities attribute.  */ +  int size; + +  /* Extended Communities value.  */ +  u_int8_t *val; + +  /* Human readable format string.  */ +  char *str; +}; + +/* Extended community value is eight octet.  */ +struct lcommunity_val +{ +  char val[LCOMMUNITY_SIZE]; +}; + +#define lcom_length(X)    ((X)->size * LCOMMUNITY_SIZE) + +extern void lcommunity_init (void); +extern void lcommunity_finish (void); +extern void lcommunity_free (struct lcommunity **); +extern struct lcommunity *lcommunity_parse (u_int8_t *, u_short); +extern struct lcommunity *lcommunity_dup (struct lcommunity *); +extern struct lcommunity *lcommunity_merge (struct lcommunity *, struct lcommunity *); +extern struct lcommunity *lcommunity_uniq_sort (struct lcommunity *); +extern struct lcommunity *lcommunity_intern (struct lcommunity *); +extern int lcommunity_cmp (const void *, const void *); +extern void lcommunity_unintern (struct lcommunity **); +extern unsigned int lcommunity_hash_make (void *); +extern struct hash *lcommunity_hash (void); +extern struct lcommunity *lcommunity_str2com (const char *); +extern char *lcommunity_lcom2str (struct lcommunity *, int); +extern int lcommunity_match (const struct lcommunity *, const struct lcommunity *); +extern char *lcommunity_str (struct lcommunity *); +extern int lcommunity_include (struct lcommunity *lcom, u_char *ptr); +extern void lcommunity_del_val (struct lcommunity *lcom, u_char *ptr); +#endif /* _QUAGGA_BGP_LCOMMUNITY_H */ diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 72c0311c17..85e32645ee 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -111,3 +111,7 @@ DEFINE_MTYPE(BGPD, ENCAP_TLV,		"ENCAP TLV")  DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS,	  "BGP TEA Options")  DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value") + +DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community") +DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string") +DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value") diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index a4ce8b891b..341fb235d0 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -108,4 +108,7 @@ DECLARE_MTYPE(ENCAP_TLV)  DECLARE_MTYPE(BGP_TEA_OPTIONS)  DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE) +DECLARE_MTYPE(LCOMMUNITY) +DECLARE_MTYPE(LCOMMUNITY_STR) +DECLARE_MTYPE(LCOMMUNITY_VAL)  #endif /* _QUAGGA_BGP_MEMORY_H */ diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 1701c70441..f564ff1691 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -38,6 +38,7 @@  #include "bgpd/bgp_aspath.h"  #include "bgpd/bgp_community.h"  #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h"  #include "bgpd/bgp_mpath.h"  /* @@ -662,6 +663,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,    u_char origin;    struct community *community, *commerge;    struct ecommunity *ecomm, *ecommerge; +  struct lcommunity *lcomm, *lcommerge;    struct attr_extra *ae;    struct attr attr = { 0 }; @@ -698,6 +700,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,        community = attr.community ? community_dup (attr.community) : NULL;        ae = attr.extra;        ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL; +      lcomm = (ae && ae->lcommunity) ? lcommunity_dup (ae->lcommunity) : NULL;        for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;             mpinfo = bgp_info_mpath_next (mpinfo)) @@ -733,6 +736,17 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,                else                  ecomm = ecommunity_dup (ae->ecommunity);              } +          if (ae && ae->lcommunity) +            { +              if (lcomm) +                { +                  lcommerge = lcommunity_merge (lcomm, ae->lcommunity); +                  lcomm = lcommunity_uniq_sort (lcommerge); +                  lcommunity_free (&lcommerge); +                } +              else +                lcomm = lcommunity_dup (ae->lcommunity); +            }          }        attr.aspath = aspath; diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 7a2717acc0..6e722bbb55 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -566,6 +566,7 @@ DEFUN (no_vpnv6_network,    return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg);  } +#if defined(KEEP_OLD_VPN_COMMANDS)  static int  show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u_char use_json, afi_t afi)  { @@ -732,6 +733,7 @@ show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u      }    return CMD_SUCCESS;  } +#endif  int  bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd, diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 97eed3c35a..ea6cbcd272 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)             \ @@ -100,8 +106,7 @@ extern char *prefix_rd2str (struct prefix_rd *, char *, size_t);  extern int  argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc, int *index, afi_t *afi); -int -bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd, -		   enum bgp_show_type type, void *output_arg, int tags, u_char use_json); +extern int bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd, +                              enum bgp_show_type type, void *output_arg, int tags, u_char use_json);  #endif /* _QUAGGA_BGP_MPLSVPN_H */ diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 0a9747b526..0cf96101c2 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -492,7 +492,7 @@ bgp_show_all_instances_nexthops_vty (struct vty *vty)  DEFUN (show_ip_bgp_nexthop,         show_ip_bgp_nexthop_cmd, -       "show [ip] bgp [<view|vrf> VRFNAME] nexthop [detail]", +       "show [ip] bgp [<view|vrf> WORD] nexthop [detail]",         SHOW_STR         IP_STR         BGP_STR @@ -501,7 +501,7 @@ DEFUN (show_ip_bgp_nexthop,         "Show detailed information\n")  {    int idx = 0; -  char *vrf = argv_find (argv, argc, "VRFNAME", &idx) ? argv[idx]->arg : NULL; +  char *vrf = argv_find (argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;    int detail = argv_find (argv, argc, "detail", &idx) ? 1 : 0;    return show_ip_bgp_nexthop_table (vty, vrf, detail);  } diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 4a06881041..7dbb439be1 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -188,7 +188,9 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)  {    struct capability_mp_data mpc;    struct stream *s = BGP_INPUT (peer); -   +  afi_t afi; +  safi_t safi; +    /* Verify length is 4 */    if (hdr->length != 4)      { @@ -204,14 +206,14 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)                 peer->host, mpc.afi, mpc.safi);    /* Convert AFI, SAFI to internal values, check. */ -  if (bgp_map_afi_safi_iana2int (mpc.afi, mpc.safi, &mpc.afi, &mpc.safi)) +  if (bgp_map_afi_safi_iana2int (mpc.afi, mpc.safi, &afi, &safi))      return -1;    /* Now safi remapped, and afi/safi are valid array indices */ -  peer->afc_recv[mpc.afi][mpc.safi] = 1; +  peer->afc_recv[afi][safi] = 1; -  if (peer->afc[mpc.afi][mpc.safi]) -    peer->afc_nego[mpc.afi][mpc.safi] = 1; +  if (peer->afc[afi][safi]) +    peer->afc_nego[afi][safi] = 1;    else       return -1; @@ -219,7 +221,7 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)  }  static void -bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi, +bgp_capability_orf_not_support (struct peer *peer, iana_afi_t afi, safi_t safi,  				u_char type, u_char mode)  {    if (bgp_debug_neighbor_events(peer)) @@ -247,7 +249,8 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)  {    struct stream *s = BGP_INPUT (peer);    struct capability_orf_entry entry; -  afi_t pkt_afi, afi; +  iana_afi_t pkt_afi; +  afi_t afi;    safi_t pkt_safi, safi;    u_char type;    u_char mode; @@ -274,7 +277,7 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)        return 0;      } -  entry.mpc.afi = afi; +  entry.mpc.afi = pkt_afi;    entry.mpc.safi = safi;    /* validate number field */ @@ -418,7 +421,7 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)      {        afi_t afi;        safi_t safi; -      afi_t pkt_afi = stream_getw (s); +      iana_afi_t pkt_afi = stream_getw (s);        safi_t pkt_safi = stream_getc (s);        u_char flag = stream_getc (s); @@ -496,7 +499,7 @@ bgp_capability_addpath (struct peer *peer, struct capability_header *hdr)      {        afi_t afi;        safi_t safi; -      afi_t pkt_afi = stream_getw (s); +      iana_afi_t pkt_afi = stream_getw (s);        safi_t pkt_safi = stream_getc (s);        u_char send_receive = stream_getc (s); @@ -550,9 +553,11 @@ bgp_capability_enhe (struct peer *peer, struct capability_header *hdr)    while (stream_get_getp (s) + 6 <= end)      { -      afi_t afi, pkt_afi = stream_getw (s); +      iana_afi_t pkt_afi = stream_getw (s); +      afi_t afi;        safi_t safi, pkt_safi = stream_getw (s); -      afi_t nh_afi, pkt_nh_afi = stream_getw (s); +      iana_afi_t pkt_nh_afi = stream_getw (s); +      afi_t nh_afi;        if (bgp_debug_neighbor_events(peer))          zlog_debug ("%s Received with afi/safi/next-hop afi: %u/%u/%u", @@ -1162,7 +1167,7 @@ bgp_open_capability_orf (struct stream *s, struct peer *peer,    unsigned long orfp;    unsigned long numberp;    int number_of_orfs = 0; -  afi_t pkt_afi; +  iana_afi_t pkt_afi;    safi_t pkt_safi;    /* Convert AFI, SAFI to values for packet. */ @@ -1225,7 +1230,8 @@ bgp_open_capability (struct stream *s, struct peer *peer)  {    u_char len;    unsigned long cp, capp, rcapp; -  afi_t afi, pkt_afi; +  iana_afi_t pkt_afi; +  afi_t afi;    safi_t safi, pkt_safi;    as_t local_as;    u_int32_t restart_time; diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index b0a396ec11..9275b3a101 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -31,7 +31,7 @@ struct capability_header  /* Generic MP capability data */  struct capability_mp_data  { -  afi_t afi; +  iana_afi_t afi;    u_char reserved;    safi_t safi;  }; diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 38470a3c7e..2df22ab568 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -46,6 +46,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "bgpd/bgp_aspath.h"  #include "bgpd/bgp_community.h"  #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h"  #include "bgpd/bgp_network.h"  #include "bgpd/bgp_mplsvpn.h"  #include "bgpd/bgp_encap.h" @@ -147,7 +148,7 @@ static struct stream *  bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi)  {    struct stream *s; -  afi_t pkt_afi; +  iana_afi_t pkt_afi;    safi_t pkt_safi;    if (DISABLE_BGP_ANNOUNCE) @@ -695,7 +696,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,    struct stream *s;    struct bgp_filter *filter;    int orf_refresh = 0; -  afi_t pkt_afi; +  iana_afi_t pkt_afi;    safi_t pkt_safi;    if (DISABLE_BGP_ANNOUNCE) @@ -782,7 +783,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,  		     int capability_code, int action)  {    struct stream *s; -  afi_t pkt_afi; +  iana_afi_t pkt_afi;    safi_t pkt_safi;    /* Convert AFI, SAFI to values for packet. */ @@ -1711,7 +1712,8 @@ bgp_keepalive_receive (struct peer *peer, bgp_size_t size)  static void  bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)  { -  afi_t pkt_afi, afi; +  iana_afi_t pkt_afi; +  afi_t afi;    safi_t pkt_safi, safi;    struct stream *s;    struct peer_af *paf; @@ -1932,7 +1934,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)    struct capability_mp_data mpc;    struct capability_header *hdr;    u_char action; -  afi_t pkt_afi, afi; +  iana_afi_t pkt_afi; +  afi_t afi;    safi_t pkt_safi, safi;    end = pnt + length; @@ -2153,15 +2156,6 @@ bgp_marker_all_one (struct stream *s, int length)    return 1;  } -/* Recent thread time. -   On same clock base as bgp_clock (MONOTONIC) -   but can be time of last context switch to bgp_read thread. */ -static time_t -bgp_recent_clock (void) -{ -  return recent_relative_time().tv_sec; -} -  /* Starting point of packet process function. */  int  bgp_read (struct thread *thread) @@ -2288,14 +2282,14 @@ bgp_read (struct thread *thread)        bgp_open_receive (peer, size); /* XXX return value ignored! */        break;      case BGP_MSG_UPDATE: -      peer->readtime = bgp_recent_clock (); +      peer->readtime = monotime (NULL);        bgp_update_receive (peer, size);        break;      case BGP_MSG_NOTIFY:        bgp_notify_receive (peer, size);        break;      case BGP_MSG_KEEPALIVE: -      peer->readtime = bgp_recent_clock (); +      peer->readtime = monotime (NULL);        bgp_keepalive_receive (peer, size);        break;      case BGP_MSG_ROUTE_REFRESH_NEW: diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index eea0f86b34..fb33b234f4 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1,5 +1,6 @@  /* BGP routing information     Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro +   Copyright (C) 2016 Job Snijders <job@instituut.net>  This file is part of GNU Zebra. @@ -46,6 +47,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "bgpd/bgp_regex.h"  #include "bgpd/bgp_community.h"  #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h"  #include "bgpd/bgp_clist.h"  #include "bgpd/bgp_packet.h"  #include "bgpd/bgp_filter.h" @@ -2112,10 +2114,10 @@ bgp_maximum_prefix_restart_timer (struct thread *thread)  }  int -bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,  +bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,                               safi_t safi, int always)  { -  afi_t pkt_afi; +  iana_afi_t pkt_afi;    safi_t pkt_safi;    if (!CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) @@ -7061,7 +7063,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)))  	{ @@ -7117,7 +7124,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) @@ -7172,7 +7179,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)          { @@ -7215,30 +7222,30 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,  #define BGP_SHOW_FLAP_HEADER "   Network          From            Flaps Duration Reuse    Path%s"  static int -bgp_show_prefix_list (struct vty *vty, const char *name, +bgp_show_prefix_list (struct vty *vty, struct bgp *bgp,                        const char *prefix_list_str, afi_t afi,                        safi_t safi, enum bgp_show_type type);  static int -bgp_show_filter_list (struct vty *vty, const char *name, +bgp_show_filter_list (struct vty *vty, struct bgp *bgp,                        const char *filter, afi_t afi,                        safi_t safi, enum bgp_show_type type);  static int -bgp_show_route_map (struct vty *vty, const char *name, +bgp_show_route_map (struct vty *vty, struct bgp *bgp,                      const char *rmap_str, afi_t afi,                      safi_t safi, enum bgp_show_type type);  static int -bgp_show_community_list (struct vty *vty, const char *name, +bgp_show_community_list (struct vty *vty, struct bgp *bgp,                           const char *com, int exact,                           afi_t afi, safi_t safi);  static int -bgp_show_prefix_longer (struct vty *vty, const char *name, +bgp_show_prefix_longer (struct vty *vty, struct bgp *bgp,                          const char *prefix, afi_t afi,                          safi_t safi, enum bgp_show_type type);  static int  bgp_show_regexp (struct vty *vty, const char *regstr, afi_t afi,  		 safi_t safi, enum bgp_show_type type);  static int -bgp_show_community (struct vty *vty, const char *view_name, int argc, +bgp_show_community (struct vty *vty, struct bgp *bgp, int argc,  		    struct cmd_token **argv, int exact, afi_t afi, safi_t safi);  static int @@ -7397,6 +7404,27 @@ bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table,                  if (! community_list_exact_match (ri->attr->community, list))                    continue;                } +            if (type == bgp_show_type_lcommunity) +              { +                struct lcommunity *lcom = output_arg; + +                if (! ri->attr->extra || ! ri->attr->extra->lcommunity || +                    ! lcommunity_match (ri->attr->extra->lcommunity, lcom)) +                  continue; +              } +            if (type == bgp_show_type_lcommunity_list) +              { +                struct community_list *list = output_arg; + +                if (! ri->attr->extra || +                    ! lcommunity_list_match (ri->attr->extra->lcommunity, list)) +                  continue; +              } +            if (type == bgp_show_type_lcommunity_all) +              { +                if (! ri->attr->extra || ! ri->attr->extra->lcommunity) +                  continue; +              }              if (type == bgp_show_type_dampend_paths                  || type == bgp_show_type_damp_neighbor)                { @@ -7781,41 +7809,173 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,  /* Display specified route of Main RIB */  static int -bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str, +bgp_show_route (struct vty *vty, struct bgp *bgp, const char *ip_str,  		afi_t afi, safi_t safi, struct prefix_rd *prd,  		int prefix_check, enum bgp_path_type pathtype,                  u_char use_json)  { -  struct bgp *bgp; +  return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str,  +                                  afi, safi, prd, prefix_check, pathtype, +                                  use_json); +} -  /* BGP structure lookup. */ -  if (view_name) +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++)      { -      bgp = bgp_lookup_by_name (view_name); -      if (bgp == NULL) -	{ -	  vty_out (vty, "Can't find BGP instance %s%s", view_name, VTY_NEWLINE); -	  return CMD_WARNING; -	} +      if (first) +        buffer_putc (b, ' '); +      else +        { +          if (strmatch (argv[i]->text, "<AA:BB:CC>")) +            { +              first = 1; +              buffer_putstr (b, argv[i]->arg); +            } +        }      } -  else +  buffer_putc (b, '\0'); + +  str = buffer_getstr (b); +  buffer_free (b); + +  lcom = lcommunity_str2com (str); +  XFREE (MTYPE_TMP, str); +  if (! lcom)      { -      bgp = bgp_get_default (); -      if (bgp == NULL) -	{ -	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); -	  return CMD_WARNING; -	} +      vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE); +      return CMD_WARNING;      } -  -  return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str,  -                                  afi, safi, prd, prefix_check, pathtype, -                                  use_json); + +  return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity, lcom, uj); +} + +static int +bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom, +                          afi_t afi, safi_t safi, u_char uj) +{ +  struct community_list *list; + +  list = community_list_lookup (bgp_clist, lcom, LARGE_COMMUNITY_LIST_MASTER); +  if (list == NULL) +    { +      vty_out (vty, "%% %s is not a valid large-community-list name%s", lcom, +               VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_list, list, uj);  } +DEFUN (show_ip_bgp_large_community_list, +       show_ip_bgp_large_community_list_cmd, +       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community-list <(1-500)|WORD> [json]", +       SHOW_STR +       IP_STR +       BGP_STR +       BGP_INSTANCE_HELP_STR +       "Address Family\n" +       "Address Family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the large-community-list\n" +       "large-community-list number\n" +       "large-community-list name\n" +       JSON_STR) +{ +  char *vrf = NULL; +  afi_t afi = AFI_IP6; +  safi_t safi = SAFI_UNICAST; +  int idx = 0; + +  if (argv_find (argv, argc, "ip", &idx)) +    afi = AFI_IP; +  if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx)) +    vrf = argv[++idx]->arg; +  if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx)) +  { +    afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP; +    if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx)) +      safi = bgp_vty_safi_from_arg (argv[idx]->text); +  } + +  int uj = use_json (argc, argv); + +    struct bgp *bgp = bgp_lookup_by_name (vrf); +  if (bgp == NULL) +   { +     vty_out (vty, "Can't find BGP instance %s%s", vrf, VTY_NEWLINE); +     return CMD_WARNING; +   } + +  argv_find (argv, argc, "large-community-list", &idx); +  return bgp_show_lcommunity_list (vty, bgp, argv[idx+1]->arg, afi, safi, uj); +} +DEFUN (show_ip_bgp_large_community, +       show_ip_bgp_large_community_cmd, +       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] large-community [AA:BB:CC] [json]", +       SHOW_STR +       IP_STR +       BGP_STR +       BGP_INSTANCE_HELP_STR +       "Address Family\n" +       "Address Family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Display routes matching the large-communities\n" +       "List of large-community numbers\n" +       JSON_STR) +{ +  char *vrf = NULL; +  afi_t afi = AFI_IP6; +  safi_t safi = SAFI_UNICAST; +  int idx = 0; + +  if (argv_find (argv, argc, "ip", &idx)) +    afi = AFI_IP; +  if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx)) +    vrf = argv[++idx]->arg; +  if (argv_find (argv, argc, "ipv4", &idx) || argv_find (argv, argc, "ipv6", &idx)) +  { +    afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP; +    if (argv_find (argv, argc, "unicast", &idx) || argv_find (argv, argc, "multicast", &idx)) +      safi = bgp_vty_safi_from_arg (argv[idx]->text); +  } + +  int uj = use_json (argc, argv); + +  struct bgp *bgp = bgp_lookup_by_name (vrf); +  if (bgp == NULL) +   { +     vty_out (vty, "Can't find BGP instance %s%s", vrf, VTY_NEWLINE); +     return CMD_WARNING; +   } + +  argv_find (argv, argc, "large-community", &idx); +  if (strmatch(argv[idx+1]->text, "AA:BB:CC")) +    return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj); +  else +    return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj); +} + +static int bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi); +  /* BGP route print out function. */ -DEFUN (show_ip_bgp_ipv4, -       show_ip_bgp_ipv4_cmd, +DEFUN (show_ip_bgp, +       show_ip_bgp_cmd,         "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]]\            [<\               cidr-only\ @@ -7823,6 +7983,7 @@ DEFUN (show_ip_bgp_ipv4,               |route-map WORD\               |prefix-list WORD\               |filter-list WORD\ +             |statistics\               |community [<AA:NN|local-AS|no-advertise|no-export> [exact-match]]\               |community-list <(1-500)|WORD> [exact-match]\               |A.B.C.D/M longer-prefixes\ @@ -7842,13 +8003,14 @@ DEFUN (show_ip_bgp_ipv4,         "Display detailed information about dampening\n"         "Display flap statistics of routes\n"         "Display paths suppressed due to dampening\n" -       "Display dampening parameters\n" +       "Display detail of configured dampening parameters\n"         "Display routes matching the route-map\n"         "A route-map to match on\n"         "Display routes conforming to the prefix-list\n"         "Prefix-list name\n"         "Display routes conforming to the filter-list\n"         "Regular expression access list name\n" +       "BGP RIB advertisement statistics\n"         "Display routes matching the communities\n"         COMMUNITY_AANN_STR         "Do not send outside local AS (well-known community)\n" @@ -7865,87 +8027,80 @@ DEFUN (show_ip_bgp_ipv4,         "Display route and more specific routes\n"         JSON_STR)  { -  char *vrf = NULL; +  vrf_id_t vrf = VRF_DEFAULT;    afi_t afi = AFI_IP6;    safi_t safi = SAFI_UNICAST;    int exact_match = 0;    enum bgp_show_type sh_type = bgp_show_type_normal; - +  struct bgp *bgp = NULL;    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); -    else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpn", &idx)) -      safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN; -  } +  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf); +  if (!idx) +    return CMD_WARNING; +    int uj = use_json (argc, argv);    if (uj) argc--; -  struct bgp *bgp = bgp_lookup_by_name (vrf); +  bgp = bgp_lookup_by_vrf_id (vrf);    if (bgp == NULL) -   { -     vty_out (vty, "Can't find BGP instance %s%s", vrf, VTY_NEWLINE); -     return CMD_WARNING; -   } +    { +      vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE); +      return CMD_WARNING; +    } -  if (++idx < argc) -  { -    if (strmatch(argv[idx]->text, "cidr-only")) -      return bgp_show (vty, bgp, afi, safi, bgp_show_type_cidr_only, NULL, uj); +  if (argv_find(argv, argc, "cidr-only", &idx)) +    return bgp_show (vty, bgp, afi, safi, bgp_show_type_cidr_only, NULL, uj); -    else if (strmatch(argv[idx]->text, "dampening")) +  if (argv_find(argv, argc, "dampening", &idx))      {        if (argv_find (argv, argc, "dampened-paths", &idx))          return bgp_show (vty, bgp, afi, safi, bgp_show_type_dampend_paths, NULL, uj);        else if (argv_find (argv, argc, "flap-statistics", &idx))          return bgp_show (vty, bgp, afi, safi, bgp_show_type_flap_statistics, NULL, uj);        else if (argv_find (argv, argc, "parameters", &idx)) -        return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST); +        return bgp_show_dampening_parameters (vty, afi, safi);      } -    else if (strmatch(argv[idx]->text, "prefix-list")) -      return bgp_show_prefix_list (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_list); +  if (argv_find(argv, argc, "prefix-list", &idx)) +    return bgp_show_prefix_list (vty, bgp, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_list); -    else if (strmatch(argv[idx]->text, "filter-list")) -      return bgp_show_filter_list (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_filter_list); +  if (argv_find(argv, argc, "filter-list", &idx)) +    return bgp_show_filter_list (vty, bgp, argv[idx + 1]->arg, afi, safi, bgp_show_type_filter_list); -    else if (strmatch(argv[idx]->text, "route-map")) -      return bgp_show_route_map (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_route_map); +  if (argv_find(argv, argc, "statistics", &idx)) +    return bgp_table_stats (vty, bgp, afi, safi); -    else if (strmatch(argv[idx]->text, "community")) +  if (argv_find(argv, argc, "route-map", &idx)) +    return bgp_show_route_map (vty, bgp, argv[idx + 1]->arg, afi, safi, bgp_show_type_route_map); + +  if (argv_find(argv, argc, "community", &idx))      {        /* show a specific community */ -      if (argv[idx + 1]->type == VARIABLE_TKN || -          strmatch(argv[idx + 1]->text, "local-AS") || -          strmatch(argv[idx + 1]->text, "no-advertise") || -          strmatch(argv[idx + 1]->text, "no-export")) +      if (argv_find (argv, argc, "local-AS", &idx) || +          argv_find (argv, argc, "no-advertise", &idx) || +          argv_find (argv, argc, "no-export", &idx))          { -          if (strmatch(argv[idx + 2]->text, "exact_match"))  +          if (argv_find (argv, argc, "exact_match", &idx))              exact_match = 1; -          return bgp_show_community (vty, vrf, argc, argv, exact_match, afi, safi); +          return bgp_show_community (vty, bgp, argc, argv, exact_match, afi, safi);          }        /* show all communities */        else          return bgp_show (vty, bgp, afi, safi, bgp_show_type_community_all, NULL, uj);      } -    else if (strmatch(argv[idx]->text, "community-list")) -      { -        const char *clist_number_or_name = argv[++idx]->arg; -        if (++idx < argc && strmatch (argv[idx]->arg, "exact-match")) -          exact_match = 1; -        return bgp_show_community_list (vty, vrf, clist_number_or_name, exact_match, afi, safi); -      } -    /* 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); -  } + +  if (argv_find(argv, argc, "community-list", &idx)) +    { +      const char *clist_number_or_name = argv[++idx]->arg; +      if (++idx < argc && strmatch (argv[idx]->text, "exact-match")) +        exact_match = 1; +      return bgp_show_community_list (vty, bgp, clist_number_or_name, exact_match, afi, safi); +    } +  /* prefix-longer */ +  if (argv_find(argv, argc, "A.B.C.D/M", &idx) || argv_find(argv, argc, "X:X::X:X/M", &idx)) +    return bgp_show_prefix_longer (vty, bgp, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_longer); +    if (safi == SAFI_MPLS_VPN)      return bgp_show_mpls_vpn (vty, afi, NULL, bgp_show_type_normal, NULL, 0, uj);    else if (safi == SAFI_ENCAP) @@ -7980,34 +8135,32 @@ DEFUN (show_ip_bgp_route,    afi_t afi = AFI_IP6;    safi_t safi = SAFI_UNICAST; -  char *vrf = NULL; +  vrf_id_t vrf = VRF_DEFAULT;;    char *prefix = NULL; - +  struct bgp *bgp = NULL;    enum bgp_path_type path_type;    u_char uj = use_json(argc, argv);    int idx = 0; -  /* show [ip] bgp */ -  if (argv_find (argv, argc, "ip", &idx)) -    afi = AFI_IP; -  /* [<view|vrf> WORD] */ -  if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx)) -    vrf = argv[++idx]->arg; -  /* [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] */ -  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 = strmatch (argv[idx]->text, "unicast") ? SAFI_UNICAST : SAFI_MULTICAST; -  } -  else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpnv4", &idx)) -  { -    afi = AFI_IP; -    safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN; -    // advance idx if necessary -    argv_find (argv, argc, "unicast", &idx); -  } +  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf); +  if (!idx) +    return CMD_WARNING; + +  if (vrf != VRF_ALL) +    { +      bgp = bgp_lookup_by_vrf_id (vrf); +      if (bgp == NULL) +        { +          vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE); +          return CMD_WARNING; +        } +    } +  else +    { +      vty_out (vty, "Specified 'all' vrf's but this command currently only works per view/vrf%s", VTY_NEWLINE); +      return CMD_WARNING; +    }    /* <A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> */    if (argv_find (argv, argc, "A.B.C.D", &idx) || argv_find (argv, argc, "X:X::X:X", &idx)) @@ -8036,51 +8189,33 @@ DEFUN (show_ip_bgp_route,    else      path_type = BGP_PATH_ALL; -  return bgp_show_route (vty, vrf, prefix, afi, safi, NULL, prefix_check, path_type, uj); +  return bgp_show_route (vty, bgp, prefix, afi, safi, NULL, prefix_check, path_type, uj);  }  DEFUN (show_ip_bgp_regexp,         show_ip_bgp_regexp_cmd, -       "show [ip] bgp [<ipv4 [<unicast|multicast|vpn|encap>]|ipv6 [<unicast|multicast|vpn|encap>]|encap [unicast]|vpnv4 [unicast]>] regexp REGEX...", +       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] regexp REGEX...",         SHOW_STR         IP_STR         BGP_STR +       BGP_INSTANCE_HELP_STR         "Address Family\n" -       "Address Family modifier\n" -       "Address Family modifier\n" -       "Address Family modifier\n" -       "Address Family modifier\n"         "Address Family\n"         "Address Family modifier\n"         "Address Family modifier\n"         "Address Family modifier\n"         "Address Family modifier\n" -       "Address Family\n" -       "Address Family modifier\n" -       "Address Family\n" -       "Address Family modifier\n"         "Display routes matching the AS path regular expression\n"         "A regular-expression to match the BGP AS paths\n")  { +  vrf_id_t vrf = VRF_DEFAULT;    afi_t afi = AFI_IP6;    safi_t safi = SAFI_UNICAST;    int idx = 0; - -  /* [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] */ -  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 = strmatch (argv[idx]->text, "unicast") ? SAFI_UNICAST : SAFI_MULTICAST; -  } -  else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpnv4", &idx)) -  { -    afi = AFI_IP; -    safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN; -    // advance idx if necessary -    argv_find (argv, argc, "unicast", &idx); -  } +  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf); +  if (!idx) +    return CMD_WARNING;    // get index of regex    argv_find (argv, argc, "regexp", &idx); @@ -8094,53 +8229,35 @@ DEFUN (show_ip_bgp_regexp,  DEFUN (show_ip_bgp_instance_all,         show_ip_bgp_instance_all_cmd, -       "show [ip] bgp <view|vrf> all [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] [json]", +       "show [ip] bgp <view|vrf> all [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] [json]",         SHOW_STR         IP_STR         BGP_STR         BGP_INSTANCE_ALL_HELP_STR         "Address Family\n" -       "Address Family modifier\n" -       "Address Family modifier\n"         "Address Family\n"         "Address Family modifier\n"         "Address Family modifier\n" -       "Address Family\n"         "Address Family modifier\n" -       "Address Family\n"         "Address Family modifier\n"         JSON_STR)  { +  vrf_id_t vrf = VRF_DEFAULT;    afi_t afi = AFI_IP;    safi_t safi = SAFI_UNICAST;    int idx = 0; +  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf); +  if (!idx) +    return CMD_WARNING; -  /* show [ip] bgp */ -  if (argv_find (argv, argc, "ip", &idx)) -    afi = AFI_IP; -  /* [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] */ -  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 = strmatch (argv[idx]->text, "unicast") ? SAFI_UNICAST : SAFI_MULTICAST; -  } -  else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpnv4", &idx)) -  { -    afi = AFI_IP; -    safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN; -    // advance idx if necessary -    argv_find (argv, argc, "unicast", &idx); -  } - -  u_char uj = use_json(argc, argv); +  int uj = use_json (argc, argv); +  if (uj) argc--;    bgp_show_all_instances_routes_vty (vty, afi, safi, uj);    return CMD_SUCCESS;  } -  static int  bgp_show_regexp (struct vty *vty, const char *regstr, afi_t afi,  		 safi_t safi, enum bgp_show_type type) @@ -8163,18 +8280,11 @@ bgp_show_regexp (struct vty *vty, const char *regstr, afi_t afi,  }  static int -bgp_show_prefix_list (struct vty *vty, const char *name, +bgp_show_prefix_list (struct vty *vty, struct bgp *bgp,                        const char *prefix_list_str, afi_t afi,  		      safi_t safi, enum bgp_show_type type)  {    struct prefix_list *plist; -  struct bgp *bgp = NULL; - -  if (name && !(bgp = bgp_lookup_by_name(name))) -    { -      vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE); -      return CMD_WARNING; -    }    plist = prefix_list_lookup (afi, prefix_list_str);    if (plist == NULL) @@ -8188,18 +8298,11 @@ bgp_show_prefix_list (struct vty *vty, const char *name,  }  static int -bgp_show_filter_list (struct vty *vty, const char *name, +bgp_show_filter_list (struct vty *vty, struct bgp *bgp,                        const char *filter, afi_t afi,  		      safi_t safi, enum bgp_show_type type)  {    struct as_list *as_list; -  struct bgp *bgp = NULL; - -  if (name && !(bgp = bgp_lookup_by_name(name))) -    { -      vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE); -      return CMD_WARNING; -    }    as_list = as_list_lookup (filter);    if (as_list == NULL) @@ -8211,53 +8314,12 @@ bgp_show_filter_list (struct vty *vty, const char *name,    return bgp_show (vty, bgp, afi, safi, type, as_list, 0);  } -DEFUN (show_ip_bgp_dampening_info, -       show_ip_bgp_dampening_params_cmd, -       "show [ip] bgp dampening parameters", -       SHOW_STR -       IP_STR -       BGP_STR -       "Display detailed information about dampening\n" -       "Display detail of configured dampening parameters\n") -{ -    return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST); -} - - -DEFUN (show_ip_bgp_ipv4_dampening_parameters, -       show_ip_bgp_ipv4_dampening_parameters_cmd, -       "show [ip] bgp ipv4 <unicast|multicast> dampening parameters", -       SHOW_STR -       IP_STR -       BGP_STR -       "Address Family\n" -       "Address Family modifier\n" -       "Address Family modifier\n" -       "Display detailed information about dampening\n" -       "Display detail of configured dampening parameters\n") -{ -  int idx_safi = 4; -    if (strncmp(argv[idx_safi]->arg, "m", 1) == 0) -      return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_MULTICAST); - -    return bgp_show_dampening_parameters (vty, AFI_IP, SAFI_UNICAST); -} -  static int -bgp_show_route_map (struct vty *vty, const char *name, +bgp_show_route_map (struct vty *vty, struct bgp *bgp,                      const char *rmap_str, afi_t afi,  		    safi_t safi, enum bgp_show_type type)  {    struct route_map *rmap; -  struct bgp *bgp = NULL; - -  if (name && !(bgp = bgp_lookup_by_name(name))) -    { - - -      vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE); -      return CMD_WARNING; -    }    rmap = route_map_lookup_by_name (rmap_str);    if (! rmap) @@ -8271,36 +8333,15 @@ bgp_show_route_map (struct vty *vty, const char *name,  }  static int -bgp_show_community (struct vty *vty, const char *view_name, int argc, +bgp_show_community (struct vty *vty, struct bgp *bgp, int argc,  		    struct cmd_token **argv, int exact, afi_t afi, safi_t safi)  {    struct community *com;    struct buffer *b; -  struct bgp *bgp;    int i;    char *str;    int first = 0; -  /* BGP structure lookup */ -  if (view_name) -    { -      bgp = bgp_lookup_by_name (view_name); -      if (bgp == NULL) -	{ -	  vty_out (vty, "Can't find BGP instance %s%s", view_name, VTY_NEWLINE); -	  return CMD_WARNING; -	} -    } -  else -    { -      bgp = bgp_get_default (); -      if (bgp == NULL) -	{ -	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); -	  return CMD_WARNING; -	} -    } -    b = buffer_new (1024);    for (i = 0; i < argc; i++)      { @@ -8334,18 +8375,11 @@ bgp_show_community (struct vty *vty, const char *view_name, int argc,  }  static int -bgp_show_community_list (struct vty *vty, const char *name, +bgp_show_community_list (struct vty *vty, struct bgp *bgp,                           const char *com, int exact,  			 afi_t afi, safi_t safi)  {    struct community_list *list; -  struct bgp *bgp = NULL; - -  if (name && !(bgp = bgp_lookup_by_name(name))) -    { -      vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE); -      return CMD_WARNING; -    }    list = community_list_lookup (bgp_clist, com, COMMUNITY_LIST_MASTER);    if (list == NULL) @@ -8361,19 +8395,12 @@ bgp_show_community_list (struct vty *vty, const char *name,  }  static int -bgp_show_prefix_longer (struct vty *vty, const char *name, +bgp_show_prefix_longer (struct vty *vty, struct bgp *bgp,                          const char *prefix, afi_t afi,  			safi_t safi, enum bgp_show_type type)  {    int ret;    struct prefix *p; -  struct bgp *bgp = NULL; - -  if (name && !(bgp = bgp_lookup_by_name(name))) -    { -      vty_out (vty, "%% No such BGP instance exists%s", VTY_NEWLINE); -      return CMD_WARNING; -    }    p = prefix_new(); @@ -8390,52 +8417,13 @@ bgp_show_prefix_longer (struct vty *vty, const char *name,  }  static struct peer * -peer_lookup_in_view (struct vty *vty, const char *view_name,  +peer_lookup_in_view (struct vty *vty, struct bgp *bgp,                       const char *ip_str, u_char use_json)  {    int ret; -  struct bgp *bgp;    struct peer *peer;    union sockunion su; -  /* BGP structure lookup. */ -  if (view_name) -    { -      bgp = bgp_lookup_by_name (view_name); -      if (! bgp) -        { -          if (use_json) -            { -              json_object *json_no = NULL; -              json_no = json_object_new_object(); -              json_object_string_add(json_no, "warning", "Can't find BGP view"); -              vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); -              json_object_free(json_no); -            } -          else -            vty_out (vty, "Can't find BGP instance %s%s", view_name, VTY_NEWLINE); -          return NULL; -        }       -    } -  else -    { -      bgp = bgp_get_default (); -      if (! bgp) -        { -          if (use_json) -            { -              json_object *json_no = NULL; -              json_no = json_object_new_object(); -              json_object_string_add(json_no, "warning", "No BGP process configured"); -              vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); -              json_object_free(json_no); -            } -          else -            vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); -          return NULL; -        } -    } -    /* Get peer sockunion. */      ret = str2sockunion (ip_str, &su);    if (ret < 0) @@ -8731,81 +8719,6 @@ bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi)    return CMD_SUCCESS;  } -static int -bgp_table_stats_vty (struct vty *vty, const char *name, -                     const char *afi_str, const char *safi_str) -{ -  struct bgp *bgp; -  afi_t afi; -  safi_t safi; -   - if (name) -    bgp = bgp_lookup_by_name (name); -  else -    bgp = bgp_get_default (); - -  if (!bgp) -    { -      vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); -      return CMD_WARNING; -    } -  afi  = bgp_vty_afi_from_arg(afi_str); -  if (afi == AFI_MAX) -    { -      vty_out (vty, "%% Invalid address family \"%s\"%s", -               afi_str, VTY_NEWLINE); -      return CMD_WARNING; -    } -  safi = bgp_vty_safi_from_arg(safi_str); -  if (safi == SAFI_MAX) -    { -      vty_out (vty, "%% Invalid subsequent address family %s%s", -               safi_str, VTY_NEWLINE); -      return CMD_WARNING; -    } - -  return bgp_table_stats (vty, bgp, afi, safi); -} - -DEFUN (show_bgp_statistics, -       show_bgp_statistics_cmd, -       "show [ip] bgp <ipv4|ipv6> <encap|multicast|unicast|vpn> statistics", -       SHOW_STR -       IP_STR -       BGP_STR -       "Address Family\n" -       "Address Family\n" -       "Address Family modifier\n" -       "Address Family modifier\n" -       "Address Family modifier\n" -       "Address Family modifier\n" -       "BGP RIB advertisement statistics\n") -{ -  int idx_afi = 2; -  int idx_safi = 3; -  return bgp_table_stats_vty (vty, NULL, argv[idx_afi]->arg, argv[idx_safi]->arg); -} - -DEFUN (show_bgp_statistics_view, -       show_bgp_statistics_view_cmd, -       "show [ip] bgp <view|vrf> WORD <ipv4|ipv6> <unicast|multicast|vpn|encap> statistics", -       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" -       "BGP RIB advertisement statistics\n") -{ -  int idx_word = 3; -  int idx_afi = 4; -  return bgp_table_stats_vty (vty, NULL, argv[idx_word]->arg, argv[idx_afi]->arg); -} -  enum bgp_pcounts  {    PCOUNT_ADJ_IN = 0, @@ -8997,89 +8910,20 @@ bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, u_c    return CMD_SUCCESS;  } -DEFUN (show_ip_bgp_neighbor_prefix_counts, -       show_ip_bgp_neighbor_prefix_counts_cmd, -       "show [ip] bgp neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]", -       SHOW_STR -       IP_STR -       BGP_STR -       "Detailed information on TCP and BGP neighbor connections\n" -       "Neighbor to display information about\n" -       "Neighbor to display information about\n" -       "Neighbor on BGP configured interface\n" -       "Display detailed prefix count information\n" -       JSON_STR) -{ -  int idx_peer = 4; -  struct peer *peer; -  u_char uj = use_json(argc, argv); - -  peer = peer_lookup_in_view (vty, NULL, argv[idx_peer]->arg, uj); -  if (! peer)  -    return CMD_WARNING; -  -  return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST, uj); -} -  DEFUN (show_ip_bgp_instance_neighbor_prefix_counts,         show_ip_bgp_instance_neighbor_prefix_counts_cmd, -       "show [ip] bgp <view|vrf> WORD neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]", +       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] " +       "neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]",         SHOW_STR         IP_STR         BGP_STR         BGP_INSTANCE_HELP_STR -       "Detailed information on TCP and BGP neighbor connections\n" -       "Neighbor to display information about\n" -       "Neighbor to display information about\n" -       "Neighbor on BGP configured interface\n" -       "Display detailed prefix count information\n" -       JSON_STR) -{ -  int idx_word = 4; -  int idx_peer = 6; -  struct peer *peer; -  u_char uj = use_json(argc, argv); - -  peer = peer_lookup_in_view (vty, argv[idx_word]->arg, argv[idx_peer]->arg, uj); -  if (! peer) -    return CMD_WARNING; - -  return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST, uj); -} - -DEFUN (show_bgp_ipv6_neighbor_prefix_counts, -       show_bgp_ipv6_neighbor_prefix_counts_cmd, -       "show [ip] bgp ipv6 neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]", -       SHOW_STR -       IP_STR -       BGP_STR         "Address Family\n" -       "Detailed information on TCP and BGP neighbor connections\n" -       "Neighbor to display information about\n" -       "Neighbor to display information about\n" -       "Neighbor on BGP configured interface\n" -       "Display detailed prefix count information\n" -       JSON_STR) -{ -  int idx_peer = 4; -  struct peer *peer; -  u_char uj = use_json(argc, argv); - -  peer = peer_lookup_in_view (vty, NULL, argv[idx_peer]->arg, uj); -  if (! peer)  -    return CMD_WARNING; -  -  return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST, uj); -} - -DEFUN (show_bgp_instance_ipv6_neighbor_prefix_counts, -       show_bgp_instance_ipv6_neighbor_prefix_counts_cmd, -       "show [ip] bgp <view|vrf> WORD ipv6 neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]", -       SHOW_STR -       IP_STR -       BGP_STR -       BGP_INSTANCE_HELP_STR         "Address Family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Address Family modifier\n"         "Detailed information on TCP and BGP neighbor connections\n"         "Neighbor to display information about\n"         "Neighbor to display information about\n" @@ -9087,46 +8931,46 @@ DEFUN (show_bgp_instance_ipv6_neighbor_prefix_counts,         "Display detailed prefix count information\n"         JSON_STR)  { -  int idx_word = 3; -  int idx_peer = 6; +  vrf_id_t vrf = VRF_DEFAULT; +  afi_t afi = AFI_IP6; +  safi_t safi = SAFI_UNICAST;    struct peer *peer; -  u_char uj = use_json(argc, argv); +  int idx = 0; +  struct bgp *bgp = NULL; -  peer = peer_lookup_in_view (vty, argv[idx_word]->arg, argv[idx_peer]->arg, uj); -  if (! peer) +  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf); +  if (!idx)      return CMD_WARNING; -  return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST, uj); -} +  int uj = use_json (argc, argv); +  if (uj) argc--; -DEFUN (show_ip_bgp_ipv4_neighbor_prefix_counts, -       show_ip_bgp_ipv4_neighbor_prefix_counts_cmd, -       "show [ip] bgp ipv4 <unicast|multicast> neighbors <A.B.C.D|X:X::X:X|WORD> prefix-counts [json]", -       SHOW_STR -       IP_STR -       BGP_STR -       "Address Family\n" -       "Address Family modifier\n" -       "Address Family modifier\n" -       "Detailed information on TCP and BGP neighbor connections\n" -       "Neighbor to display information about\n" -       "Neighbor to display information about\n" -       "Neighbor on BGP configured interface\n" -       "Display detailed prefix count information\n" -       JSON_STR) -{ -  int idx_safi = 4; -  int idx_peer = 6; -  struct peer *peer; -  u_char uj = use_json(argc, argv); +  if (vrf != VRF_ALL) +    { +      bgp = bgp_lookup_by_vrf_id (vrf); +      if (bgp == NULL) +        { +          if (uj) +            { +              json_object *json_no = NULL; +              json_no = json_object_new_object(); +              json_object_string_add(json_no, "warning", "Can't find BGP view"); +              vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); +              json_object_free(json_no); +            } +          else +            vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE); +          return CMD_WARNING; +        } +    } +  else +    bgp = NULL; -  peer = peer_lookup_in_view (vty, NULL, argv[idx_peer]->arg, uj); +  argv_find (argv, argc, "neighbors", &idx); +  peer = peer_lookup_in_view (vty, bgp, argv[idx+1]->arg, uj);    if (! peer)      return CMD_WARNING; -  if (strncmp (argv[idx_safi]->arg, "m", 1) == 0) -    return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MULTICAST, uj); -    return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST, uj);  } @@ -9171,9 +9015,15 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix,  {    int idx = 0;    char *network = NULL; +  struct bgp *bgp = bgp_get_default(); +  if (!bgp) +    { +      vty_out (vty, "Can't find default instance%s", VTY_NEWLINE); +      return CMD_WARNING; +    }    network = argv_find (argv, argc, "A.B.C.D", &idx) ? argv[idx]->arg : NULL;    network = argv_find (argv, argc, "A.B.C.D/M", &idx) ? argv[idx]->arg : NULL; -  return bgp_show_route (vty, NULL, network, AFI_IP, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_ALL, use_json(argc, argv)); +  return bgp_show_route (vty, bgp, network, AFI_IP, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_ALL, use_json(argc, argv));  }  #endif /* KEEP_OLD_VPN_COMMANDS */ @@ -9419,20 +9269,17 @@ 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 [<view|vrf> WORD] [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] neighbors <A.B.C.D|X:X::X:X|WORD> [<received-routes|advertised-routes> [route-map WORD]] [json]", +       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] " +       "neighbors <A.B.C.D|X:X::X:X|WORD> [<received-routes|advertised-routes> [route-map WORD]] [json]",         SHOW_STR         IP_STR         BGP_STR         BGP_INSTANCE_HELP_STR         "Address Family\n" -       "Address Family modifier\n" -       "Address Family modifier\n"         "Address Family\n"         "Address Family modifier\n"         "Address Family modifier\n" -       "Address Family\n"         "Address Family modifier\n" -       "Address Family\n"         "Address Family modifier\n"         "Detailed information on TCP and BGP neighbor connections\n"         "Neighbor to display information about\n" @@ -9444,51 +9291,47 @@ DEFUN (show_ip_bgp_instance_neighbor_advertised_route,         "Name of the route map\n"         JSON_STR)  { +  vrf_id_t vrf = VRF_DEFAULT;    afi_t afi = AFI_IP6;    safi_t safi = SAFI_UNICAST; -  char *vrf = NULL;    char *rmap_name = NULL;    char *peerstr = NULL;    int rcvd = 0; - +  struct bgp *bgp = NULL;    struct peer *peer;    int idx = 0; -  /* show [ip] bgp */ -  if (argv_find (argv, argc, "ip", &idx)) -    afi = AFI_IP; -  /* [<view|vrf> WORD] */ -  if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx)) -    vrf = argv[++idx]->arg; -  /* [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] */ -  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 = strmatch (argv[idx]->text, "unicast") ? SAFI_UNICAST : SAFI_MULTICAST; -  } -  else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpnv4", &idx)) -  { -    afi = AFI_IP; -    safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN; -    // advance idx if necessary -    argv_find (argv, argc, "unicast", &idx); -  } +  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf); +  if (!idx) +    return CMD_WARNING; + +  int uj = use_json (argc, argv); +  if (uj) argc--; + +  bgp = bgp_lookup_by_vrf_id (vrf); +  if (bgp == NULL) +    { +      if (uj) +	{ +	  json_object *json_no = NULL; +	  json_no = json_object_new_object(); +	  json_object_string_add(json_no, "warning", "Can't find BGP view"); +	  vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); +	  json_object_free(json_no); +            } +      else +	vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE); +      return CMD_WARNING; +    }    /* neighbors <A.B.C.D|X:X::X:X|WORD> */    argv_find (argv, argc, "neighbors", &idx);    peerstr = argv[++idx]->arg; -  u_char uj = use_json(argc, argv); - -  peer = peer_lookup_in_view (vty, vrf, peerstr, uj); - +  peer = peer_lookup_in_view (vty, bgp, peerstr, uj);    if (! peer)  -    { -      vty_out (vty, "No such neighbor%s", VTY_NEWLINE); -      return CMD_WARNING; -    } +    return CMD_WARNING;    if (argv_find (argv, argc, "received-routes", &idx))      rcvd = 1; @@ -9611,20 +9454,17 @@ bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi,  DEFUN (show_ip_bgp_neighbor_routes,         show_ip_bgp_neighbor_routes_cmd, -       "show [ip] bgp [<view|vrf> WORD] [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] neighbors <A.B.C.D|X:X::X:X|WORD> <flap-statistics|dampened-routes|routes> [json]", +       "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] " +       "neighbors <A.B.C.D|X:X::X:X|WORD> <flap-statistics|dampened-routes|routes> [json]",         SHOW_STR         IP_STR         BGP_STR         BGP_INSTANCE_HELP_STR         "Address Family\n" -       "Address Family modifier\n" -       "Address Family modifier\n"         "Address Family\n"         "Address Family modifier\n"         "Address Family modifier\n" -       "Address Family\n"         "Address Family modifier\n" -       "Address Family\n"         "Address Family modifier\n"         "Detailed information on TCP and BGP neighbor connections\n"         "Neighbor to display information about\n" @@ -9635,9 +9475,9 @@ DEFUN (show_ip_bgp_neighbor_routes,         "Display routes learned from neighbor\n"         JSON_STR)  { -  char *vrf = NULL; +  vrf_id_t vrf = VRF_DEFAULT;    char *peerstr = NULL; - +  struct bgp *bgp = NULL;    afi_t afi = AFI_IP6;    safi_t safi = SAFI_UNICAST;    struct peer *peer; @@ -9645,33 +9485,39 @@ DEFUN (show_ip_bgp_neighbor_routes,    int idx = 0; -  /* show [ip] bgp */ -  if (argv_find (argv, argc, "ip", &idx)) -    afi = AFI_IP; -  /* [<view|vrf> WORD] */ -  if (argv_find (argv, argc, "view", &idx) || argv_find (argv, argc, "vrf", &idx)) -    vrf = argv[++idx]->arg; -  /* [<ipv4 [<unicast|multicast>]|ipv6 [<unicast|multicast>]|encap [unicast]|vpnv4 [unicast]>] */ -  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 = strmatch (argv[idx]->text, "unicast") ? SAFI_UNICAST : SAFI_MULTICAST; -  } -  else if (argv_find (argv, argc, "encap", &idx) || argv_find (argv, argc, "vpnv4", &idx)) -  { -    afi = AFI_IP; -    safi = strmatch (argv[idx]->text, "encap") ? SAFI_ENCAP : SAFI_MPLS_VPN; -    // advance idx if necessary -    argv_find (argv, argc, "unicast", &idx); -  } +  bgp_vty_find_and_parse_afi_safi_vrf (vty, argv, argc, &idx, &afi, &safi, &vrf); +  if (!idx) +    return CMD_WARNING; + +  int uj = use_json (argc, argv); +  if (uj) argc--; + +  if (vrf != VRF_ALL) +    { +      bgp = bgp_lookup_by_vrf_id (vrf); +      if (bgp == NULL) +        { +          if (uj) +            { +              json_object *json_no = NULL; +              json_no = json_object_new_object(); +              json_object_string_add(json_no, "warning", "Can't find BGP view"); +              vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); +              json_object_free(json_no); +            } +          else +            vty_out (vty, "Can't find BGP instance %s%s", argv[5]->arg, VTY_NEWLINE); +          return CMD_WARNING; +        } +    } +  else +    bgp = NULL; +    /* neighbors <A.B.C.D|X:X::X:X|WORD> */    argv_find (argv, argc, "neighbors", &idx);    peerstr = argv[++idx]->arg; -  u_char uj = use_json(argc, argv); - -  peer = peer_lookup_in_view (vty, vrf, peerstr, uj); +  peer = peer_lookup_in_view (vty, bgp, peerstr, uj);    if (! peer)      {        vty_out (vty, "No such neighbor%s", VTY_NEWLINE); @@ -10505,14 +10351,13 @@ bgp_route_init (void)    install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd);    install_element (VIEW_NODE, &show_ip_bgp_instance_all_cmd); -  install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_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); -  install_element (VIEW_NODE, &show_ip_bgp_dampening_params_cmd); -  install_element (VIEW_NODE, &show_ip_bgp_ipv4_dampening_parameters_cmd);  #ifdef KEEP_OLD_VPN_COMMANDS    install_element (VIEW_NODE, &show_ip_bgp_vpn_all_route_prefix_cmd);  #endif /* KEEP_OLD_VPN_COMMANDS */ @@ -10520,18 +10365,15 @@ 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);    /* prefix count */ -  install_element (ENABLE_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd);    install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbor_prefix_counts_cmd); -  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd);  #ifdef KEEP_OLD_VPN_COMMANDS    install_element (ENABLE_NODE, &show_ip_bgp_vpn_neighbor_prefix_counts_cmd);  #endif /* KEEP_OLD_VPN_COMMANDS */ -  install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_cmd); -  install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbor_prefix_counts_cmd);    /* New config IPv6 BGP commands.  */    install_element (BGP_IPV6_NODE, &bgp_table_map_cmd); @@ -10546,10 +10388,6 @@ bgp_route_init (void)    install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);    install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd); -  /* Statistics */ -  install_element (ENABLE_NODE, &show_bgp_statistics_cmd); -  install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd); -    install_element (BGP_NODE, &bgp_distance_cmd);    install_element (BGP_NODE, &no_bgp_distance_cmd);    install_element (BGP_NODE, &bgp_distance_source_cmd); @@ -10589,6 +10427,10 @@ bgp_route_init (void)    /* IPv4 Multicast Mode */    install_element (BGP_IPV4M_NODE, &bgp_damp_set_cmd);    install_element (BGP_IPV4M_NODE, &bgp_damp_unset_cmd); + +  /* Large Communities */ +  install_element (VIEW_NODE, &show_ip_bgp_large_community_list_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_large_community_cmd);  }  void diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index f2e6273b84..2103338b7d 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -41,6 +41,9 @@ enum bgp_show_type    bgp_show_type_community_exact,    bgp_show_type_community_list,    bgp_show_type_community_list_exact, +  bgp_show_type_lcommunity_all, +  bgp_show_type_lcommunity, +  bgp_show_type_lcommunity_list,    bgp_show_type_flap_statistics,    bgp_show_type_flap_neighbor,    bgp_show_type_dampend_paths, diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 50524baa01..8f2486314a 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -52,6 +52,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "bgpd/bgp_filter.h"  #include "bgpd/bgp_mplsvpn.h"  #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_lcommunity.h"  #include "bgpd/bgp_vty.h"  #include "bgpd/bgp_debug.h" @@ -84,6 +85,8 @@ o Cisco route-map        as-path tag       :  Not yet        automatic-tag     :  (This will not be implemented by bgpd)        community         :  Done +      large-community   :  Done +      large-comm-list   :  Done        comm-list         :  Not yet        dampning          :  Not yet        default           :  (This will not be implemented by bgpd) @@ -847,6 +850,78 @@ struct route_map_rule_cmd route_match_community_cmd =    route_match_community_free  }; +/* Match function for lcommunity match. */ +static route_map_result_t +route_match_lcommunity (void *rule, struct prefix *prefix, +                       route_map_object_t type, void *object) +{ +  struct community_list *list; +  struct bgp_info *bgp_info; +  struct rmap_community *rcom; + +  if (type == RMAP_BGP) +    { +      bgp_info = object; +      rcom = rule; + +      list = community_list_lookup (bgp_clist, rcom->name, +                                    LARGE_COMMUNITY_LIST_MASTER); +      if (! list) +        return RMAP_NOMATCH; + +      if (bgp_info->attr->extra && +          lcommunity_list_match (bgp_info->attr->extra->lcommunity, list)) +        return RMAP_MATCH; + +    } +  return RMAP_NOMATCH; +} + +/* Compile function for community match. */ +static void * +route_match_lcommunity_compile (const char *arg) +{ +  struct rmap_community *rcom; +  int len; +  char *p; + +  rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community)); + +  p = strchr (arg, ' '); +  if (p) +    { +      len = p - arg; +      rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); +      memcpy (rcom->name, arg, len); +    } +  else +    { +      rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); +      rcom->exact = 0; +    } +  return rcom; +} + +/* Compile function for community match. */ +static void +route_match_lcommunity_free (void *rule) +{ +  struct rmap_community *rcom = rule; + +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name); +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom); +} + +/* Route map commands for community matching. */ +struct route_map_rule_cmd route_match_lcommunity_cmd = +{ +  "large-community", +  route_match_lcommunity, +  route_match_lcommunity_compile, +  route_match_lcommunity_free +}; + +  /* Match function for extcommunity match. */  static route_map_result_t  route_match_ecommunity (void *rule, struct prefix *prefix, @@ -1544,6 +1619,224 @@ struct route_map_rule_cmd route_set_community_cmd =    route_set_community_free,  }; +/* `set community COMMUNITY' */ +struct rmap_lcom_set +{ +  struct lcommunity *lcom; +  int additive; +  int none; +}; + + +/* For lcommunity set mechanism. */ +static route_map_result_t +route_set_lcommunity (void *rule, struct prefix *prefix, +                     route_map_object_t type, void *object) +{ +  struct rmap_lcom_set *rcs; +  struct bgp_info *binfo; +  struct attr *attr; +  struct lcommunity *new = NULL; +  struct lcommunity *old; +  struct lcommunity *merge; + +  if (type == RMAP_BGP) +    { +      rcs = rule; +      binfo = object; +      attr = binfo->attr; +      old = (attr->extra) ? attr->extra->lcommunity : NULL; + +      /* "none" case.  */ +      if (rcs->none) +        { +          attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)); +          if (attr->extra) +            attr->extra->lcommunity = NULL; + +          /* See the longer comment down below. */ +          if (old && old->refcnt == 0) +            lcommunity_free(&old); +          return RMAP_OKAY; +        } + +      if (rcs->additive && old) +        { +          merge = lcommunity_merge (lcommunity_dup (old), rcs->lcom); + +          /* HACK: if the old large-community is not intern'd, +           * we should free it here, or all reference to it may be lost. +           * Really need to cleanup attribute caching sometime. +           */ +          if (old->refcnt == 0) +            lcommunity_free (&old); +          new = lcommunity_uniq_sort (merge); +          lcommunity_free (&merge); +        } +      else +        new = lcommunity_dup (rcs->lcom); + +      /* will be intern()'d or attr_flush()'d by bgp_update_main() */ +      (bgp_attr_extra_get (attr))->lcommunity = new; + +      attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); +    } + +  return RMAP_OKAY; +} + +/* Compile function for set community. */ +static void * +route_set_lcommunity_compile (const char *arg) +{ +  struct rmap_lcom_set *rcs; +  struct lcommunity *lcom = NULL; +  char *sp; +  int additive = 0; +  int none = 0; + +  if (strcmp (arg, "none") == 0) +    none = 1; +  else +    { +      sp = strstr (arg, "additive"); + +      if (sp && sp > arg) +        { +          /* "additive" keyworkd is included.  */ +          additive = 1; +          *(sp - 1) = '\0'; +        } + +      lcom = lcommunity_str2com (arg); + +      if (additive) +        *(sp - 1) = ' '; + +      if (! lcom) +        return NULL; +    } + +  rcs = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set)); +  rcs->lcom = lcom; +  rcs->additive = additive; +  rcs->none = none; + +  return rcs; +} + +/* Free function for set lcommunity. */ +static void +route_set_lcommunity_free (void *rule) +{ +  struct rmap_lcom_set *rcs = rule; + +  if (rcs->lcom) { +    lcommunity_free (&rcs->lcom); +  } +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs); +} + +/* Set community rule structure. */ +struct route_map_rule_cmd route_set_lcommunity_cmd = +{ +  "large-community", +  route_set_lcommunity, +  route_set_lcommunity_compile, +  route_set_lcommunity_free, +}; + +/* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */ + +/* For large community set mechanism. */ +static route_map_result_t +route_set_lcommunity_delete (void *rule, struct prefix *prefix, +                             route_map_object_t type, void *object) +{ +  struct community_list *list; +  struct lcommunity *merge; +  struct lcommunity *new; +  struct lcommunity *old; +  struct bgp_info *binfo; + +  if (type == RMAP_BGP) +    { +      if (! rule) +        return RMAP_OKAY; + +      binfo = object; +      list = community_list_lookup (bgp_clist, rule, +                                    LARGE_COMMUNITY_LIST_MASTER); +      old = ((binfo->attr->extra) ? binfo->attr->extra->lcommunity : NULL); + +      if (list && old) +        { +          merge = lcommunity_list_match_delete (lcommunity_dup (old), list); +          new = lcommunity_uniq_sort (merge); +          lcommunity_free (&merge); + +          /* HACK: if the old community is not intern'd, +           * we should free it here, or all reference to it may be lost. +           * Really need to cleanup attribute caching sometime. +           */ +          if (old->refcnt == 0) +            lcommunity_free (&old); + +          if (new->size == 0) +            { +              binfo->attr->extra->lcommunity = NULL; +              binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); +              lcommunity_free (&new); +            } +          else +            { +              binfo->attr->extra->lcommunity = new; +              binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES); +            } +        } +    } + +  return RMAP_OKAY; +} + +/* Compile function for set lcommunity. */ +static void * +route_set_lcommunity_delete_compile (const char *arg) +{ +  char *p; +  char *str; +  int len; + +  p = strchr (arg, ' '); +  if (p) +    { +      len = p - arg; +      str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); +      memcpy (str, arg, len); +    } +  else +    str = NULL; + +  return str; +} + +/* Free function for set lcommunity. */ +static void +route_set_lcommunity_delete_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Set lcommunity rule structure. */ +struct route_map_rule_cmd route_set_lcommunity_delete_cmd = +{ +  "large-comm-list", +  route_set_lcommunity_delete, +  route_set_lcommunity_delete_compile, +  route_set_lcommunity_delete_free, +}; + +  /* `set comm-list (<1-99>|<100-500>|WORD) delete' */  /* For community set mechanism. */ @@ -3164,7 +3457,32 @@ DEFUN (no_match_community,  				 RMAP_EVENT_CLIST_DELETED);  } +DEFUN (match_lcommunity, +       match_lcommunity_cmd, +       "match large-community [<(1-99)|(100-500)|WORD>]", +       MATCH_STR +       "Match BGP large community list\n" +       "Large Community-list number (standard)\n" +       "Large Community-list number (expanded)\n" +       "Large Community-list name\n") +{ +  return bgp_route_match_add (vty, "large-community", argv[2]->arg, +                              RMAP_EVENT_LLIST_ADDED); +} +DEFUN (no_match_lcommunity, +       no_match_lcommunity_cmd, +       "no match large-community [<(1-99)|(100-500)|WORD>]", +       NO_STR +       MATCH_STR +       "Match BGP large community list\n" +       "Large Community-list number (standard)\n" +       "Large Community-list number (expanded)\n" +       "Large Community-list name\n") +{ +  return bgp_route_match_delete (vty, "large-community", NULL, +                                 RMAP_EVENT_LLIST_DELETED); +}  DEFUN (match_ecommunity,         match_ecommunity_cmd, @@ -3597,6 +3915,95 @@ DEFUN (no_set_community_delete,                               "comm-list", NULL);  } +DEFUN (set_lcommunity, +       set_lcommunity_cmd, +       "set large-community AA:BB:CC...", +       SET_STR +       "BGP large community attribute\n" +       "Large Community number in aa:bb:cc format or additive\n") +{ +  int ret; +  char *str; + +  str = argv_concat (argv, argc, 2); +  ret = generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), "large-community", str); +  XFREE (MTYPE_TMP, str); + +  return ret; +} + +DEFUN (set_lcommunity_none, +       set_lcommunity_none_cmd, +       "set large-community none", +       SET_STR +       "BGP large community attribute\n" +       "No large community attribute\n") +{ +  return generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), +                          "large-community", "none"); +} + +DEFUN (no_set_lcommunity, +       no_set_lcommunity_cmd, +       "no set large-community none", +       NO_STR +       SET_STR +       "BGP large community attribute\n" +       "No community attribute\n") +{ +  return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index), +                             "large-community", NULL); +} + +DEFUN (no_set_lcommunity1, +       no_set_lcommunity1_cmd, +       "no set large-community AA:BB:CC...", +       NO_STR +       SET_STR +       "BGP large community attribute\n" +       "Large community in AA:BB:CC... format or additive\n") +{ +  return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index), +                             "large-community", NULL); +} + +DEFUN (set_lcommunity_delete, +       set_lcommunity_delete_cmd, +       "set large-comm-list <(1-99)|(100-500)|WORD> delete", +       SET_STR +       "set BGP large community list (for deletion)\n" +       "Large Community-list number (standard)\n" +       "Large Communitly-list number (expanded)\n" +       "Large Community-list name\n" +       "Delete matching large communities\n") +{ +  char *str; + +  str = XCALLOC (MTYPE_TMP, strlen (argv[2]->arg) + strlen (" delete") + 1); +  strcpy (str, argv[2]->arg); +  strcpy (str + strlen (argv[2]->arg), " delete"); + +  generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), +                   "large-comm-list", str); + +  XFREE (MTYPE_TMP, str); +  return CMD_SUCCESS; +} + +DEFUN (no_set_lcommunity_delete, +       no_set_lcommunity_delete_cmd, +       "no set large-comm-list <(1-99|(100-500)|WORD)> [delete]", +       NO_STR +       SET_STR +       "set BGP large community list (for deletion)\n" +       "Large Community-list number (standard)\n" +       "Large Communitly-list number (expanded)\n" +       "Large Community-list name\n" +       "Delete matching large communities\n") +{ +  return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index), +                             "large-comm-list", NULL); +}  DEFUN (set_ecommunity_rt,         set_ecommunity_rt_cmd, @@ -3992,7 +4399,7 @@ DEFUN (no_set_vpn_nexthop,  DEFUN (set_ipx_vpn_nexthop,         set_ipx_vpn_nexthop_cmd, -       "set <ipv4|ipv6> vpn next-hop [A.B.C.D|X:X::X:X]", +       "set <ipv4|ipv6> vpn next-hop [<A.B.C.D|X:X::X:X>]",         SET_STR         "IPv4 information\n"         "IPv6 information\n" @@ -4019,7 +4426,7 @@ DEFUN (set_ipx_vpn_nexthop,  DEFUN (no_set_ipx_vpn_nexthop,         no_set_ipx_vpn_nexthop_cmd, -       "no set <ipv4|ipv6> vpn next-hop [A.B.C.D|X:X::X:X]", +       "no set <ipv4|ipv6> vpn next-hop [<A.B.C.D|X:X::X:X>]",         NO_STR         SET_STR         "IPv4 information\n" @@ -4139,6 +4546,7 @@ bgp_route_map_init (void)    route_map_install_match (&route_match_ip_route_source_prefix_list_cmd);    route_map_install_match (&route_match_aspath_cmd);    route_map_install_match (&route_match_community_cmd); +  route_map_install_match (&route_match_lcommunity_cmd);    route_map_install_match (&route_match_ecommunity_cmd);    route_map_install_match (&route_match_local_pref_cmd);    route_map_install_match (&route_match_metric_cmd); @@ -4158,6 +4566,8 @@ bgp_route_map_init (void)    route_map_install_set (&route_set_aggregator_as_cmd);    route_map_install_set (&route_set_community_cmd);    route_map_install_set (&route_set_community_delete_cmd); +  route_map_install_set (&route_set_lcommunity_cmd); +  route_map_install_set (&route_set_lcommunity_delete_cmd);    route_map_install_set (&route_set_vpnv4_nexthop_cmd);    route_map_install_set (&route_set_vpnv6_nexthop_cmd);    route_map_install_set (&route_set_originator_id_cmd); @@ -4180,6 +4590,8 @@ bgp_route_map_init (void)    install_element (RMAP_NODE, &match_community_cmd);    install_element (RMAP_NODE, &match_community_exact_cmd);    install_element (RMAP_NODE, &no_match_community_cmd); +  install_element (RMAP_NODE, &match_lcommunity_cmd); +  install_element (RMAP_NODE, &no_match_lcommunity_cmd);    install_element (RMAP_NODE, &match_ecommunity_cmd);    install_element (RMAP_NODE, &no_match_ecommunity_cmd);    install_element (RMAP_NODE, &match_origin_cmd); @@ -4209,6 +4621,12 @@ bgp_route_map_init (void)    install_element (RMAP_NODE, &no_set_community_cmd);    install_element (RMAP_NODE, &set_community_delete_cmd);    install_element (RMAP_NODE, &no_set_community_delete_cmd); +  install_element (RMAP_NODE, &set_lcommunity_cmd); +  install_element (RMAP_NODE, &set_lcommunity_none_cmd); +  install_element (RMAP_NODE, &no_set_lcommunity_cmd); +  install_element (RMAP_NODE, &no_set_lcommunity1_cmd); +  install_element (RMAP_NODE, &set_lcommunity_delete_cmd); +  install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd);    install_element (RMAP_NODE, &set_ecommunity_rt_cmd);    install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd);    install_element (RMAP_NODE, &set_ecommunity_soo_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 80efe5f591..94809d69f5 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -41,14 +41,15 @@ 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" -#include "bgpd/bgp_mplsvpn.h"  #include "bgpd/bgp_nexthop.h"  #include "bgpd/bgp_open.h"  #include "bgpd/bgp_regex.h"  #include "bgpd/bgp_route.h" +#include "bgpd/bgp_mplsvpn.h"  #include "bgpd/bgp_zebra.h"  #include "bgpd/bgp_table.h"  #include "bgpd/bgp_vty.h" @@ -167,17 +168,7 @@ bgp_vty_safi_from_arg(const char *safi_str)  }  int -bgp_parse_safi(const char *str, safi_t *safi) -{ -  *safi = bgp_vty_safi_from_arg(str); -  if (*safi != SAFI_MAX) -    return 0; -  else -    return -1; -} - -int -argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *safi) +argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t *safi)  {    int ret = 0;    if (argv_find (argv, argc, "unicast", index)) @@ -207,6 +198,80 @@ argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *    return ret;  } +/* + * bgp_vty_find_and_parse_afi_safi_vrf + * + * For a given 'show ...' command, correctly parse the afi/safi/vrf out from it + * This function *assumes* that the calling function pre-sets the afi/safi/vrf + * to appropriate values for the calling function.  This is to allow the + * calling function to make decisions appropriate for the show command + * that is being parsed. + * + * The show commands are generally of the form: + * "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] ..." + * + * Since we use argv_find if the show command in particular doesn't have: + * [ip] + * [<view|vrf> WORD] + * [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] + * The command parsing should still be ok. + * + * vty  -> The vty for the command so we can output some useful data in + *         the event of a parse error in the vrf. + * argv -> The command tokens + * argc -> How many command tokens we have + * idx  -> The current place in the command, generally should be 0 for this function + * afi  -> The parsed afi if it was included in the show command, returned here + * safi -> The parsed safi if it was included in the show command, returned here + * vrf  -> The parsed vrf id if it was included in the show command, returned here + * + * The function returns the correct location in the parse tree for the + * last token found. + * + * Returns 0 for failure to parse correctly, else the idx position of where + * it found the last token. + */ +int +bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, int argc, int *idx, +                                     afi_t *afi, safi_t *safi, vrf_id_t *vrf) +{ +  char *vrf_name = NULL; + +  assert (afi); +  assert (safi); +  assert (vrf && *vrf != VRF_UNKNOWN); + +  if (argv_find (argv, argc, "ip", idx)) +      *afi = AFI_IP; + +  if (argv_find (argv, argc, "view", idx) || argv_find (argv, argc, "vrf", idx)) +    { +      vrf_name = argv[*idx + 1]->arg; +      *idx += 2; +    } + +  if (argv_find_and_parse_afi (argv, argc, idx, afi)) +    argv_find_and_parse_safi (argv, argc, idx, safi); + +  if (vrf_name) +    { +      if (strmatch(vrf_name, "all")) +       *vrf = VRF_ALL; +      else +       *vrf = vrf_name_to_id (vrf_name); +    } + +  if (*vrf == VRF_UNKNOWN) +    { +      vty_out (vty, "View/Vrf specified is unknown: %s", vrf_name); +      *idx = 0; +      return 0; +    } + +  *idx += 1; +  return *idx; +} +  static int  peer_address_self_check (struct bgp *bgp, union sockunion *su)  { @@ -3748,13 +3813,15 @@ DEFUN (no_neighbor_send_community,  /* neighbor send-community extended. */  DEFUN (neighbor_send_community_type,         neighbor_send_community_type_cmd, -       "neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|extended|standard>", +       "neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",         NEIGHBOR_STR         NEIGHBOR_ADDR_STR2         "Send Community attribute to this neighbor\n"         "Send Standard and Extended Community attributes\n" +       "Send Standard, Large and Extended Community attributes\n"         "Send Extended Community attributes\n" -       "Send Standard Community attributes\n") +       "Send Standard Community attributes\n" +       "Send Large Community attributes\n")  {    int idx = 0;    u_int32_t flag = 0; @@ -3765,25 +3832,35 @@ DEFUN (neighbor_send_community_type,      SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);    else if (argv_find (argv, argc, "extended", &idx))      SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY); +  else if (argv_find (argv, argc, "large", &idx)) +    SET_FLAG (flag, PEER_FLAG_SEND_LARGE_COMMUNITY); +  else if (argv_find (argv, argc, "both", &idx)) +    { +      SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY); +      SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY); +    }    else -  { -    SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY); -    SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY); -  } +    { +      SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY); +      SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY); +      SET_FLAG (flag, PEER_FLAG_SEND_LARGE_COMMUNITY); +    }    return peer_af_flag_set_vty (vty, peer, bgp_node_afi (vty), bgp_node_safi (vty), flag);  }  DEFUN (no_neighbor_send_community_type,         no_neighbor_send_community_type_cmd, -       "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|extended|standard>", +       "no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",         NO_STR         NEIGHBOR_STR         NEIGHBOR_ADDR_STR2         "Send Community attribute to this neighbor\n"         "Send Standard and Extended Community attributes\n" +       "Send Standard, Large and Extended Community attributes\n"         "Send Extended Community attributes\n" -       "Send Standard Community attributes\n") +       "Send Standard Community attributes\n" +       "Send Large Community attributes\n")  {    int idx_peer = 2;    int idx_type = 4; @@ -3795,11 +3872,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. */ @@ -5586,7 +5673,7 @@ DEFUN (address_family_vpnv6,    vty->node = BGP_VPNV6_NODE;    return CMD_SUCCESS;  } -#endif /* KEEP_OLD_VPN_COMMANDS */ +#endif  DEFUN (address_family_encap,         address_family_encap_cmd, @@ -6134,6 +6221,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, @@ -7111,12 +7204,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 @@ -8559,7 +8656,7 @@ DEFUN (show_ip_bgp_neighbors,         SHOW_STR         IP_STR         BGP_STR -       BGP_INSTANCE_ALL_HELP_STR +       BGP_INSTANCE_HELP_STR         "Address Family\n"         "Address Family\n"         "Address Family\n" @@ -8644,6 +8741,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", @@ -9195,7 +9322,7 @@ bgp_show_peer_group_vty (struct vty *vty, const char *name,  DEFUN (show_ip_bgp_peer_groups,         show_ip_bgp_peer_groups_cmd, -       "show [ip] bgp [<view|vrf> VRFNAME] peer-group [PGNAME]", +       "show [ip] bgp [<view|vrf> WORD] peer-group [PGNAME]",         SHOW_STR         IP_STR         BGP_STR @@ -9207,7 +9334,7 @@ DEFUN (show_ip_bgp_peer_groups,    vrf = pg = NULL;    int idx = 0; -  vrf = argv_find (argv, argc, "VRFNAME", &idx) ? argv[idx]->arg : NULL; +  vrf = argv_find (argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;    pg = argv_find (argv, argc, "PGNAME", &idx) ? argv[idx]->arg : NULL;    return bgp_show_peer_group_vty (vty, vrf, show_all_groups, pg); @@ -10695,6 +10822,7 @@ bgp_vty_init (void)    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_encap_cmd);    install_element (BGP_NODE, &address_family_encapv6_cmd); @@ -10745,6 +10873,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); @@ -11077,6 +11207,350 @@ DEFUN (show_ip_community_list_arg,    return CMD_SUCCESS;  } +/* + * Large Community code. + */ +static int +lcommunity_list_set_vty (struct vty *vty, int argc, struct cmd_token **argv, +                         int style, int reject_all_digit_name) +{ +  int ret; +  int direct; +  char *str; +  int idx = 0; +  char *cl_name; + +  direct = argv_find (argv, argc, "permit", &idx) ? COMMUNITY_PERMIT : COMMUNITY_DENY; + +  /* All digit name check.  */ +  idx = 0; +  argv_find (argv, argc, "WORD", &idx); +  argv_find (argv, argc, "(1-99)", &idx); +  argv_find (argv, argc, "(100-500)", &idx); +  cl_name = argv[idx]->arg; +  if (reject_all_digit_name && all_digit (cl_name)) +    { +      vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  argv_find (argv, argc, "AA:BB:CC", &idx); +  argv_find (argv, argc, "LINE", &idx); +  /* Concat community string argument. */ +  if (idx) +    str = argv_concat (argv, argc, idx); +  else +    str = NULL; + +  ret = lcommunity_list_set (bgp_clist, cl_name, str, direct, style); + +  /* Free temporary community list string allocated by +     argv_concat().  */ +  if (str) +    XFREE (MTYPE_TMP, str); + +  if (ret < 0) +    { +      community_list_perror (vty, ret); +      return CMD_WARNING; +    } +  return CMD_SUCCESS; +} + +static int +lcommunity_list_unset_vty (struct vty *vty, int argc, struct cmd_token **argv, +                           int style) +{ +  int ret; +  int direct = 0; +  char *str = NULL; +  int idx = 0; + +  argv_find (argv, argc, "permit", &idx); +  argv_find (argv, argc, "deny", &idx); + +  if (idx) +    { +      /* Check the list direct. */ +      if (strncmp (argv[idx]->arg, "p", 1) == 0) +        direct = COMMUNITY_PERMIT; +      else +        direct = COMMUNITY_DENY; + +      idx = 0; +      argv_find (argv, argc, "LINE", &idx); +      argv_find (argv, argc, "AA:AA:NN", &idx); +      /* Concat community string argument.  */ +      str = argv_concat (argv, argc, idx); +    } + +  idx = 0; +  argv_find (argv, argc, "(1-99)", &idx); +  argv_find (argv, argc, "(100-500)", &idx); +  argv_find (argv, argc, "WORD", &idx); + +  /* Unset community list.  */ +  ret = lcommunity_list_unset (bgp_clist, argv[idx]->arg, str, direct, style); + +  /* Free temporary community list string allocated by +     argv_concat().  */ +  if (str) +    XFREE (MTYPE_TMP, str); + +  if (ret < 0) +    { +      community_list_perror (vty, ret); +      return CMD_WARNING; +    } + +  return CMD_SUCCESS; +} + +/* "large-community-list" keyword help string.  */ +#define LCOMMUNITY_LIST_STR "Add a large community list entry\n" +#define LCOMMUNITY_VAL_STR  "large community in 'aa:bb:cc' format\n" + +DEFUN (ip_lcommunity_list_standard, +       ip_lcommunity_list_standard_cmd, +       "ip large-community-list (1-99) <deny|permit>", +       IP_STR +       LCOMMUNITY_LIST_STR +       "Large Community list number (standard)\n" +       "Specify large community to reject\n" +       "Specify large community to accept\n" +       LCOMMUNITY_VAL_STR) +{ +  return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 0); +} + +DEFUN (ip_lcommunity_list_standard1, +       ip_lcommunity_list_standard1_cmd, +       "ip large-community-list (1-99) <deny|permit> AA:BB:CC...", +       IP_STR +       LCOMMUNITY_LIST_STR +       "Large Community list number (standard)\n" +       "Specify large community to reject\n" +       "Specify large community to accept\n" +       LCOMMUNITY_VAL_STR) +{ +  return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 0); +} + +DEFUN (ip_lcommunity_list_expanded, +       ip_lcommunity_list_expanded_cmd, +       "ip large-community-list (100-500) <deny|permit> LINE...", +       IP_STR +       LCOMMUNITY_LIST_STR +       "Large Community list number (expanded)\n" +       "Specify large community to reject\n" +       "Specify large community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 0); +} + +DEFUN (ip_lcommunity_list_name_standard, +       ip_lcommunity_list_name_standard_cmd, +       "ip large-community-list standard WORD <deny|permit>", +       IP_STR +       LCOMMUNITY_LIST_STR +       "Specify standard large-community-list\n" +       "Large Community list name\n" +       "Specify large community to reject\n" +       "Specify large community to accept\n") +{ +  return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1); +} + +DEFUN (ip_lcommunity_list_name_standard1, +       ip_lcommunity_list_name_standard1_cmd, +       "ip large-community-list standard WORD <deny|permit> AA:BB:CC...", +       IP_STR +       LCOMMUNITY_LIST_STR +       "Specify standard large-community-list\n" +       "Large Community list name\n" +       "Specify large community to reject\n" +       "Specify large community to accept\n" +       LCOMMUNITY_VAL_STR) +{ +  return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1); +} + +DEFUN (ip_lcommunity_list_name_expanded, +       ip_lcommunity_list_name_expanded_cmd, +       "ip large-community-list expanded WORD <deny|permit> LINE...", +       IP_STR +       LCOMMUNITY_LIST_STR +       "Specify expanded large-community-list\n" +       "Large Community list name\n" +       "Specify large community to reject\n" +       "Specify large community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 1); +} + +DEFUN (no_ip_lcommunity_list_standard_all, +       no_ip_lcommunity_list_standard_all_cmd, +       "no ip large-community-list <(1-99)|(100-500)|WORD>", +       NO_STR +       IP_STR +       LCOMMUNITY_LIST_STR +       "Large Community list number (standard)\n" +       "Large Community list number (expanded)\n" +       "Large Community list name\n") +{ +  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_lcommunity_list_name_expanded_all, +       no_ip_lcommunity_list_name_expanded_all_cmd, +       "no ip large-community-list expanded WORD", +       NO_STR +       IP_STR +       LCOMMUNITY_LIST_STR +       "Specify expanded large-community-list\n" +       "Large Community list name\n") +{ +  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_lcommunity_list_standard, +       no_ip_lcommunity_list_standard_cmd, +       "no ip large-community-list (1-99) <deny|permit> AA:AA:NN...", +       NO_STR +       IP_STR +       LCOMMUNITY_LIST_STR +       "Large Community list number (standard)\n" +       "Specify large community to reject\n" +       "Specify large community to accept\n" +       LCOMMUNITY_VAL_STR) +{ +  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_lcommunity_list_expanded, +       no_ip_lcommunity_list_expanded_cmd, +       "no ip large-community-list (100-500) <deny|permit> LINE...", +       NO_STR +       IP_STR +       LCOMMUNITY_LIST_STR +       "Large Community list number (expanded)\n" +       "Specify large community to reject\n" +       "Specify large community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); +} + +DEFUN (no_ip_lcommunity_list_name_standard, +       no_ip_lcommunity_list_name_standard_cmd, +       "no ip large-community-list standard WORD <deny|permit> AA:AA:NN...", +       NO_STR +       IP_STR +       LCOMMUNITY_LIST_STR +       "Specify standard large-community-list\n" +       "Large Community list name\n" +       "Specify large community to reject\n" +       "Specify large community to accept\n" +       LCOMMUNITY_VAL_STR) +{ +  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD); +} + +DEFUN (no_ip_lcommunity_list_name_expanded, +       no_ip_lcommunity_list_name_expanded_cmd, +       "no ip large-community-list expanded WORD <deny|permit> LINE...", +       NO_STR +       IP_STR +       LCOMMUNITY_LIST_STR +       "Specify expanded large-community-list\n" +       "Large community list name\n" +       "Specify large community to reject\n" +       "Specify large community to accept\n" +       "An ordered list as a regular-expression\n") +{ +  return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED); +} + +static void +lcommunity_list_show (struct vty *vty, struct community_list *list) +{ +  struct community_entry *entry; + +  for (entry = list->head; entry; entry = entry->next) +    { +      if (entry == list->head) +        { +          if (all_digit (list->name)) +            vty_out (vty, "Large community %s list %s%s", +                     entry->style == EXTCOMMUNITY_LIST_STANDARD ? +                     "standard" : "(expanded) access", +                     list->name, VTY_NEWLINE); +          else +            vty_out (vty, "Named large community %s list %s%s", +                     entry->style == EXTCOMMUNITY_LIST_STANDARD ? +                     "standard" : "expanded", +                     list->name, VTY_NEWLINE); +        } +      if (entry->any) +        vty_out (vty, "    %s%s", +                 community_direct_str (entry->direct), VTY_NEWLINE); +      else +        vty_out (vty, "    %s %s%s", +                 community_direct_str (entry->direct), +                 entry->style == EXTCOMMUNITY_LIST_STANDARD ? +                 entry->u.ecom->str : entry->config, +                 VTY_NEWLINE); +    } +} + +DEFUN (show_ip_lcommunity_list, +       show_ip_lcommunity_list_cmd, +       "show ip large-community-list", +       SHOW_STR +       IP_STR +       "List large-community list\n") +{ +  struct community_list *list; +  struct community_list_master *cm; + +  cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER); +  if (! cm) +    return CMD_SUCCESS; + +  for (list = cm->num.head; list; list = list->next) +    lcommunity_list_show (vty, list); + +  for (list = cm->str.head; list; list = list->next) +    lcommunity_list_show (vty, list); + +  return CMD_SUCCESS; +} + +DEFUN (show_ip_lcommunity_list_arg, +       show_ip_lcommunity_list_arg_cmd, +       "show ip large-community-list <(1-500)|WORD>", +       SHOW_STR +       IP_STR +       "List large-community list\n" +       "large-community-list number\n" +       "large-community-list name\n") +{ +  struct community_list *list; + +  list = community_list_lookup (bgp_clist, argv[3]->arg, LARGE_COMMUNITY_LIST_MASTER); +  if (! list) +    { +      vty_out (vty, "%% Can't find extcommunity-list%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  lcommunity_list_show (vty, list); + +  return CMD_SUCCESS; +} +  /* "extcommunity-list" keyword help string.  */  #define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n"  #define EXTCOMMUNITY_VAL_STR  "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n" @@ -11386,6 +11860,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;  } @@ -11416,4 +11914,20 @@ community_list_vty (void)    install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd);    install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd);    install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd); + +  /* Large Community List */ +  install_element (CONFIG_NODE, &ip_lcommunity_list_standard_cmd); +  install_element (CONFIG_NODE, &ip_lcommunity_list_standard1_cmd); +  install_element (CONFIG_NODE, &ip_lcommunity_list_expanded_cmd); +  install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd); +  install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard1_cmd); +  install_element (CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd); +  install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd); +  install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_all_cmd); +  install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_cmd); +  install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_cmd); +  install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_cmd); +  install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_cmd); +  install_element (VIEW_NODE, &show_ip_lcommunity_list_cmd); +  install_element (VIEW_NODE, &show_ip_lcommunity_list_arg_cmd);  } diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 40c1723218..13e67d112e 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -51,9 +51,6 @@ peer_and_group_lookup_vty (struct vty *vty, const char *peer_str);  extern int  bgp_parse_afi(const char *str, afi_t *afi); -extern int -bgp_parse_safi(const char *str, safi_t *safi); -  extern afi_t  bgp_vty_afi_from_arg(const char *afi_str); @@ -66,4 +63,7 @@ argv_find_and_parse_afi(struct cmd_token **argv, int argc, int *index, afi_t *af  extern int  argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *safi); +extern int +bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, int argc, int *idx, +                                     afi_t *afi, safi_t *safi, vrf_id_t *vrf);  #endif /* _QUAGGA_BGP_VTY_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index ec2223d3ed..b0c163f1e3 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -348,7 +348,7 @@ time_t bgp_clock (void)  {    struct timeval tv; -  quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv); +  monotime(&tv);    return tv.tv_sec;  } @@ -652,7 +652,7 @@ bgp_listen_limit_unset (struct bgp *bgp)  }  int -bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi, +bgp_map_afi_safi_iana2int (iana_afi_t pkt_afi, safi_t pkt_safi,                             afi_t *afi, safi_t *safi)  {    /* Map from IANA values to internal values, return error if @@ -668,7 +668,7 @@ bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi,  int  bgp_map_afi_safi_int2iana (afi_t afi, safi_t safi, -                           afi_t *pkt_afi, safi_t *pkt_safi) +                           iana_afi_t *pkt_afi, safi_t *pkt_safi)  {    /* Map from internal values to IANA values, return error if     * internal values are bad (unexpected). @@ -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 2718805130..2eef04e1d1 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -705,6 +705,7 @@ struct peer  #define PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS (1 << 23) /* addpath-tx-bestpath-per-AS */  #define PEER_FLAG_WEIGHT                    (1 << 24) /* weight */  #define PEER_FLAG_ALLOWAS_IN_ORIGIN         (1 << 25) /* allowas-in origin */ +#define PEER_FLAG_SEND_LARGE_COMMUNITY      (1 << 26) /* Send large Communities */    /* MD5 password */    char *password; @@ -963,6 +964,7 @@ struct bgp_nlri  #define BGP_ATTR_AS4_AGGREGATOR                 18  #define BGP_ATTR_AS_PATHLIMIT                   21  #define BGP_ATTR_ENCAP                          23 +#define BGP_ATTR_LARGE_COMMUNITIES              32  #if ENABLE_BGP_VNC  #define BGP_ATTR_VNC                           255  #endif @@ -1355,11 +1357,11 @@ extern void bgp_route_map_terminate(void);  extern int peer_cmp (struct peer *p1, struct peer *p2);  extern int -bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi, +bgp_map_afi_safi_iana2int (iana_afi_t pkt_afi, safi_t pkt_safi,                             afi_t *afi, safi_t *safi);  extern int  bgp_map_afi_safi_int2iana (afi_t afi, safi_t safi, -                           afi_t *pkt_afi, safi_t *pkt_safi); +                           iana_afi_t *pkt_afi, safi_t *pkt_safi);  extern struct peer_af * peer_af_create (struct peer *, afi_t, safi_t);  extern struct peer_af * peer_af_find (struct peer *, afi_t, safi_t); diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index ab9a24e831..8ff28a39d7 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -30,8 +30,8 @@  #include "bgpd/bgpd.h"  #include "bgpd/bgp_attr.h" -#include "bgpd/bgp_mplsvpn.h"  #include "bgpd/bgp_route.h" +#include "bgpd/bgp_mplsvpn.h"  #include "bgpd/bgp_ecommunity.h"  #include "bgpd/rfapi/rfapi.h" @@ -561,8 +561,9 @@ DEFUN (vnc_defaults_responselifetime,    return CMD_SUCCESS;  } -static struct rfapi_nve_group_cfg * -rfapi_group_lookup_byname (struct bgp *bgp, const char *name) +struct rfapi_nve_group_cfg * +bgp_rfapi_cfg_match_byname (struct bgp *bgp, const char *name, +                           rfapi_group_cfg_type_t type)  /* _MAX = any */  {    struct rfapi_nve_group_cfg *rfg;    struct listnode *node, *nnode; @@ -570,18 +571,29 @@ rfapi_group_lookup_byname (struct bgp *bgp, const char *name)    for (ALL_LIST_ELEMENTS         (bgp->rfapi_cfg->nve_groups_sequential, node, nnode, rfg))      { -      if (!strcmp (rfg->name, name)) +      if ((type == RFAPI_GROUP_CFG_MAX || type == rfg->type) && +          !strcmp (rfg->name, name))          return rfg;      }    return NULL;  }  static struct rfapi_nve_group_cfg * -rfapi_group_new () +rfapi_group_new (struct bgp *bgp, +                 rfapi_group_cfg_type_t type, +                 const char *name)  {    struct rfapi_nve_group_cfg *rfg;    rfg = XCALLOC (MTYPE_RFAPI_GROUP_CFG, sizeof (struct rfapi_nve_group_cfg)); +  if (rfg)  +    { +      rfg->type = type; +      rfg->name = strdup (name); +      /* add to tail of list */ +      listnode_add (bgp->rfapi_cfg->nve_groups_sequential, rfg); +    } +  rfg->label = MPLS_LABEL_ILLEGAL;    QOBJ_REG (rfg, rfapi_nve_group_cfg);    return rfg; @@ -1033,7 +1045,8 @@ DEFUN (vnc_redistribute_nvegroup,     * OK if nve group doesn't exist yet; we'll set the pointer     * when the group is defined later     */ -  bgp->rfapi_cfg->rfg_redist = rfapi_group_lookup_byname (bgp, argv[3]->arg); +  bgp->rfapi_cfg->rfg_redist = bgp_rfapi_cfg_match_byname (bgp, argv[3]->arg, +                                                           RFAPI_GROUP_CFG_NVE);    if (bgp->rfapi_cfg->rfg_redist_name)      free (bgp->rfapi_cfg->rfg_redist_name);    bgp->rfapi_cfg->rfg_redist_name = strdup (argv[3]->arg); @@ -1622,7 +1635,7 @@ DEFUN (vnc_export_nvegroup,        return CMD_WARNING;      } -  rfg_new = rfapi_group_lookup_byname (bgp, argv[5]->arg); +  rfg_new = bgp_rfapi_cfg_match_byname (bgp, argv[5]->arg, RFAPI_GROUP_CFG_NVE);    if (argv[2]->arg[0] == 'b')      { @@ -2417,20 +2430,17 @@ DEFUN (vnc_nve_group,    struct rfapi_rfg_name *rfgn;    /* Search for name */ -  rfg = rfapi_group_lookup_byname (bgp, argv[2]->arg); +  rfg = bgp_rfapi_cfg_match_byname (bgp, argv[2]->arg, RFAPI_GROUP_CFG_NVE);    if (!rfg)      { -      rfg = rfapi_group_new (); +      rfg = rfapi_group_new (bgp, RFAPI_GROUP_CFG_NVE, argv[2]->arg);        if (!rfg)          {            /* Error out of memory */            vty_out (vty, "Can't allocate memory for NVE group%s", VTY_NEWLINE);            return CMD_WARNING;          } -      rfg->name = strdup (argv[2]->arg); -      /* add to tail of list */ -      listnode_add (bgp->rfapi_cfg->nve_groups_sequential, rfg);        /* Copy defaults from struct rfapi_cfg */        rfg->rd = bgp->rfapi_cfg->default_rd; @@ -2453,7 +2463,7 @@ DEFUN (vnc_nve_group,            rfg->rt_import_list =              ecommunity_dup (bgp->rfapi_cfg->default_rt_import_list);            rfg->rfapi_import_table = -            rfapiImportTableRefAdd (bgp, rfg->rt_import_list); +            rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);          }        /* @@ -2629,7 +2639,8 @@ static int  bgp_rfapi_delete_named_nve_group (    struct vty *vty,      /* NULL = no output */    struct bgp *bgp, -  const char *rfg_name)        /* NULL = any */ +  const char *rfg_name, /* NULL = any */ +  rfapi_group_cfg_type_t type)  /* _MAX = any */  {    struct rfapi_nve_group_cfg *rfg = NULL;    struct listnode *node, *nnode; @@ -2638,7 +2649,7 @@ bgp_rfapi_delete_named_nve_group (    /* Search for name */    if (rfg_name)      { -      rfg = rfapi_group_lookup_byname (bgp, rfg_name); +      rfg = bgp_rfapi_cfg_match_byname (bgp, rfg_name, type);        if (!rfg)          {            if (vty) @@ -2665,7 +2676,8 @@ bgp_rfapi_delete_named_nve_group (    for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l,                               node, rfgn))      { -      if (rfg_name == NULL || !strcmp (rfgn->name, rfg_name)) +      if (rfg_name == NULL || +          (type == RFAPI_GROUP_CFG_NVE && !strcmp (rfgn->name, rfg_name)))          {            rfgn->rfg = NULL;            /* remove exported routes from this group */ @@ -2680,7 +2692,8 @@ bgp_rfapi_delete_named_nve_group (    for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn))      { -      if (rfg_name == NULL || !strcmp (rfgn->name, rfg_name)) +      if (rfg_name == NULL || +          (type == RFAPI_GROUP_CFG_NVE && !strcmp (rfgn->name, rfg_name)))          {            rfgn->rfg = NULL;            /* remove exported routes from this group */ @@ -2707,7 +2720,7 @@ DEFUN (vnc_no_nve_group,  {    VTY_DECLVAR_CONTEXT(bgp, bgp); -  return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[3]->arg); +  return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[3]->arg, RFAPI_GROUP_CFG_NVE);  }  DEFUN (vnc_nve_group_prefix, @@ -2890,7 +2903,7 @@ DEFUN (vnc_nve_group_rt_import,     */    if (rfg->rfapi_import_table)      rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table); -  rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list); +  rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);    if (is_export_bgp)      vnc_direct_bgp_add_group (bgp, rfg); @@ -2997,7 +3010,7 @@ DEFUN (vnc_nve_group_rt_both,     */    if (rfg->rfapi_import_table)      rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table); -  rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list); +  rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg);    if (is_export_bgp)      vnc_direct_bgp_add_group (bgp, rfg); @@ -3238,6 +3251,492 @@ static struct cmd_node bgp_vnc_nve_group_node = {  };  /*------------------------------------------------------------------------- + *			VNC nve-group + * Note there are two types of NVEs, one for VPNs one for RFP NVEs + *-----------------------------------------------------------------------*/ + +DEFUN (vnc_vrf_policy, +       vnc_vrf_policy_cmd, +       "vrf-policy NAME", +       "Configure a VRF policy group\n" +       "VRF name\n") +{ +  struct rfapi_nve_group_cfg *rfg; +  VTY_DECLVAR_CONTEXT(bgp, bgp); + +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* Search for name */ +  rfg = bgp_rfapi_cfg_match_byname (bgp, argv[1]->arg, RFAPI_GROUP_CFG_VRF); + +  if (!rfg) +    { +      rfg = rfapi_group_new (bgp, RFAPI_GROUP_CFG_VRF, argv[1]->arg); +      if (!rfg) +        { +          /* Error out of memory */ +          vty_out (vty, "Can't allocate memory for NVE group%s", VTY_NEWLINE); +          return CMD_WARNING; +        } +    } +  /* +   * XXX subsequent calls will need to make sure this item is still +   * in the linked list and has the same name +   */ +  VTY_PUSH_CONTEXT_SUB (BGP_VRF_POLICY_NODE, rfg); + +  return CMD_SUCCESS; +} + +DEFUN (vnc_no_vrf_policy, +       vnc_no_vrf_policy_cmd, +       "no vrf-policy NAME", +       NO_STR +       "Remove a VRF policy group\n" +       "VRF name\n") +{ +  VTY_DECLVAR_CONTEXT(bgp, bgp); + +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  return bgp_rfapi_delete_named_nve_group (vty, bgp, argv[2]->arg, RFAPI_GROUP_CFG_VRF); +} + +DEFUN (vnc_vrf_policy_label, +       vnc_vrf_policy_label_cmd, +       "label (0-1048575)", +       "Default label value for VRF\n" +       "Label Value <0-1048575>\n") +{ +  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); + +  uint32_t label; +  VTY_DECLVAR_CONTEXT(bgp, bgp); + +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* make sure it's still in list */ +  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg)) +    { +      /* Not in list anymore */ +      vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  VTY_GET_INTEGER_RANGE ("Label value", label, argv[1]->arg, 0, MPLS_LABEL_MAX); + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_prechange (bgp); +    } + +  rfg->label = label; + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_postchange (bgp); +    } +  return CMD_SUCCESS; +} + +DEFUN (vnc_vrf_policy_no_label, +       vnc_vrf_policy_no_label_cmd, +       "no label", +       "Remove VRF default label\n") +{ +  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); +  VTY_DECLVAR_CONTEXT(bgp, bgp); + +  /* make sure it's still in list */ +  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg)) +    { +      /* Not in list anymore */ +      vty_out (vty, "Current VRF group no longer exists%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_prechange (bgp); +    } + +  rfg->label = MPLS_LABEL_ILLEGAL; + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_postchange (bgp); +    } +  return CMD_SUCCESS; +} + +DEFUN (vnc_vrf_policy_nexthop, +       vnc_vrf_policy_nexthop_cmd, +       "nexthop <A.B.C.D|X:X::X:X|self>", +       "Specify next hop to use for VRF advertised prefixes\n" +       "IPv4 prefix\n" +       "IPv6 prefix\n" +       "Use configured router-id (default)") +{ +  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); +  struct prefix p; + +  VTY_DECLVAR_CONTEXT(bgp, bgp); + +  /* make sure it's still in list */ +  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg)) +    { +      /* Not in list anymore */ +      vty_out (vty, "Current VRF no longer exists%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_prechange (bgp); +    } + +  if (!str2prefix (argv[1]->arg, &p) && p.family) +    { +      //vty_out (vty, "Nexthop set to self%s", VTY_NEWLINE); +      SET_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF); +      memset(&rfg->vn_prefix, 0, sizeof(struct prefix)); +    } +  else +    { +      UNSET_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF); +      rfg->vn_prefix = p; +    } + +  /* TBD handle router-id/ nexthop changes when have advertised prefixes */ + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_postchange (bgp); +    } + +  return CMD_SUCCESS; +} + +/* The RT code should be refactored/simplified with above... */ +DEFUN (vnc_vrf_policy_rt_import, +       vnc_vrf_policy_rt_import_cmd, +       "rt import RTLIST...", +       "Specify route targets\n" +       "Import filter\n" +       "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ +  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); +  VTY_DECLVAR_CONTEXT(bgp, bgp); +  int rc; +  struct listnode *node; +  struct rfapi_rfg_name *rfgn; +  int is_export_bgp = 0; +  int is_export_zebra = 0; + +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* make sure it's still in list */ +  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg)) +    { +      /* Not in list anymore */ +      vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list); +  if (rc != CMD_SUCCESS) +    return rc; + +  for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l, +                             node, rfgn)) +    { + +      if (rfgn->rfg == rfg) +        { +          is_export_bgp = 1; +          break; +        } +    } + +  if (is_export_bgp) +    vnc_direct_bgp_del_group (bgp, rfg); + +  for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn)) +    { + +      if (rfgn->rfg == rfg) +        { +          is_export_zebra = 1; +          break; +        } +    } + +  if (is_export_zebra) +    vnc_zebra_del_group (bgp, rfg); + +  /* +   * stop referencing old import table, now reference new one +   */ +  if (rfg->rfapi_import_table) +    rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table); +  rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg); + +  if (is_export_bgp) +    vnc_direct_bgp_add_group (bgp, rfg); + +  if (is_export_zebra) +    vnc_zebra_add_group (bgp, rfg); + +  return CMD_SUCCESS; +} + +DEFUN (vnc_vrf_policy_rt_export, +       vnc_vrf_policy_rt_export_cmd, +       "rt export RTLIST...", +       "Specify route targets\n" +       "Export filter\n" +       "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ +  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); +  VTY_DECLVAR_CONTEXT(bgp, bgp); +  int rc; + +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* make sure it's still in list */ +  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg)) +    { +      /* Not in list anymore */ +      vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_prechange (bgp); +    } + +  rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list); + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_postchange (bgp); +    } + +  return rc; +} + +DEFUN (vnc_vrf_policy_rt_both, +       vnc_vrf_policy_rt_both_cmd, +       "rt both RTLIST...", +       "Specify route targets\n" +       "Export+import filters\n" +       "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n") +{ +  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); +  VTY_DECLVAR_CONTEXT(bgp, bgp); +  int rc; +  int is_export_bgp = 0; +  int is_export_zebra = 0; +  struct listnode *node; +  struct rfapi_rfg_name *rfgn; + +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* make sure it's still in list */ +  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg)) +    { +      /* Not in list anymore */ +      vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list); +  if (rc != CMD_SUCCESS) +    return rc; + +  for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_direct_bgp_l, +                             node, rfgn)) +    { + +      if (rfgn->rfg == rfg) +        { +          is_export_bgp = 1; +          break; +        } +    } + +  if (is_export_bgp) +    vnc_direct_bgp_del_group (bgp, rfg); + +  for (ALL_LIST_ELEMENTS_RO (bgp->rfapi_cfg->rfg_export_zebra_l, node, rfgn)) +    { + +      if (rfgn->rfg == rfg) +        { +          is_export_zebra = 1; +          break; +        } +    } + +  if (is_export_zebra) +    { +      vnc_zlog_debug_verbose ("%s: is_export_zebra", __func__); +      vnc_zebra_del_group (bgp, rfg); +    } + +  /* +   * stop referencing old import table, now reference new one +   */ +  if (rfg->rfapi_import_table) +    rfapiImportTableRefDelByIt (bgp, rfg->rfapi_import_table); +  rfg->rfapi_import_table = rfapiImportTableRefAdd (bgp, rfg->rt_import_list, rfg); + +  if (is_export_bgp) +    vnc_direct_bgp_add_group (bgp, rfg); + +  if (is_export_zebra) +    vnc_zebra_add_group (bgp, rfg); + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_prechange (bgp); +    } + +  rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list); + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_postchange (bgp); +    } + +  return rc; + +} + +DEFUN (vnc_vrf_policy_rd, +       vnc_vrf_policy_rd_cmd, +       "rd ASN:nn_or_IP-address:nn", +       "Specify default VRF route distinguisher\n" +       "Route Distinguisher (<as-number>:<number> | <ip-address>:<number> | auto:nh:<number> )\n") +{ +  int ret; +  struct prefix_rd prd; +  VTY_DECLVAR_CONTEXT_SUB(rfapi_nve_group_cfg, rfg); +  VTY_DECLVAR_CONTEXT(bgp, bgp); + +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  /* make sure it's still in list */ +  if (!listnode_lookup (bgp->rfapi_cfg->nve_groups_sequential, rfg)) +    { +      /* Not in list anymore */ +      vty_out (vty, "Current NVE group no longer exists%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  if (!strncmp (argv[1]->arg, "auto:nh:", 8)) +    { +      /* +       * use AF_UNIX to designate automatically-assigned RD +       * auto:vn:nn where nn is a 2-octet quantity +       */ +      char *end = NULL; +      uint32_t value32 = strtoul (argv[1]->arg + 8, &end, 10); +      uint16_t value = value32 & 0xffff; + +      if (!*(argv[1]->arg + 5) || *end) +        { +          vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE); +          return CMD_WARNING; +        } +      if (value32 > 0xffff) +        { +          vty_out (vty, "%% Malformed rd (must be less than %u%s", +                   0x0ffff, VTY_NEWLINE); +          return CMD_WARNING; +        } + +      memset (&prd, 0, sizeof (prd)); +      prd.family = AF_UNIX; +      prd.prefixlen = 64; +      prd.val[0] = (RD_TYPE_IP >> 8) & 0x0ff; +      prd.val[1] = RD_TYPE_IP & 0x0ff; +      prd.val[6] = (value >> 8) & 0x0ff; +      prd.val[7] = value & 0x0ff; + +    } +  else +    { + +      ret = str2prefix_rd (argv[1]->arg, &prd); +      if (!ret) +        { +          vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE); +          return CMD_WARNING; +        } +    } + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_prechange (bgp); +    } + +  rfg->rd = prd; + +  if (bgp->rfapi_cfg->rfg_redist == rfg) +    { +      vnc_redistribute_postchange (bgp); +    } +  return CMD_SUCCESS; +} + +DEFUN (exit_vrf_policy, +       exit_vrf_policy_cmd, +       "exit-vrf-policy", +       "Exit VRF policy configuration mode\n") +{ +  if (vty->node == BGP_VRF_POLICY_NODE) +    { +      vty->node = BGP_NODE; +    } +  return CMD_SUCCESS; +} + +static struct cmd_node bgp_vrf_policy_node = { +  BGP_VRF_POLICY_NODE, +  "%s(config-router-vrf-policy)# ", +  1 +}; + +/*-------------------------------------------------------------------------   *			vnc-l2-group   *-----------------------------------------------------------------------*/ @@ -3247,11 +3746,17 @@ DEFUN (vnc_l2_group,         "vnc l2-group NAME",         VNC_CONFIG_STR "Configure a L2 group\n" "Group name\n")  { -  VTY_DECLVAR_CONTEXT(bgp, bgp);    struct rfapi_l2_group_cfg *rfg; +  VTY_DECLVAR_CONTEXT(bgp, bgp); + +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    }    /* Search for name */ -  rfg = rfapi_l2_group_lookup_byname (bgp, argv[2]->arg); +  rfg = rfapi_l2_group_lookup_byname (bgp, argv[1]->arg);    if (!rfg)      { @@ -3262,7 +3767,7 @@ DEFUN (vnc_l2_group,            vty_out (vty, "Can't allocate memory for L2 group%s", VTY_NEWLINE);            return CMD_WARNING;          } -      rfg->name = strdup (argv[2]->arg); +      rfg->name = strdup (argv[1]->arg);        /* add to tail of list */        listnode_add (bgp->rfapi_cfg->l2_groups, rfg);      } @@ -3336,18 +3841,29 @@ DEFUN (vnc_no_l2_group,  {    VTY_DECLVAR_CONTEXT(bgp, bgp); +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    }    return bgp_rfapi_delete_named_l2_group (vty, bgp, argv[3]->arg);  }  DEFUN (vnc_l2_group_lni,         vnc_l2_group_lni_cmd, -       "logical-network-id (0-4294967295)", +       "logical-network-id <0-4294967295>",         "Specify Logical Network ID associated with group\n"         "value\n")  { -  VTY_DECLVAR_CONTEXT(bgp, bgp);    VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); +  VTY_DECLVAR_CONTEXT(bgp, bgp); + +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    }    /* make sure it's still in list */    if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg)) @@ -3364,14 +3880,20 @@ DEFUN (vnc_l2_group_lni,  DEFUN (vnc_l2_group_labels,         vnc_l2_group_labels_cmd, -       "labels LABELLIST...", +       "labels .LABELLIST",         "Specify label values associated with group\n"         "Space separated list of label values <0-1048575>\n")  { -  VTY_DECLVAR_CONTEXT(bgp, bgp);    VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); +  VTY_DECLVAR_CONTEXT(bgp, bgp);    struct list *ll; +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +    /* make sure it's still in list */    if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))      { @@ -3386,13 +3908,12 @@ DEFUN (vnc_l2_group_labels,        ll = list_new ();        rfg->labels = ll;      } - -  argc -= 1; -  argv += 1; +  argc--; +  argv++;    for (; argc; --argc, ++argv)      {        uint32_t label; -      VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, 1048575); +      VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, MPLS_LABEL_MAX);        if (!listnode_lookup (ll, (void *) (uintptr_t) label))          listnode_add (ll, (void *) (uintptr_t) label);      } @@ -3402,16 +3923,22 @@ DEFUN (vnc_l2_group_labels,  DEFUN (vnc_l2_group_no_labels,         vnc_l2_group_no_labels_cmd, -       "no labels LABELLIST...", +       "no labels .LABELLIST",         NO_STR         "Remove label values associated with L2 group\n"         "Specify label values associated with L2 group\n"         "Space separated list of label values <0-1048575>\n")  { -  VTY_DECLVAR_CONTEXT(bgp, bgp);    VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); +  VTY_DECLVAR_CONTEXT(bgp, bgp);    struct list *ll; +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +    /* make sure it's still in list */    if (!listnode_lookup (bgp->rfapi_cfg->l2_groups, rfg))      { @@ -3427,12 +3954,12 @@ DEFUN (vnc_l2_group_no_labels,        return CMD_WARNING;      } -  argc -= 2; -  argv += 2; +  argc-=2; +  argv+=2;    for (; argc; --argc, ++argv)      {        uint32_t label; -      VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, 1048575); +      VTY_GET_INTEGER_RANGE ("Label value", label, argv[0]->arg, 0, MPLS_LABEL_MAX);        listnode_delete (ll, (void *) (uintptr_t) label);      } @@ -3448,8 +3975,8 @@ DEFUN (vnc_l2_group_rt,         "Import filters\n"         "A route target\n")  { -  VTY_DECLVAR_CONTEXT(bgp, bgp);    VTY_DECLVAR_CONTEXT_SUB(rfapi_l2_group_cfg, rfg); +  VTY_DECLVAR_CONTEXT(bgp, bgp);    int rc = CMD_SUCCESS;    int do_import = 0;    int do_export = 0; @@ -3467,10 +3994,8 @@ DEFUN (vnc_l2_group_rt,      default:        vty_out (vty, "Unknown option, %s%s", argv[1]->arg, VTY_NEWLINE);        return CMD_ERR_NO_MATCH; -    } -  if (argc < 3) -    return CMD_ERR_INCOMPLETE; +    }    if (!bgp)      {        vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); @@ -3486,9 +4011,9 @@ DEFUN (vnc_l2_group_rt,      }    if (do_import) -    rc = set_ecom_list (vty, argc - 2, argv + 2, &rfg->rt_import_list); +    rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_import_list);    if (rc == CMD_SUCCESS && do_export) -    rc = set_ecom_list (vty, argc - 2, argv + 2, &rfg->rt_export_list); +    rc = set_ecom_list (vty, argc-2, argv+2, &rfg->rt_export_list);    return rc;  } @@ -3571,7 +4096,9 @@ bgp_rfapi_cfg_init (void)    install_node (&bgp_vnc_defaults_node, NULL);    install_node (&bgp_vnc_nve_group_node, NULL); +  install_node (&bgp_vrf_policy_node, NULL);    install_node (&bgp_vnc_l2_group_node, NULL); +  install_default (BGP_VRF_POLICY_NODE);    install_default (BGP_VNC_DEFAULTS_NODE);    install_default (BGP_VNC_NVE_GROUP_NODE);    install_default (BGP_VNC_L2_GROUP_NODE); @@ -3582,6 +4109,8 @@ bgp_rfapi_cfg_init (void)    install_element (BGP_NODE, &vnc_defaults_cmd);    install_element (BGP_NODE, &vnc_nve_group_cmd);    install_element (BGP_NODE, &vnc_no_nve_group_cmd); +  install_element (BGP_NODE, &vnc_vrf_policy_cmd); +  install_element (BGP_NODE, &vnc_no_vrf_policy_cmd);    install_element (BGP_NODE, &vnc_l2_group_cmd);    install_element (BGP_NODE, &vnc_no_l2_group_cmd);    install_element (BGP_NODE, &vnc_advertise_un_method_cmd); @@ -3645,6 +4174,16 @@ bgp_rfapi_cfg_init (void)                     &vnc_nve_group_export_no_routemap_cmd);    install_element (BGP_VNC_NVE_GROUP_NODE, &exit_vnc_cmd); +  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_label_cmd); +  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_no_label_cmd); +  //Hide per Jan 17 discussion +  //install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_nexthop_cmd); +  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_import_cmd); +  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_export_cmd); +  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rt_both_cmd); +  install_element (BGP_VRF_POLICY_NODE, &vnc_vrf_policy_rd_cmd); +  install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd); +    install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_lni_cmd);    install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_labels_cmd);    install_element (BGP_VNC_L2_GROUP_NODE, &vnc_l2_group_no_labels_cmd); @@ -3713,7 +4252,7 @@ bgp_rfapi_cfg_destroy (struct bgp *bgp, struct rfapi_cfg *h)    if (h == NULL)      return; -  bgp_rfapi_delete_named_nve_group (NULL, bgp, NULL); +  bgp_rfapi_delete_named_nve_group (NULL, bgp, NULL, RFAPI_GROUP_CFG_MAX);    bgp_rfapi_delete_named_l2_group (NULL, bgp, NULL);    if (h->l2_groups != NULL)      list_delete (h->l2_groups); @@ -3741,6 +4280,166 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)    afi_t afi;    int type; +  vty_out (vty, "!%s", VTY_NEWLINE); +  for (ALL_LIST_ELEMENTS (hc->nve_groups_sequential, node, nnode, rfg)) +    if (rfg->type == RFAPI_GROUP_CFG_VRF) +      { +        ++write; +        vty_out (vty, " vrf-policy %s%s", rfg->name, VTY_NEWLINE); +        if (rfg->label <= MPLS_LABEL_MAX) +          { +            vty_out (vty, "  label %u%s", rfg->label, VTY_NEWLINE); + +          } +        if (CHECK_FLAG (rfg->flags, RFAPI_RFG_VPN_NH_SELF)) +          { +            vty_out (vty, "  nexthop self%s", VTY_NEWLINE); + +          } +        else  +          { +            if (rfg->vn_prefix.family) +              { +                char buf[BUFSIZ]; +                buf[0] = buf[BUFSIZ - 1] = 0; +                inet_ntop(rfg->vn_prefix.family, &rfg->vn_prefix.u.prefix, buf, sizeof(buf)); +                if (!buf[0] || buf[BUFSIZ - 1]) +                  { +                    //vty_out (vty, "nexthop self%s", VTY_NEWLINE); +                  } +                else +                  { +                    vty_out (vty, "  nexthop %s%s", buf, VTY_NEWLINE); +                  } +              } +          } + +        if (rfg->rd.prefixlen) +          { +            char buf[BUFSIZ]; +            buf[0] = buf[BUFSIZ - 1] = 0; + +            if (AF_UNIX == rfg->rd.family) +              { + +                uint16_t value = 0; + +                value = ((rfg->rd.val[6] << 8) & 0x0ff00) | +                  (rfg->rd.val[7] & 0x0ff); + +                vty_out (vty, "  rd auto:nh:%d%s", value, VTY_NEWLINE); + +              } +            else +              { + +                if (!prefix_rd2str (&rfg->rd, buf, BUFSIZ) || +                    !buf[0] || buf[BUFSIZ - 1]) +                  { + +                    vty_out (vty, "!Error: Can't convert rd%s", VTY_NEWLINE); +                  } +                else +                  { +                    vty_out (vty, "  rd %s%s", buf, VTY_NEWLINE); +                  } +              } +          } + +        if (rfg->rt_import_list && rfg->rt_export_list && +            ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list)) +          { +            char *b = ecommunity_ecom2str (rfg->rt_import_list, +                                           ECOMMUNITY_FORMAT_ROUTE_MAP); +            vty_out (vty, "  rt both %s%s", b, VTY_NEWLINE); +            XFREE (MTYPE_ECOMMUNITY_STR, b); +          } +        else +          { +            if (rfg->rt_import_list) +              { +                char *b = ecommunity_ecom2str (rfg->rt_import_list, +                                               ECOMMUNITY_FORMAT_ROUTE_MAP); +                vty_out (vty, "  rt import %s%s", b, VTY_NEWLINE); +                XFREE (MTYPE_ECOMMUNITY_STR, b); +              } +            if (rfg->rt_export_list) +              { +                char *b = ecommunity_ecom2str (rfg->rt_export_list, +                                               ECOMMUNITY_FORMAT_ROUTE_MAP); +                vty_out (vty, "  rt export %s%s", b, VTY_NEWLINE); +                XFREE (MTYPE_ECOMMUNITY_STR, b); +              } +          } + +        /* +         * route filtering: prefix-lists and route-maps +         */ +        for (afi = AFI_IP; afi < AFI_MAX; ++afi) +          { + +            const char *afistr = (afi == AFI_IP) ? "ipv4" : "ipv6"; + +            if (rfg->plist_export_bgp_name[afi]) +              { +                vty_out (vty, "  export bgp %s prefix-list %s%s", +                         afistr, rfg->plist_export_bgp_name[afi], +                         VTY_NEWLINE); +              } +            if (rfg->plist_export_zebra_name[afi]) +              { +                vty_out (vty, "  export zebra %s prefix-list %s%s", +                         afistr, rfg->plist_export_zebra_name[afi], +                         VTY_NEWLINE); +              } +            /* +             * currently we only support redist plists for bgp-direct. +             * If we later add plist support for redistributing other +             * protocols, we'll need to loop over protocols here +             */ +            if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]) +              { +                vty_out (vty, "  redistribute bgp-direct %s prefix-list %s%s", +                         afistr, +                         rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi], +                         VTY_NEWLINE); +              } +            if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT][afi]) +              { +                vty_out (vty, +                         "  redistribute bgp-direct-to-nve-groups %s prefix-list %s%s", +                         afistr, +                         rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT] +                         [afi], VTY_NEWLINE); +              } +          } + +        if (rfg->routemap_export_bgp_name) +          { +            vty_out (vty, "  export bgp route-map %s%s", +                     rfg->routemap_export_bgp_name, VTY_NEWLINE); +          } +        if (rfg->routemap_export_zebra_name) +          { +            vty_out (vty, "  export zebra route-map %s%s", +                     rfg->routemap_export_zebra_name, VTY_NEWLINE); +          } +        if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) +          { +            vty_out (vty, "  redistribute bgp-direct route-map %s%s", +                     rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT], +                     VTY_NEWLINE); +          } +        if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT]) +          { +            vty_out (vty, +                     "  redistribute bgp-direct-to-nve-groups route-map %s%s", +                     rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT_EXT], +                     VTY_NEWLINE); +          } +        vty_out (vty, "  exit-vrf-policy%s", VTY_NEWLINE); +        vty_out (vty, "!%s", VTY_NEWLINE); +      }    if (hc->flags & BGP_VNC_CONFIG_ADV_UN_METHOD_ENCAP)      {        vty_out (vty, " vnc advertise-un-method encap-safi%s", VTY_NEWLINE); @@ -3902,6 +4601,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp)        }      for (ALL_LIST_ELEMENTS (hc->nve_groups_sequential, node, nnode, rfg)) +      if (rfg->type == RFAPI_GROUP_CFG_NVE)        {          ++write;          vty_out (vty, " vnc nve-group %s%s", rfg->name, VTY_NEWLINE); diff --git a/bgpd/rfapi/bgp_rfapi_cfg.h b/bgpd/rfapi/bgp_rfapi_cfg.h index 897b4be764..8f93d69f6b 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.h +++ b/bgpd/rfapi/bgp_rfapi_cfg.h @@ -41,12 +41,21 @@ struct rfapi_l2_group_cfg  };  DECLARE_QOBJ_TYPE(rfapi_l2_group_cfg) +typedef enum +{ +  RFAPI_GROUP_CFG_NVE = 1, +  RFAPI_GROUP_CFG_VRF, +  RFAPI_GROUP_CFG_L2, +  RFAPI_GROUP_CFG_MAX +} rfapi_group_cfg_type_t; +  struct rfapi_nve_group_cfg  {    struct route_node *vn_node;   /* backref */    struct route_node *un_node;   /* backref */ -  char *name; +  rfapi_group_cfg_type_t type;  /* NVE|VPN */ +  char *name;                   /* unique by type! */    struct prefix vn_prefix;    struct prefix un_prefix; @@ -54,8 +63,9 @@ struct rfapi_nve_group_cfg    uint8_t l2rd;                 /* 0 = VN addr LSB */    uint32_t response_lifetime;    uint32_t flags; -#define RFAPI_RFG_RESPONSE_LIFETIME	0x1 +#define RFAPI_RFG_RESPONSE_LIFETIME	0x01 /* bits */  #define RFAPI_RFG_L2RD			0x02 +#define RFAPI_RFG_VPN_NH_SELF		0x04    struct ecommunity *rt_import_list;    struct ecommunity *rt_export_list;    struct rfapi_import_table *rfapi_import_table; @@ -99,6 +109,9 @@ struct rfapi_nve_group_cfg    char *routemap_redist_name[ZEBRA_ROUTE_MAX];    struct route_map *routemap_redist[ZEBRA_ROUTE_MAX]; +  /* for VRF type groups */ +  uint32_t                label; +  struct rfapi_descriptor *rfd;    QOBJ_FIELDS  };  DECLARE_QOBJ_TYPE(rfapi_nve_group_cfg) @@ -288,6 +301,12 @@ bgp_rfapi_cfg_match_group (    struct prefix		*vn,    struct prefix		*un); +struct rfapi_nve_group_cfg * +bgp_rfapi_cfg_match_byname ( +  struct bgp *bgp, +  const char *name, +  rfapi_group_cfg_type_t type);  /* _MAX = any */ +  extern void  vnc_prefix_list_update (struct bgp *bgp); diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 61da18a308..cc6b555c9d 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -36,13 +36,13 @@  #include "bgpd/bgpd.h"  #include "bgpd/bgp_ecommunity.h"  #include "bgpd/bgp_attr.h" -#include "bgpd/bgp_mplsvpn.h"  #include "bgpd/rfapi/bgp_rfapi_cfg.h"  #include "bgpd/rfapi/rfapi.h"  #include "bgpd/rfapi/rfapi_backend.h"  #include "bgpd/bgp_route.h" +#include "bgpd/bgp_mplsvpn.h"  #include "bgpd/bgp_aspath.h"  #include "bgpd/bgp_advertise.h"  #include "bgpd/bgp_vnc_types.h" @@ -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, @@ -2777,7 +2796,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 4b8eb9511b..5cc1dd7815 100644 --- a/bgpd/rfapi/rfapi_ap.c +++ b/bgpd/rfapi/rfapi_ap.c @@ -35,13 +35,13 @@  #include "bgpd/bgpd.h"  #include "bgpd/bgp_ecommunity.h"  #include "bgpd/bgp_attr.h" -#include "bgpd/bgp_mplsvpn.h"  #include "bgpd/rfapi/bgp_rfapi_cfg.h"  #include "bgpd/rfapi/rfapi.h"  #include "bgpd/rfapi/rfapi_backend.h"  #include "bgpd/bgp_route.h" +#include "bgpd/bgp_mplsvpn.h"  #include "bgpd/bgp_aspath.h"  #include "bgpd/bgp_advertise.h" @@ -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 f2805f49cb..8a59f05274 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_backend.h b/bgpd/rfapi/rfapi_backend.h index 788ec73751..9e5b0dc5cb 100644 --- a/bgpd/rfapi/rfapi_backend.h +++ b/bgpd/rfapi/rfapi_backend.h @@ -36,15 +36,6 @@ extern void rfapi_delete (struct bgp *);  struct rfapi *bgp_rfapi_new (struct bgp *bgp);  void bgp_rfapi_destroy (struct bgp *bgp, struct rfapi *h); -struct rfapi_import_table *rfapiImportTableRefAdd (struct bgp *bgp, -                                                   struct ecommunity -                                                   *rt_import_list); - -void -rfapiImportTableRefDelByIt (struct bgp *bgp, -                            struct rfapi_import_table *it_target); - -  extern void  rfapiProcessUpdate (struct peer *peer,                      void *rfd, diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index e6fdb7180e..1cd12ca0d2 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); @@ -4943,6 +4945,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 +4961,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 +4999,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 +5024,11 @@ rfapiDeleteRemotePrefixes (  	&deleted_holddown_nve_count,  	uniq_active_nves,  	uniq_holddown_nves); + +      if (arg_it) +        it = NULL; +      else +        it = it->next;      }    /* diff --git a/bgpd/rfapi/rfapi_import.h b/bgpd/rfapi/rfapi_import.h index 3cf55462a1..3ba76539dd 100644 --- a/bgpd/rfapi/rfapi_import.h +++ b/bgpd/rfapi/rfapi_import.h @@ -38,6 +38,7 @@  struct rfapi_import_table  {    struct rfapi_import_table *next; +  struct rfapi_nve_group_cfg *rfg;    struct ecommunity *rt_import_list;    /* copied from nve grp */    int refcount;                 /* nve grps and nves */    uint32_t l2_logical_net_id;   /* L2 only: EVPN Eth Seg Id */ @@ -90,6 +91,11 @@ rfapiShowImportTable (    struct route_table	*rt,    int			isvpn); +extern struct rfapi_import_table * +rfapiImportTableRefAdd ( +  struct bgp *bgp, +  struct ecommunity *rt_import_list, +  struct rfapi_nve_group_cfg *rfg);  extern void  rfapiImportTableRefDelByIt ( @@ -223,6 +229,7 @@ extern int rfapiEcommunityGetEthernetTag (   *	un			if set, tunnel must match this prefix   *	vn			if set, nexthop prefix must match this prefix   *	p			if set, prefix must match this prefix + *      it                      if set, only look in this import table   *   * output   *	pARcount		number of active routes deleted @@ -238,6 +245,7 @@ rfapiDeleteRemotePrefixes (    struct prefix	*un,    struct prefix	*vn,    struct prefix	*p, +  struct rfapi_import_table *it,    int		delete_active,    int		delete_holddown,    uint32_t	*pARcount,     /* active routes */ diff --git a/bgpd/rfapi/rfapi_private.h b/bgpd/rfapi/rfapi_private.h index 33390c4f55..ed83ef1e1f 100644 --- a/bgpd/rfapi/rfapi_private.h +++ b/bgpd/rfapi/rfapi_private.h @@ -35,21 +35,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:   *   * 1. each is referenced in by_lifetime @@ -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 */ @@ -151,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) (					\ @@ -378,9 +363,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); @@ -452,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 6aae35e635..8e5d47415f 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 <struct rfapi_rib_key>s   */ -static int +int  rfapi_rib_key_cmp (void *k1, void *k2)  {    struct rfapi_rib_key *a = (struct rfapi_rib_key *) k1; @@ -498,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_rib.h b/bgpd/rfapi/rfapi_rib.h index 2a111946f7..74331a28d0 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 1e7941a41d..1e92cbcbf1 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -1447,17 +1447,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 @@ -1847,14 +1854,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 = @@ -1865,14 +1872,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);  } @@ -3005,9 +3012,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; @@ -3107,22 +3117,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, "*"))      { @@ -3168,7 +3182,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 @@ -3272,51 +3320,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; @@ -3376,7 +3410,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", @@ -3385,11 +3419,22 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)                      continue;                    }                } +            if (pPrd)  +              { +                if (memcmp(pPrd->val, adb->u.s.prd.val, 8) != 0) +                  { +#if DEBUG_L2_EXTRA +                    vnc_zlog_debug_verbose ("%s: adb=%p, RD doesn't match, skipping", +                                __func__, adb); +#endif +                    continue; +                  } +              }              if (CHECK_FLAG (cda->l2o.flags, RFAPI_L2O_MACADDR))                {                  if (memcmp                      (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", @@ -3423,48 +3468,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->prefix_ip, &rp); +            rfapiQprefix2Rprefix (&adb->u.s.prefix_ip, &rp); + +            memset (optary, 0, sizeof (optary));              /* 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; - -                /* -                 * 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; - -                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; @@ -3500,7 +3540,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))                        { @@ -3527,7 +3567,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; @@ -3590,11 +3630,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   * @@ -3610,6 +3683,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     */ @@ -3627,7 +3702,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, @@ -3712,7 +3791,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; @@ -3745,7 +3824,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; @@ -3778,7 +3857,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; @@ -3806,7 +3885,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; @@ -3833,7 +3912,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; @@ -3876,7 +3955,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); @@ -3906,7 +3985,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); @@ -3932,7 +4011,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); @@ -3958,7 +4037,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); @@ -3980,7 +4059,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); @@ -4022,8 +4101,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); @@ -4056,8 +4135,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); @@ -4086,7 +4165,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); @@ -4115,7 +4194,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); @@ -4141,7 +4220,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); @@ -4182,8 +4261,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); @@ -4224,8 +4303,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); @@ -4258,8 +4337,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); @@ -4292,8 +4371,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); @@ -4322,7 +4401,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); @@ -4930,6 +5009,361 @@ notcfg:    return CMD_WARNING;  } +/************************************************************************ + *		Add prefix with vrf + * + * add [vrf <vrf-name>] prefix <prefix> + *     [rd <value>] [label <value>] [local-preference <0-4294967295>] + ************************************************************************/ +static int +vnc_add_vrf_prefix (struct vty *vty, +                    const char *arg_vrf, +                    const char *arg_prefix, +                    const char *arg_rd,     /* optional */ +                    const char *arg_label,  /* optional */ +                    const char *arg_pref)   /* optional */ +{ +  struct bgp                 *bgp; +  struct rfapi_nve_group_cfg *rfg; +  struct prefix               pfx; +  struct rfapi_ip_prefix      rpfx; +  uint32_t                    pref = 0; +  struct rfapi_vn_option      optary[3]; +  struct rfapi_vn_option      *opt = NULL; +  int                         cur_opt = 0; + +  bgp = bgp_get_default (); /* assume main instance for now */ +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  if (!bgp->rfapi || !bgp->rfapi_cfg) +    { +      vty_out (vty, "VRF support not configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + +  rfg = bgp_rfapi_cfg_match_byname (bgp,  arg_vrf, RFAPI_GROUP_CFG_VRF); +  /* arg checks */ +  if (!rfg) +    { +      vty_out (vty, "VRF \"%s\" appears not to be configured.%s", +               arg_vrf, VTY_NEWLINE); +          return CMD_WARNING; +    } +  if (!rfg->rt_export_list || !rfg->rfapi_import_table) +    { +      vty_out (vty, "VRF \"%s\" is missing RT import/export RT configuration.%s", +               arg_vrf, VTY_NEWLINE); +      return CMD_WARNING; +    } +  if (!rfg->rd.family && !arg_rd) +    { +      vty_out (vty, "VRF \"%s\" isn't configured with an RD, so RD must be provided.%s", +               arg_vrf, VTY_NEWLINE); +      return CMD_WARNING; +    } +  if (rfg->label > MPLS_LABEL_MAX && !arg_label) +    { +      vty_out (vty, "VRF \"%s\" isn't configured with a default labels, so a label must be provided.%s", +               arg_vrf, VTY_NEWLINE); +      return CMD_WARNING; +    } +  if (!str2prefix (arg_prefix, &pfx)) +    { +      vty_out (vty, "Malformed prefix \"%s\"%s", +               arg_prefix, VTY_NEWLINE); +      return CMD_WARNING; +    } +  rfapiQprefix2Rprefix (&pfx, &rpfx); +  memset (optary, 0, sizeof (optary)); +  if (arg_rd) +    { +      if (opt != NULL) +        opt->next = &optary[cur_opt]; +      opt = &optary[cur_opt++]; +      opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD; +      if (!str2prefix_rd (arg_rd, &opt->v.internal_rd)) +        { +          vty_out (vty, "Malformed RD \"%s\"%s", +                   arg_rd, VTY_NEWLINE); +          return CMD_WARNING; +        } +    } +  if (rfg->label <= MPLS_LABEL_MAX || arg_label) +    { +      struct rfapi_l2address_option	*l2o; +      if (opt != NULL) +        opt->next = &optary[cur_opt]; +      opt = &optary[cur_opt++]; +      opt->type  = RFAPI_VN_OPTION_TYPE_L2ADDR; +      l2o =  &opt->v.l2addr; +      if (arg_label) +        { +          int32_t label; +          VTY_GET_INTEGER_RANGE ("Label value", label, arg_label, 0, MPLS_LABEL_MAX); +          l2o->label = label; +        } +      else +        l2o->label = rfg->label; +    } +  if (arg_pref) +    { +      char *endptr = NULL; +      pref = strtoul (arg_pref, &endptr, 10); +      if (*endptr != '\0') +        { +          vty_out (vty, "%% Invalid local-preference value \"%s\"%s", arg_pref, VTY_NEWLINE); +          return CMD_WARNING; +         } +    } +  rpfx.cost = 255 - (pref & 255) ; +  if (rfg->rfd == NULL)         /* need new rfapi_handle */ +    { +      /* based on rfapi_open */ +      struct rfapi_descriptor *rfd; +      rfd = XCALLOC (MTYPE_RFAPI_DESC, sizeof (struct rfapi_descriptor)); +      rfd->bgp = bgp; +      rfg->rfd = rfd; +      /* leave most fields empty as will get from (dynamic) config when needed */ +      rfd->default_tunneltype_option.type = BGP_ENCAP_TYPE_MPLS; +      rfd->cookie = rfg; +      if (rfg->vn_prefix.family && +          !CHECK_FLAG(rfg->flags, RFAPI_RFG_VPN_NH_SELF)) +        { +          rfapiQprefix2Raddr(&rfg->vn_prefix, &rfd->vn_addr); +        } +      else +        { +          memset(&rfd->vn_addr, 0, sizeof(struct rfapi_ip_addr)); +          rfd->vn_addr.addr_family = AF_INET; +          rfd->vn_addr.addr.v4 = bgp->router_id; +        } +      rfd->un_addr = rfd->vn_addr; /* sigh, need something in UN for lookups */ +      vnc_zlog_debug_verbose ("%s: Opening RFD for VRF %s", +                              __func__, rfg->name); +      rfapi_init_and_open(bgp, rfd, rfg); +    } + +  if (!rfapi_register (rfg->rfd, &rpfx, RFAPI_INFINITE_LIFETIME, NULL, +                       (cur_opt ? optary : NULL), RFAPI_REGISTER_ADD)) +    { +      struct rfapi_next_hop_entry *head = NULL; +      struct rfapi_next_hop_entry *tail = NULL; +      struct rfapi_vn_option *vn_opt_new; + +      vnc_zlog_debug_verbose ("%s: rfapi_register succeeded", __func__); + +      if (bgp->rfapi->rfp_methods.local_cb) +        { +          struct rfapi_descriptor *r = (struct rfapi_descriptor *) rfg->rfd; +          vn_opt_new = rfapi_vn_options_dup (opt); + +          rfapiAddDeleteLocalRfpPrefix (&r->un_addr, &r->vn_addr, &rpfx, +                                        1, RFAPI_INFINITE_LIFETIME, +                                        vn_opt_new, &head, &tail); +          if (head) +            { +              bgp->rfapi->flags |= RFAPI_INCALLBACK; +              (*bgp->rfapi->rfp_methods.local_cb) (head, r->cookie); +              bgp->rfapi->flags &= ~RFAPI_INCALLBACK; +            } +          head = tail = NULL; +        } +      vnc_zlog_debug_verbose ("%s completed, count=%d/%d",  __func__, +                              rfg->rfapi_import_table->local_count[AFI_IP], +                              rfg->rfapi_import_table->local_count[AFI_IP6]); +      return CMD_SUCCESS; +    } + +  vnc_zlog_debug_verbose ("%s: rfapi_register failed", __func__); +  vty_out (vty, "Add failed.%s", VTY_NEWLINE); +  return CMD_WARNING; +} + +DEFUN (add_vrf_prefix_rd_label_pref, +       add_vrf_prefix_rd_label_pref_cmd, +      "add vrf NAME prefix <A.B.C.D/M|X:X::X:X/M> [rd ASN:nn_or_IP-address] [label (0-1048575)] [preference (0-4294967295)]", +       "Add\n" +       "To a VRF\n" +       "VRF name\n" +       "Add/modify prefix related information\n" +       "IPv4 prefix\n" +       "IPv6 prefix\n" +       "Override configured VRF Route Distinguisher\n" +       "<as-number>:<number> or <ip-address>:<number>\n" +       "Override configured VRF label" +       "Label Value <0-1048575>\n" +       "Set advertised local preference\n" +       "local preference (higher=more preferred)\n") +{ +  char *arg_vrf    = argv[2]->arg; +  char *arg_prefix = argv[4]->arg; +  char *arg_rd     = NULL;      /* optional */ +  char *arg_label  = NULL;      /* optional */ +  char *arg_pref   = NULL;      /* optional */ +  int  pargc = 5; +  argc--;                        /* don't parse argument */ +  while (pargc < argc)  +    { +      switch (argv[pargc++]->arg[0]) +        { +        case 'r': +          arg_rd    = argv[pargc]->arg; +          break; +        case 'l': +          arg_label = argv[pargc]->arg; +          break; +        case 'p': +          arg_pref  = argv[pargc]->arg; +          break; +        default: +          break; +        } +      pargc ++; +    } +   +  return vnc_add_vrf_prefix (vty, arg_vrf, arg_prefix, arg_rd, arg_label, arg_pref); +} + +/************************************************************************ + *		del prefix with vrf + * + * clear [vrf <vrf-name>] prefix <prefix> [rd <value>] + ************************************************************************/ +static int +rfapi_cfg_group_it_count(struct rfapi_nve_group_cfg *rfg) +{ +  int count = 0; +  afi_t afi = AFI_MAX; +  while (afi-- > 0) +    { +      count += rfg->rfapi_import_table->local_count[afi]; +    } +  return count; +} + +static void +clear_vnc_vrf_closer (struct rfapi_nve_group_cfg *rfg) +{ +  struct rfapi_descriptor *rfd = rfg->rfd; +  afi_t                    afi; + +  if (rfd == NULL) +    return; +  /* check if IT is empty */ +  for (afi = 0;  +       afi < AFI_MAX && rfg->rfapi_import_table->local_count[afi] == 0;  +       afi++); + +  if (afi == AFI_MAX) +    { +      vnc_zlog_debug_verbose ("%s: closing RFD for VRF %s", +                              __func__, rfg->name); +      rfg->rfd = NULL; +      rfapi_close(rfd); +    } +  else +    { +      vnc_zlog_debug_verbose ("%s: VRF %s afi=%d count=%d", +                              __func__, rfg->name, afi,  +                              rfg->rfapi_import_table->local_count[afi]); +    } +} + +static int +vnc_clear_vrf (struct vty *vty, +               struct bgp *bgp, +               const char *arg_vrf, +               const char *arg_prefix, /* NULL = all */ +               const char *arg_rd)     /* optional */ +{ +  struct rfapi_nve_group_cfg        *rfg; +  struct rfapi_local_reg_delete_arg  cda; +  int                                rc; +  int                                start_count; + +  if (bgp == NULL) +    bgp = bgp_get_default (); /* assume main instance for now */ +  if (!bgp) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  if (!bgp->rfapi || !bgp->rfapi_cfg) +    { +      vty_out (vty, "VRF support not configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } +  rfg = bgp_rfapi_cfg_match_byname (bgp,  arg_vrf, RFAPI_GROUP_CFG_VRF); +  /* arg checks */ +  if (!rfg) +    { +      vty_out (vty, "VRF \"%s\" appears not to be configured.%s", +               arg_vrf, VTY_NEWLINE); +          return CMD_WARNING; +    } +  rc = parse_deleter_args (vty, bgp, arg_prefix, NULL, NULL, NULL, NULL, +                           arg_rd, rfg, &cda); +  if (rc != CMD_SUCCESS)        /* parse error */ +    return rc; + +  start_count = rfapi_cfg_group_it_count(rfg); +  clear_vnc_prefix (&cda); +  clear_vnc_vrf_closer (rfg); +  vty_out (vty, "Cleared %u out of %d prefixes.%s",  +           cda.pfx_count, start_count, VTY_NEWLINE); +  return CMD_SUCCESS; +} + +DEFUN (clear_vrf_prefix_rd, +       clear_vrf_prefix_rd_cmd, +       "clear vrf NAME [prefix <A.B.C.D/M|X:X::X:X/M>] [rd ASN:nn_or_IP-address]", +       "Clear stored data\n" +       "From a VRF\n" +       "VRF name\n" +       "Prefix related information\n" +       "IPv4 prefix\n" +       "IPv6 prefix\n" +       "Specific VRF Route Distinguisher\n" +       "<as-number>:<number> or <ip-address>:<number>\n") +{ +  char *arg_vrf    = argv[2]->arg; +  char *arg_prefix = NULL;       /* optional */ +  char *arg_rd     = NULL;       /* optional */ +  int  pargc = 3; +  argc--;                       /* don't check parameter */ +  while (pargc < argc)  +    { +      switch (argv[pargc++]->arg[0]) +        { +        case 'r': +          arg_rd     = argv[pargc]->arg; +          break; +        case 'p': +          arg_prefix = argv[pargc]->arg; +          break; +        default: +          break; +        } +      pargc ++; +    } +  return vnc_clear_vrf (vty, NULL, arg_vrf, arg_prefix, arg_rd); +} + +DEFUN (clear_vrf_all, +       clear_vrf_all_cmd, +       "clear vrf NAME all", +       "Clear stored data\n" +       "From a VRF\n" +       "VRF name\n" +       "All prefixes\n") +{ +  char *arg_vrf    = argv[2]->arg; +  return vnc_clear_vrf (vty, NULL, arg_vrf, NULL, NULL); +} +  void rfapi_vty_init ()  {    install_element (ENABLE_NODE, &add_vnc_prefix_cost_life_lnh_cmd); @@ -4953,6 +5387,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); @@ -4977,6 +5413,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);  | 
