diff options
| -rw-r--r-- | ChangeLog | 64 | ||||
| -rw-r--r-- | bgpd/bgp_attr.c | 3 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 1529 | ||||
| -rw-r--r-- | bgpd/bgp_route.h | 15 | ||||
| -rw-r--r-- | bgpd/bgp_routemap.c | 161 | ||||
| -rw-r--r-- | bgpd/bgp_table.c | 3 | ||||
| -rw-r--r-- | bgpd/bgp_table.h | 11 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 692 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 193 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 22 | ||||
| -rw-r--r-- | lib/routemap.c | 131 | ||||
| -rw-r--r-- | lib/routemap.h | 6 | 
12 files changed, 2656 insertions, 174 deletions
@@ -1,3 +1,67 @@ +2004-09-13 Jose Luis Rubio <jrubio@dit.upm.es> +           (at Technical University of Madrid as part of Euro6ix Project) + +        Enhanced Route Server functionality and Route-Maps: + +        * bgpd/bgpd.h: Modified 'struct peer' and 'struct bgp_filter' to +        support rs-clients. A 'struct bgp_table *rib' has been added to the +        first (to mantain a separated RIB for each rs-client) and two new +        route-maps have been added to the last (for import/export policies). +        Added the following #defines: RMAP_{IN|OUT|IMPORT|EXPORT|MAX}, +        PEER_RMAP_TYPE_{IMPORT|EXPORT} and BGP_CLEAR_SOFT_RSCLIENT. + +        * bgpd/bgpd.c: Modified the functions that create/delete/etc peers in +        order to consider the new fields included in 'struct peer' for +        supporting rs-clients, i.e. the import/export route-maps and the +        'struct bgp_table'. + +        * bgpd/bgp_route.{ch}: Modified several functions related with +        receiving/sending announces in order to support the new Route Server +        capabilities. +        Function 'bgp_process' has been reorganized, creating an auxiliar +        function for best path selection ('bgp_best_selection'). +        Modified 'bgp_show' and 'bgp_show_route' for displaying information +        about any RIB (and not only the main bgp RIB). +        Added commands for displaying information about RS-clients RIBs: +        'show bgp rsclient (A.B.C.D|X:X::X:X)', 'show bgp rsclient +        (A.B.C.D|X:X::X:X) X:X::X:X/M', etc + +        * bgpd/bgp_table.{ch}: The structure 'struct bgp_table' now has two +        new fields: type (which can take the values BGP_TABLE_{MAIN|RSCLIENT}) +        and 'void *owner' which points to 'struct bgp' or 'struct peer' which +        owns the table. +        When creating a new bgp_table by default 'type=BGP_TABLE_MAIN' is set. + +        * bgpd/bgp_vty.c: The commands 'neighbor ... route-server-client' and +        'no neighbor ... route-server-client' now not only set/unset the flag +        PEER_FLAG_RSERVER_CLIENT, but they create/destroy the 'struct +        bgp_table' of the peer. Special actions are taken for peer_groups. +        Command 'neighbor ... route-map WORD (in|out)' now also supports two +        new kinds of route-map: 'import' and 'export'. +        Added commands 'clear bgp * rsclient', etc. These commands allow a new +        kind of soft_reconfig which affects only the RIB of the specified +        RS-client. +        Added commands 'show bgp rsclient summary', etc which display a +        summary of the rs-clients configured for the corresponding address +        family. + +        * bgpd/bgp_routemap.c: A new match statement is available, +        'match peer (A.B.C.D|X:X::X:X)'. This statement can only be used in +        import/export route-maps, and it matches when the peer who announces +        (when used in an import route-map) or is going to receive (when used +        in an export route-map) the route is the same than the one specified +        in the statement. +        For peer-groups the statement matches if the specified peer is member +        of the peer-group. +        A special version of the command, 'match peer local', matches with +        routes originated by the Route Server (defined with 'network ...', +        redistributed routes and default-originate). + +        * lib/routemap.{ch}: Added a new clause 'call NAME' for use in +        route-maps. It jumps into the specified route-map and when it returns +        the first route-map ends if the called RM returns DENY_MATCH, or +        continues in other case. +  2004-08-31  Greg Troxel  <gdt@poblano.ir.bbn.com>  	* Makefile.am: make m4 as subdir, rather the EXTRA_DISTing it diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index d745d871..c8f5ed62 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1365,8 +1365,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,    if (peer_sort (peer) == BGP_PEER_EBGP        && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)  	  || attr->aspath->length == 0) -      && ! (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) -	    && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))) +      && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))      {            aspath = aspath_dup (attr->aspath); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index cf65964b..6b49e2c8 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -58,16 +58,15 @@ extern char *bgp_origin_str[];  extern char *bgp_origin_long_str[];  struct bgp_node * -bgp_afi_node_get (struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p, +bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p,  		  struct prefix_rd *prd)  {    struct bgp_node *rn;    struct bgp_node *prn = NULL; -  struct bgp_table *table;    if (safi == SAFI_MPLS_VPN)      { -      prn = bgp_node_get (bgp->rib[afi][safi], (struct prefix *) prd); +      prn = bgp_node_get (table, (struct prefix *) prd);        if (prn->info == NULL)  	prn->info = bgp_table_init (); @@ -75,8 +74,6 @@ bgp_afi_node_get (struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p,  	bgp_unlock_node (prn);        table = prn->info;      } -  else -    table = bgp->rib[afi][safi];    rn = bgp_node_get (table, p); @@ -455,6 +452,77 @@ bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr,  }  int +bgp_export_modifier (struct peer *rsclient, struct peer *peer, +        struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) +{ +  struct bgp_filter *filter; +  struct bgp_info info; +  route_map_result_t ret; + +  filter = &peer->filter[afi][safi]; + +  /* Route map apply. */ +  if (ROUTE_MAP_EXPORT_NAME (filter)) +    { +      /* Duplicate current value to new strucutre for modification. */ +      info.peer = rsclient; +      info.attr = attr; + +      SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT); + +      /* Apply BGP route map to the attribute. */ +      ret = route_map_apply (ROUTE_MAP_EXPORT (filter), p, RMAP_BGP, &info); + +      rsclient->rmap_type = 0; + +      if (ret == RMAP_DENYMATCH) +        { +          /* Free newly generated AS path and community by route-map. */ +          bgp_attr_flush (attr); +          return RMAP_DENY; +        } +    } +  return RMAP_PERMIT; +} + +int +bgp_import_modifier (struct peer *rsclient, struct peer *peer, +        struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) +{ +  struct bgp_filter *filter; +  struct bgp_info info; +  route_map_result_t ret; + +  filter = &rsclient->filter[afi][safi]; + +  /* Apply default weight value. */ +  attr->weight = peer->weight; + +  /* Route map apply. */ +  if (ROUTE_MAP_IMPORT_NAME (filter)) +    { +      /* Duplicate current value to new strucutre for modification. */ +      info.peer = peer; +      info.attr = attr; + +      SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT); + +      /* Apply BGP route map to the attribute. */ +      ret = route_map_apply (ROUTE_MAP_IMPORT (filter), p, RMAP_BGP, &info); + +      peer->rmap_type = 0; + +      if (ret == RMAP_DENYMATCH) +        { +          /* Free newly generated AS path and community by route-map. */ +          bgp_attr_flush (attr); +          return RMAP_DENY; +        } +    } +  return RMAP_PERMIT; +} + +int  bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,  		    struct attr *attr, afi_t afi, safi_t safi)  { @@ -476,6 +544,10 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,    return 0;  #endif +  /* Do not send announces to RS-clients from the 'normal' bgp_table. */ +  if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +    return 0; +    /* Do not send back route to sender. */    if (from == peer)      return 0; @@ -636,7 +708,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,        || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)  	  && ((p->family == AF_INET && attr->nexthop.s_addr)  #ifdef HAVE_IPV6 -	      || (p->family == AF_INET6 && ri->peer != bgp->peer_self) +	      || (p->family == AF_INET6 &&  +                  ! IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global))  #endif /* HAVE_IPV6 */  	      )))      { @@ -645,7 +718,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,    else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF)  	   || (p->family == AF_INET && attr->nexthop.s_addr == 0)  #ifdef HAVE_IPV6 -	   || (p->family == AF_INET6 && ri->peer == bgp->peer_self) +	   || (p->family == AF_INET6 &&  +               IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global))  #endif /* HAVE_IPV6 */  	   || (peer_sort (peer) == BGP_PEER_EBGP  	       && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0)) @@ -673,6 +747,19 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,  #ifdef HAVE_IPV6    if (p->family == AF_INET6)      { +      /* Left nexthop_local unchanged if so configured. */  +      if ( CHECK_FLAG (peer->af_flags[afi][safi],  +           PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ) +        { +          if ( IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local) ) +            attr->mp_nexthop_len=32; +          else +            attr->mp_nexthop_len=16; +        } + +      /* Default nexthop_local treatment for non-RS-Clients */ +      else  +        {        /* Link-local address should not be transit to different peer. */        attr->mp_nexthop_len = 16; @@ -694,6 +781,8 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,        if (! IN6_IS_ADDR_LINKLOCAL (&peer->nexthop.v6_local))  	attr->mp_nexthop_len = 16;      } + +    }  #endif /* HAVE_IPV6 */    /* If this is EBGP peer and remove-private-AS is set.  */ @@ -737,20 +826,217 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,  }  int -bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) +bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, +        struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) +{ +  int ret; +  char buf[SU_ADDRSTRLEN]; +  struct bgp_filter *filter; +  struct bgp_info info; +  struct peer *from; +  struct bgp *bgp; + +  from = ri->peer; +  filter = &rsclient->filter[afi][safi]; +  bgp = rsclient->bgp; + +#ifdef DISABLE_BGP_ANNOUNCE +  return 0; +#endif + +  /* Do not send back route to sender. */ +  if (from == rsclient) +    return 0; + +  /* Aggregate-address suppress check. */ +  if (ri->suppress) +    if (! UNSUPPRESS_MAP_NAME (filter)) +      return 0; + +  /* Default route check.  */ +  if (CHECK_FLAG (rsclient->af_sflags[afi][safi], +          PEER_STATUS_DEFAULT_ORIGINATE)) +    { +      if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) +        return 0; +#ifdef HAVE_IPV6 +      else if (p->family == AF_INET6 && p->prefixlen == 0) +        return 0; +#endif /* HAVE_IPV6 */ +    } + +  /* If the attribute has originator-id and it is same as remote +     peer's id. */ +  if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) +    { +      if (IPV4_ADDR_SAME (&rsclient->remote_id, &ri->attr->originator_id)) +        { +         if (BGP_DEBUG (filter, FILTER)) +           zlog (rsclient->log, LOG_INFO, +                 "%s [Update:SEND] %s/%d originator-id is same as remote router-id", +                 rsclient->host, +                 inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +                 p->prefixlen); +         return 0; +       } +    } + +  /* ORF prefix-list filter check */ +  if (CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) +      && (CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) +         || CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))) +    if (rsclient->orf_plist[afi][safi]) +      { +       if (prefix_list_apply (rsclient->orf_plist[afi][safi], p) == PREFIX_DENY) +          return 0; +      } + +  /* Output filter check. */ +  if (bgp_output_filter (rsclient, p, ri->attr, afi, safi) == FILTER_DENY) +    { +      if (BGP_DEBUG (filter, FILTER)) +       zlog (rsclient->log, LOG_INFO, +             "%s [Update:SEND] %s/%d is filtered", +             rsclient->host, +             inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +             p->prefixlen); +      return 0; +    } + +#ifdef BGP_SEND_ASPATH_CHECK +  /* AS path loop check. */ +  if (aspath_loop_check (ri->attr->aspath, rsclient->as)) +    { +      if (BGP_DEBUG (filter, FILTER)) +        zlog (rsclient->log, LOG_INFO, +             "%s [Update:SEND] suppress announcement to peer AS %d is AS path.", +             rsclient->host, rsclient->as); +      return 0; +    } +#endif /* BGP_SEND_ASPATH_CHECK */ + +  /* For modify attribute, copy it to temporary structure. */ +  *attr = *ri->attr; + +  /* next-hop-set */ +  if ((p->family == AF_INET && attr->nexthop.s_addr == 0) +#ifdef HAVE_IPV6 +          || (p->family == AF_INET6 && +              IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global)) +#endif /* HAVE_IPV6 */ +     ) +  { +    /* Set IPv4 nexthop. */ +    if (p->family == AF_INET) +      { +        if (safi == SAFI_MPLS_VPN) +          memcpy (&attr->mp_nexthop_global_in, &rsclient->nexthop.v4, +                  IPV4_MAX_BYTELEN); +        else +          memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); +      } +#ifdef HAVE_IPV6 +    /* Set IPv6 nexthop. */ +    if (p->family == AF_INET6) +      { +        /* IPv6 global nexthop must be included. */ +        memcpy (&attr->mp_nexthop_global, &rsclient->nexthop.v6_global, + +                IPV6_MAX_BYTELEN); +        attr->mp_nexthop_len = 16; +      } +#endif /* HAVE_IPV6 */ +  } + +#ifdef HAVE_IPV6 +  if (p->family == AF_INET6) +    { +      /* Left nexthop_local unchanged if so configured. */ +      if ( CHECK_FLAG (rsclient->af_flags[afi][safi],  +           PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ) +        { +          if ( IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local) ) +            attr->mp_nexthop_len=32; +          else +            attr->mp_nexthop_len=16; +        } +         +      /* Default nexthop_local treatment for RS-Clients */ +      else  +        {  +          /* Announcer and RS-Client are both in the same network */       +          if (rsclient->shared_network && from->shared_network && +              (rsclient->ifindex == from->ifindex)) +            { +              if ( IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local) ) +                attr->mp_nexthop_len=32; +              else +                attr->mp_nexthop_len=16; +            } + +          /* Set link-local address for shared network peer. */ +          else if (rsclient->shared_network +              && IN6_IS_ADDR_LINKLOCAL (&rsclient->nexthop.v6_local)) +            { +              memcpy (&attr->mp_nexthop_local, &rsclient->nexthop.v6_local, +                      IPV6_MAX_BYTELEN); +              attr->mp_nexthop_len = 32; +            } + +          else +            attr->mp_nexthop_len = 16; +        } + +    } +#endif /* HAVE_IPV6 */ + + +  /* If this is EBGP peer and remove-private-AS is set.  */ +  if (peer_sort (rsclient) == BGP_PEER_EBGP +      && peer_af_flag_check (rsclient, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) +      && aspath_private_as_check (attr->aspath)) +    attr->aspath = aspath_empty_get (); + +  /* Route map & unsuppress-map apply. */ +  if (ROUTE_MAP_OUT_NAME (filter) || ri->suppress) +    { +      info.peer = rsclient; +      info.attr = attr; + +      SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_OUT); + +      if (ri->suppress) +        ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info); +      else +        ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info); + +      rsclient->rmap_type = 0; + +      if (ret == RMAP_DENYMATCH) +       { +         bgp_attr_flush (attr); +         return 0; +       } +    } + +  return 1; +} + +struct bgp_info_pair +{ +  struct bgp_info *old; +  struct bgp_info *new; +}; + +void +bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_info_pair *result)  { -  struct prefix *p; -  struct bgp_info *ri;    struct bgp_info *new_select;    struct bgp_info *old_select; -  struct listnode *nn; -  struct peer *peer; -  struct attr attr; +  struct bgp_info *ri;    struct bgp_info *ri1;    struct bgp_info *ri2; -  p = &rn->p; -    /* bgp deterministic-med */    new_select = NULL;    if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) @@ -811,17 +1097,8 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)  	new_select = ri;      } -  /* Nothing to do. */ -  if (old_select && old_select == new_select) -    { -      if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) +    if ( (! old_select) || old_select != new_select)  	{ -	  if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED)) -	    bgp_zebra_announce (p, old_select, bgp); -	  return 0; -	} -    } -    if (old_select)      UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED);    if (new_select) @@ -829,29 +1106,131 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)        SET_FLAG (new_select->flags, BGP_INFO_SELECTED);        UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED);      } +      } -  /* Check each BGP peer. */ -  LIST_LOOP (bgp->peer, peer, nn) +    result->old = old_select; +    result->new = new_select; + +    return; +} + +int +bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, +        struct bgp_node *rn, struct attr *attr, afi_t afi, safi_t safi)      { +  struct prefix *p; + +  p = &rn->p; +        /* Announce route to Established peer. */        if (peer->status != Established) -	continue; +    return 0;        /* Address family configuration check. */        if (! peer->afc_nego[afi][safi]) -	continue; +    return 0;        /* First update is deferred until ORF or ROUTE-REFRESH is received */ -      if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) -	continue; +  if (CHECK_FLAG (peer->af_sflags[afi][safi], +      PEER_STATUS_ORF_WAIT_REFRESH)) +    return 0; +  switch (rn->table->type) +    { +      case BGP_TABLE_MAIN:        /* Announcement to peer->conf.  If the route is filtered,           withdraw it. */ -      if (new_select  -	  && bgp_announce_check (new_select, peer, p, &attr, afi, safi)) -	bgp_adj_out_set (rn, peer, p, &attr, afi, safi, new_select); +        if (selected && bgp_announce_check (selected, peer, p, attr, afi, safi)) +          bgp_adj_out_set (rn, peer, p, attr, afi, safi, selected); +        else +          bgp_adj_out_unset (rn, peer, p, afi, safi); +        break; +      case BGP_TABLE_RSCLIENT: +        /* Announcement to peer->conf.  If the route is filtered,  +           withdraw it. */ +        if (selected && bgp_announce_check_rsclient +              (selected, peer, p, attr, afi, safi)) +          bgp_adj_out_set (rn, peer, p, attr, afi, safi, selected);        else  	bgp_adj_out_unset (rn, peer, p, afi, safi); +        break; +    } +  return 0; +    } + +int +bgp_process_rsclient (struct bgp *bgp, struct peer *rsclient, +        struct bgp_node *rn, afi_t afi, safi_t safi) +{ +  struct prefix *p; +  struct bgp_info *new_select; +  struct bgp_info *old_select; +  struct bgp_info_pair old_and_new; +  struct attr attr; +  struct peer_group *group; +  struct listnode *nn; + +  p = &rn->p; + +  /* Best path selection. */ +  bgp_best_selection (bgp, rn, &old_and_new); +  new_select = old_and_new.new; +  old_select = old_and_new.old; + +  if (CHECK_FLAG(rsclient->sflags, PEER_STATUS_GROUP)) +  { +    group = rsclient->group; +    LIST_LOOP(group->peer, rsclient, nn) +      { +        /* Nothing to do. */ +        if (old_select && old_select == new_select) +          if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) +            continue; + +        bgp_process_announce_selected (rsclient, new_select, rn, &attr,  +              afi, safi); +      } +    return 0; +  } + +  bgp_process_announce_selected (rsclient, new_select, rn, &attr, afi, safi); + +  return 0; +} + +int +bgp_process_main (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) +    { +  struct prefix *p; +  struct bgp_info *new_select; +  struct bgp_info *old_select; +  struct bgp_info_pair old_and_new; +  struct listnode *nn; +  struct peer *peer; +  struct attr attr; + +  p = &rn->p; + +  /* Best path selection. */ +  bgp_best_selection (bgp, rn, &old_and_new); +  old_select = old_and_new.old; +  new_select = old_and_new.new; + +  /* Nothing to do. */ +  if (old_select && old_select == new_select) +    { +      if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) +       { +         if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED)) +           bgp_zebra_announce (p, old_select, bgp); +         return 0; +       } +    } + +  /* Check each BGP peer. */ +  LIST_LOOP (bgp->peer, peer, nn) +    { +      bgp_process_announce_selected (peer, new_select, rn, &attr, afi, safi);      }    /* FIB update. */ @@ -875,6 +1254,20 @@ bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)  }  int +bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) +{ +  switch (rn->table->type) +    { +    case BGP_TABLE_MAIN: +      return bgp_process_main (bgp, rn, afi, safi); +    case BGP_TABLE_RSCLIENT: +      return bgp_process_rsclient (bgp, (struct peer *) rn->table->owner, +                                   rn, afi, safi); +    } +  return 0; +} +   +int  bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,                                safi_t safi, int always)  { @@ -940,8 +1333,12 @@ bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,  {    if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))      { +      /* Ignore 'pcount' for RS-client tables */ +      if ( rn->table->type == BGP_TABLE_MAIN) +        {        peer->pcount[afi][safi]--;        bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); +        }        UNSET_FLAG (ri->flags, BGP_INFO_VALID);        bgp_process (peer->bgp, rn, afi, safi);      } @@ -957,7 +1354,9 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,    int valid;    int status = BGP_DAMP_NONE; -  if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) +  /* Ignore 'pcount' for RS-client tables */ +  if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY) && +          rn->table->type == BGP_TABLE_MAIN)      {        peer->pcount[afi][safi]--;        bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); @@ -988,8 +1387,220 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,      }  } +void +bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, +      struct attr *attr, struct peer *peer, struct prefix *p, int type, +      int sub_type, struct prefix_rd *prd, u_char *tag) +{ +  struct bgp_node *rn; +  struct bgp *bgp; +  struct attr new_attr; +  struct attr *attr_new; +  struct attr *attr_new2; +  struct bgp_info *ri; +  struct bgp_info *new; +  char *reason; +  char buf[SU_ADDRSTRLEN]; + +  /* Do not insert announces from a rsclient into its own 'bgp_table'. */ +  if (peer == rsclient) +    return; + +  bgp = peer->bgp; +  rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, prd); + +  /* Check previously received route. */ +  for (ri = rn->info; ri; ri = ri->next) +    if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) +      break; + +  /* AS path loop check. */ +  if (aspath_loop_check (attr->aspath, rsclient->as) > peer->allowas_in[afi][safi]) +    { +      reason = "as-path contains our own AS;"; +      goto filtered; +    } + +  /* Route reflector originator ID check.  */ +  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID) +      && IPV4_ADDR_SAME (&rsclient->remote_id, &attr->originator_id)) +    { +      reason = "originator is us;"; +      goto filtered; +    } + +  new_attr = *attr; + +  /* Apply export policy. */ +  if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && +        bgp_export_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY) +    { +      reason = "export-policy;"; +      goto filtered; +    } + +  attr_new2 = bgp_attr_intern (&new_attr); + +  /* Apply import policy. */ +  if (bgp_import_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY) +    { +      bgp_attr_unintern (attr_new2); + +      reason = "import-policy;"; +      goto filtered; +    } + +  attr_new = bgp_attr_intern (&new_attr); +  bgp_attr_unintern (attr_new2); + +  /* IPv4 unicast next hop check.  */ +  if (afi == AFI_IP && safi == SAFI_UNICAST) +    { +     /* Next hop must not be 0.0.0.0 nor Class E address. */ +      if (new_attr.nexthop.s_addr == 0 +         || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000) +       { +         bgp_attr_unintern (attr_new); + +         reason = "martian next-hop;"; +         goto filtered; +       } +    } + +  /* If the update is implicit withdraw. */ +  if (ri) +    { +      ri->uptime = time (NULL); + +      /* Same attribute comes in. */ +      if (attrhash_cmp (ri->attr, attr_new)) +        { + +          UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + +          if (BGP_DEBUG (update, UPDATE_IN)) +            zlog (peer->log, LOG_INFO, +                    "%s rcvd %s/%d for RS-client %s...duplicate ignored", +                    peer->host, +                    inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +                    p->prefixlen, rsclient->host); + +                    bgp_unlock_node (rn); +                    bgp_attr_unintern (attr_new); + +                    return; +        } + +      /* Received Logging. */ +      if (BGP_DEBUG (update, UPDATE_IN)) +        zlog (peer->log, LOG_INFO, "%s rcvd %s/%d for RS-client %s", +                peer->host, +                inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +                p->prefixlen, rsclient->host); + +      /* The attribute is changed. */ +      SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + +      /* Update to new attribute.  */ +      bgp_attr_unintern (ri->attr); +      ri->attr = attr_new; + +      /* Update MPLS tag.  */ +      if (safi == SAFI_MPLS_VPN) +        memcpy (ri->tag, tag, 3); + +      SET_FLAG (ri->flags, BGP_INFO_VALID); + +      /* Process change. */ +      bgp_process (bgp, rn, afi, safi); +      bgp_unlock_node (rn); + +      return; +    } + +  /* Received Logging. */ +  if (BGP_DEBUG (update, UPDATE_IN)) +    { +      zlog (peer->log, LOG_INFO, "%s rcvd %s/%d for RS-client %s", +              peer->host, +              inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +              p->prefixlen, rsclient->host); +    } + +  /* Make new BGP info. */ +  new = bgp_info_new (); +  new->type = type; +  new->sub_type = sub_type; +  new->peer = peer; +  new->attr = attr_new; +  new->uptime = time (NULL); + +  /* Update MPLS tag. */ +  if (safi == SAFI_MPLS_VPN) +    memcpy (new->tag, tag, 3); + +  SET_FLAG (new->flags, BGP_INFO_VALID); + +  /* Register new BGP information. */ +  bgp_info_add (rn, new); + +  /* Process change. */ +  bgp_process (bgp, rn, afi, safi); + +  return; + + filtered:  + +  /* This BGP update is filtered.  Log the reason then update BGP entry.  */ +  if (BGP_DEBUG (update, UPDATE_IN)) +        zlog (peer->log, LOG_INFO, +        "%s rcvd UPDATE about %s/%d -- DENIED for RS-client %s due to: %s", +        peer->host, +        inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +        p->prefixlen, rsclient->host, reason); + +  if (ri) +    bgp_rib_withdraw (rn, ri, peer, afi, safi, 1); + +  bgp_unlock_node (rn); + +  return; +} + +void +bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, +      struct peer *peer, struct prefix *p, int type, int sub_type, +      struct prefix_rd *prd, u_char *tag) +    { +  struct bgp_node *rn; +  struct bgp_info *ri; +  char buf[SU_ADDRSTRLEN]; + +  if (rsclient == peer) +       return; + +  rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, prd); + +  /* Lookup withdrawn route. */ +  for (ri = rn->info; ri; ri = ri->next) +    if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) +      break; + +  /* Withdraw specified route from routing table. */ +  if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) +    bgp_rib_withdraw (rn, ri, peer, afi, safi, 0); +  else if (BGP_DEBUG (update, UPDATE_IN)) +    zlog (peer->log, LOG_INFO, +          "%s Can't find the route %s/%d", peer->host, +          inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +          p->prefixlen); + +  /* Unlock bgp_node_get() lock. */ +      bgp_unlock_node (rn); +    } +  int -bgp_update (struct peer *peer, struct prefix *p, struct attr *attr,  +bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,  	    afi_t afi, safi_t safi, int type, int sub_type,  	    struct prefix_rd *prd, u_char *tag, int soft_reconfig)  { @@ -1005,7 +1616,7 @@ bgp_update (struct peer *peer, struct prefix *p, struct attr *attr,    char buf[SU_ADDRSTRLEN];    bgp = peer->bgp; -  rn = bgp_afi_node_get (bgp, afi, safi, p, prd); +  rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);    /* When peer's soft reconfiguration enabled.  Record input packet in       Adj-RIBs-In.  */ @@ -1283,6 +1894,32 @@ bgp_update (struct peer *peer, struct prefix *p, struct attr *attr,  }  int +bgp_update (struct peer *peer, struct prefix *p, struct attr *attr, +            afi_t afi, safi_t safi, int type, int sub_type, +            struct prefix_rd *prd, u_char *tag, int soft_reconfig) +{ +  struct peer *rsclient; +  struct listnode *nn; +  struct bgp *bgp; +  int ret; + +  ret = bgp_update_main (peer, p, attr, afi, safi, type, sub_type, prd, tag, +          soft_reconfig); + +  bgp = peer->bgp; + +  /* Process the update for each RS-client. */ +  LIST_LOOP(bgp->rsclient, rsclient, nn) +    { +      if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +        bgp_update_rsclient (rsclient, afi, safi, attr, peer, p, type, +                sub_type, prd, tag); +    } + +  return ret; +} + +int  bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,   	     int afi, int safi, int type, int sub_type, struct prefix_rd *prd,  	      u_char *tag) @@ -1291,9 +1928,18 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,    char buf[SU_ADDRSTRLEN];    struct bgp_node *rn;    struct bgp_info *ri; +  struct peer *rsclient; +  struct listnode *nn;    bgp = peer->bgp; +  /* Process the withdraw for each RS-client. */ +  LIST_LOOP (bgp->rsclient, rsclient, nn) +    { +      if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +        bgp_withdraw_rsclient (rsclient, afi, safi, peer, p, type, sub_type, prd, tag); +    } +    /* Logging. */    if (BGP_DEBUG (update, UPDATE_IN))        zlog (peer->log, LOG_INFO, "%s rcvd UPDATE about %s/%d -- withdrawn", @@ -1302,7 +1948,7 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,  	  p->prefixlen);    /* Lookup node. */ -  rn = bgp_afi_node_get (bgp, afi, safi, p, prd); +  rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);    /* If peer is soft reconfiguration enabled.  Record input packet for       further calculation. */ @@ -1380,9 +2026,13 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)        binfo.peer = bgp->peer_self;        binfo.attr = &attr; +      SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT); +        ret = route_map_apply (peer->default_rmap[afi][safi].map, &p,  			     RMAP_BGP, &binfo); +      bgp->peer_self->rmap_type = 0; +        if (ret == RMAP_DENYMATCH)  	{  	  bgp_attr_flush (&attr); @@ -1407,14 +2057,14 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)  static void  bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, -		    struct bgp_table *table) +                   struct bgp_table *table, int rsclient)  {    struct bgp_node *rn;    struct bgp_info *ri;    struct attr attr;    if (! table) -    table = peer->bgp->rib[afi][safi]; +    table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi];    if (safi != SAFI_MPLS_VPN        && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) @@ -1424,7 +2074,9 @@ bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi,      for (ri = rn->info; ri; ri = ri->next)        if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->peer != peer)  	{ -	  if (bgp_announce_check (ri, peer, &rn->p, &attr, afi, safi)) +         if ( (rsclient) ? +              (bgp_announce_check_rsclient (ri, peer, &rn->p, &attr, afi, safi)) +              : (bgp_announce_check (ri, peer, &rn->p, &attr, afi, safi)))  	    bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri);  	  else  	    bgp_adj_out_unset (rn, peer, &rn->p, afi, safi); @@ -1448,12 +2100,15 @@ bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi)      return;    if (safi != SAFI_MPLS_VPN) -    bgp_announce_table (peer, afi, safi, NULL); +    bgp_announce_table (peer, afi, safi, NULL, 0);    else      for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;  	 rn = bgp_route_next(rn))        if ((table = (rn->info)) != NULL) -	bgp_announce_table (peer, afi, safi, table); +       bgp_announce_table (peer, afi, safi, table, 0); + +  if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +    bgp_announce_table (peer, afi, safi, NULL, 1);  }  void @@ -1468,6 +2123,40 @@ bgp_announce_route_all (struct peer *peer)  }  static void +bgp_soft_reconfig_table_rsclient (struct peer *rsclient, afi_t afi, +        safi_t safi, struct bgp_table *table) +{ +  struct bgp_node *rn; +  struct bgp_adj_in *ain; + +  if (! table) +    table = rsclient->bgp->rib[afi][safi]; + +  for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) +    for (ain = rn->adj_in; ain; ain = ain->next) +      { +        bgp_update_rsclient (rsclient, afi, safi, ain->attr, ain->peer, +                &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL); +      } +} + +void +bgp_soft_reconfig_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) +{ +  struct bgp_table *table; +  struct bgp_node *rn; +   +  if (safi != SAFI_MPLS_VPN) +    bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, NULL); + +  else +    for (rn = bgp_table_top (rsclient->bgp->rib[afi][safi]); rn; +            rn = bgp_route_next (rn)) +      if ((table = rn->info) != NULL) +        bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, table); +} + +static void  bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi,  			 struct bgp_table *table)  { @@ -1516,7 +2205,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)  static void  bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, -		       struct bgp_table *table) +                      struct bgp_table *table, struct peer *rsclient)  {    struct bgp_node *rn;    struct bgp_adj_in *ain; @@ -1524,7 +2213,7 @@ bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi,    struct bgp_info *ri;    if (! table) -    table = peer->bgp->rib[afi][safi]; +    table = (rsclient) ? rsclient->rib[afi][safi] : peer->bgp->rib[afi][safi];    for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))      { @@ -1556,17 +2245,25 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)  {    struct bgp_node *rn;    struct bgp_table *table; +  struct peer *rsclient; +  struct listnode *nn;    if (! peer->afc[afi][safi])      return;    if (safi != SAFI_MPLS_VPN) -    bgp_clear_route_table (peer, afi, safi, NULL); +    bgp_clear_route_table (peer, afi, safi, NULL, NULL);    else      for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;  	 rn = bgp_route_next (rn))        if ((table = rn->info) != NULL) -	bgp_clear_route_table (peer, afi, safi, table); +       bgp_clear_route_table (peer, afi, safi, table, NULL); + +  LIST_LOOP (peer->bgp->rsclient, rsclient, nn) +    { +      if (CHECK_FLAG(rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +        bgp_clear_route_table (peer, afi, safi, NULL, rsclient); +    }  }  void @@ -1821,7 +2518,174 @@ bgp_static_free (struct bgp_static *bgp_static)  }  void -bgp_static_update (struct bgp *bgp, struct prefix *p, +bgp_static_withdraw_rsclient (struct bgp *bgp, struct peer *rsclient, +        struct prefix *p, afi_t afi, safi_t safi) +{ +  struct bgp_node *rn; +  struct bgp_info *ri; + +  rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, NULL); + +  /* Check selected route and self inserted route. */ +  for (ri = rn->info; ri; ri = ri->next) +    if (ri->peer == bgp->peer_self +       && ri->type == ZEBRA_ROUTE_BGP +       && ri->sub_type == BGP_ROUTE_STATIC) +      break; + +  /* Withdraw static BGP route from routing table. */ +  if (ri) +    { +      UNSET_FLAG (ri->flags, BGP_INFO_VALID); +      bgp_process (bgp, rn, afi, safi); +      bgp_info_delete (rn, ri); +      bgp_info_free (ri); +      bgp_unlock_node (rn); +    } + +  /* Unlock bgp_node_lookup. */ +  bgp_unlock_node (rn); +} + +void +bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, +        struct bgp_static *bgp_static, afi_t afi, safi_t safi) +{ +  struct bgp_node *rn; +  struct bgp_info *ri; +  struct bgp_info *new; +  struct bgp_info info; +  struct attr new_attr; +  struct attr *attr_new; +  struct attr attr; +  struct bgp *bgp; +  int ret; +  char buf[SU_ADDRSTRLEN]; + +  bgp = rsclient->bgp; + +  rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, NULL); + +  bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); +  if (bgp_static) +    { +      attr.nexthop = bgp_static->igpnexthop; +      attr.med = bgp_static->igpmetric; +      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); +    } + +  new_attr = attr; + +  /* Apply network route-map for export to this rsclient. */ +  if (bgp_static->rmap.name) +    { +      info.peer = rsclient; +      info.attr = &new_attr; + +      SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT); +      SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_NETWORK); + +      ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); + +      rsclient->rmap_type = 0; + +      if (ret == RMAP_DENYMATCH) +        { +          /* Free uninterned attribute. */ +          bgp_attr_flush (&new_attr); + +          /* Unintern original. */ +          aspath_unintern (attr.aspath); +          bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); + +          return; +        } +      attr_new = bgp_attr_intern (&new_attr); +    } +  else +    attr_new = bgp_attr_intern (&attr); + +  new_attr = *attr_new; + +  SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); + +  if (bgp_import_modifier (rsclient, bgp->peer_self, p, &new_attr, afi, safi) == RMAP_DENY) +{ +      /* This BGP update is filtered.  Log the reason then update BGP entry.  */ +      if (BGP_DEBUG (update, UPDATE_IN)) +              zlog (rsclient->log, LOG_INFO, +              "Static UPDATE about %s/%d -- DENIED for RS-client %s due to: import-policy", +              inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), +              p->prefixlen, rsclient->host); + +      bgp->peer_self->rmap_type = 0; + +      bgp_attr_unintern (attr_new); +      aspath_unintern (attr.aspath); + +      bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); +       +      return; +	} + +  bgp->peer_self->rmap_type = 0; + +  bgp_attr_unintern (attr_new); +  attr_new = bgp_attr_intern (&new_attr); + +  for (ri = rn->info; ri; ri = ri->next) +    if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP +            && ri->sub_type == BGP_ROUTE_STATIC) +      break; + +  if (ri) +       { +      if (attrhash_cmp (ri->attr, attr_new)) +        { +          bgp_unlock_node (rn); +          bgp_attr_unintern (attr_new); +          aspath_unintern (attr.aspath); +          return; +       } +      else +        { +          /* The attribute is changed. */ +          SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); + +          /* Rewrite BGP route information. */ +          bgp_attr_unintern (ri->attr); +          ri->attr = attr_new; +          ri->uptime = time (NULL); + +          /* Process change. */ +          bgp_process (bgp, rn, afi, safi); +          bgp_unlock_node (rn); +          aspath_unintern (attr.aspath); +          return; +    } +} + +  /* Make new BGP info. */ +  new = bgp_info_new (); +  new->type = ZEBRA_ROUTE_BGP; +  new->sub_type = BGP_ROUTE_STATIC; +  new->peer = bgp->peer_self; +  SET_FLAG (new->flags, BGP_INFO_VALID); +  new->attr = attr_new; +  new->uptime = time (NULL); + +  /* Register new BGP information. */ +  bgp_info_add (rn, new); + +  /* Process change. */ +  bgp_process (bgp, rn, afi, safi); + +  /* Unintern original. */ +  aspath_unintern (attr.aspath); +} + +void +bgp_static_update_main (struct bgp *bgp, struct prefix *p,  		   struct bgp_static *bgp_static, afi_t afi, safi_t safi)  {    struct bgp_node *rn; @@ -1833,7 +2697,7 @@ bgp_static_update (struct bgp *bgp, struct prefix *p,    struct attr *attr_new;    int ret; -  rn = bgp_afi_node_get (bgp, afi, safi, p, NULL); +  rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, NULL);    bgp_attr_default_set (&attr, BGP_ORIGIN_IGP);    if (bgp_static) @@ -1850,8 +2714,12 @@ bgp_static_update (struct bgp *bgp, struct prefix *p,        info.peer = bgp->peer_self;        info.attr = &attr_tmp; +      SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); +        ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); +      bgp->peer_self->rmap_type = 0; +        if (ret == RMAP_DENYMATCH)  	{      	  /* Free uninterned attribute. */ @@ -1924,13 +2792,28 @@ bgp_static_update (struct bgp *bgp, struct prefix *p,  }  void +bgp_static_update (struct bgp *bgp, struct prefix *p, +                  struct bgp_static *bgp_static, afi_t afi, safi_t safi) +{ +  struct peer *rsclient; +  struct listnode *nn; + +  bgp_static_update_main (bgp, p, bgp_static, afi, safi); + +  LIST_LOOP(bgp->rsclient, rsclient, nn) +    { +      bgp_static_update_rsclient (rsclient, p, bgp_static, afi, safi); +    } +} + +void  bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,  			 u_char safi, struct prefix_rd *prd, u_char *tag)  {    struct bgp_node *rn;    struct bgp_info *new; -  rn = bgp_afi_node_get (bgp, afi, safi, p, prd); +  rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);    /* Make new BGP info. */    new = bgp_info_new (); @@ -1959,7 +2842,7 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,    struct bgp_node *rn;    struct bgp_info *ri; -  rn = bgp_afi_node_get (bgp, afi, safi, p, NULL); +  rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, NULL);    /* Check selected route and self inserted route. */    for (ri = rn->info; ri; ri = ri->next) @@ -1984,13 +2867,33 @@ bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,  }  void +bgp_check_local_routes_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) +{ +  struct bgp_static *bgp_static; +  struct bgp *bgp; +  struct bgp_node *rn; +  struct prefix *p; + +  bgp = rsclient->bgp; + +  for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) +    if ((bgp_static = rn->info) != NULL) +      { +        p = &rn->p; + +        bgp_static_update_rsclient (rsclient, p, bgp_static, +                afi, safi); +      } +} + +void  bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,  			   u_char safi, struct prefix_rd *prd, u_char *tag)  {    struct bgp_node *rn;    struct bgp_info *ri; -  rn = bgp_afi_node_get (bgp, afi, safi, p, prd); +  rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd);    /* Check selected route and self inserted route. */    for (ri = rn->info; ri; ri = ri->next) @@ -3602,8 +4505,13 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,  	      info.peer = bgp->peer_self;  	      info.attr = &attr_new; +              SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE); +  	      ret = route_map_apply (bgp->rmap[afi][type].map, p, RMAP_BGP,  				     &info); + +              bgp->peer_self->rmap_type = 0; +  	      if (ret == RMAP_DENYMATCH)  		{  		  /* Free uninterned attribute. */ @@ -3616,7 +4524,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,  		}  	    } -	  bn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL); +         bn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST], afi, SAFI_UNICAST, p, NULL);  	  new_attr = bgp_attr_intern (&attr_new);   	  for (bi = bn->info; bi; bi = bi->next) @@ -3686,7 +4594,7 @@ bgp_redistribute_delete (struct prefix *p, u_char type)        if (bgp->redist[afi][type])  	{ -	  rn = bgp_afi_node_get (bgp, afi, SAFI_UNICAST, p, NULL); +         rn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST], afi, SAFI_UNICAST, p, NULL);  	  for (ri = rn->info; ri; ri = ri->next)  	    if (ri->peer == bgp->peer_self @@ -4596,12 +5504,11 @@ bgp_show_callback (struct vty *vty, int unlock)  }  int -bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, +bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router_id,  	  enum bgp_show_type type)  {    struct bgp_info *ri;    struct bgp_node *rn; -  struct bgp_table *table;    int header = 1;    int count;    int limit; @@ -4612,24 +5519,12 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,  		   ? vty->lines : vty->height - 2));    limit = limit > 0 ? limit : 2; -  if (bgp == NULL) { -    bgp = bgp_get_default (); -  } - -  if (bgp == NULL) -    { -      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); -      return CMD_WARNING; -    } -    count = 0;    /* This is first entry point, so reset total line. */    vty->output_count = 0;    vty->output_type = type; -  table = bgp->rib[afi][safi]; -    /* Start processing of routes. */    for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))       if (rn->info != NULL) @@ -4782,7 +5677,7 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,  	    if (header)  	      { -		vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); +               vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (*router_id), VTY_NEWLINE);  		vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE);  		vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE);  		if (type == bgp_show_type_dampend_paths @@ -4861,6 +5756,28 @@ bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,    return CMD_SUCCESS;  } +int +bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, +         enum bgp_show_type type) +{ +  struct bgp_table *table; + +  if (bgp == NULL) { +    bgp = bgp_get_default (); +  } + +  if (bgp == NULL) +    { +      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +      return CMD_WARNING; +    } + + +  table = bgp->rib[afi][safi]; + +  return bgp_show_table (vty, table, &bgp->router_id, type); +} +  /* Header of detailed BGP route information */  void  route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, @@ -4946,7 +5863,8 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp,  /* Display specified route of BGP table. */  int -bgp_show_route (struct vty *vty, char *view_name, char *ip_str, +bgp_show_route_in_table (struct vty *vty, struct bgp *bgp,  +                         struct bgp_table *rib, char *ip_str,   		afi_t afi, safi_t safi, struct prefix_rd *prd,  		int prefix_check)  { @@ -4957,29 +5875,8 @@ bgp_show_route (struct vty *vty, char *view_name, char *ip_str,    struct bgp_node *rn;    struct bgp_node *rm;    struct bgp_info *ri; -  struct bgp *bgp;    struct bgp_table *table; -  /* BGP structure lookup. */ -  if (view_name) -    { -      bgp = bgp_lookup_by_name (view_name); -      if (bgp == NULL) -	{ -	  vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); -	  return CMD_WARNING; -	} -    } -  else -    { -      bgp = bgp_get_default (); -      if (bgp == NULL) -	{ -	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); -	  return CMD_WARNING; -	} -    } -    /* Check IP address argument. */    ret = str2prefix (ip_str, &match);    if (! ret) @@ -4992,7 +5889,7 @@ bgp_show_route (struct vty *vty, char *view_name, char *ip_str,    if (safi == SAFI_MPLS_VPN)      { -      for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) +      for (rn = bgp_table_top (rib); rn; rn = bgp_route_next (rn))          {            if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)              continue; @@ -5026,7 +5923,7 @@ bgp_show_route (struct vty *vty, char *view_name, char *ip_str,      {        header = 1; -      if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL) +      if ((rn = bgp_node_match (rib, &match)) != NULL)          {            if (! prefix_check || rn->p.prefixlen == match.prefixlen)              { @@ -5053,6 +5950,38 @@ bgp_show_route (struct vty *vty, char *view_name, char *ip_str,    return CMD_SUCCESS;  } +/* Display specified route of Main RIB */ +int +bgp_show_route (struct vty *vty, char *view_name, char *ip_str, +		afi_t afi, safi_t safi, struct prefix_rd *prd, +		int prefix_check) +{ +  struct bgp *bgp; + +  /* BGP structure lookup. */ +  if (view_name) +    { +      bgp = bgp_lookup_by_name (view_name); +      if (bgp == NULL) +	{ +	  vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } +  else +    { +      bgp = bgp_get_default (); +      if (bgp == NULL) +	{ +	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } +  +  return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str,  +                                   afi, safi, prd, prefix_check); +} +  /* BGP route print out function. */  DEFUN (show_ip_bgp,         show_ip_bgp_cmd, @@ -8132,6 +9061,204 @@ DEFUN (show_ip_bgp_ipv4_neighbor_routes,  				  bgp_show_type_neighbor);  } +DEFUN (show_ip_bgp_view_rsclient, +       show_ip_bgp_view_rsclient_cmd, +       "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X)", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "BGP view name\n" +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR) +{ +  struct bgp_table *table; +  struct peer *peer; + +  if (argc == 2) +    peer = peer_lookup_in_view (vty, argv[0], argv[1]); +  else +    peer = peer_lookup_in_view (vty, NULL, argv[0]); + +  if (! peer) +    return CMD_WARNING; + +  if (! peer->afc[AFI_IP][SAFI_UNICAST]) +    { +      vty_out (vty, "%% Activate the neighbor for the address family first%s", +            VTY_NEWLINE); +      return CMD_WARNING; +    } + +  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], +              PEER_FLAG_RSERVER_CLIENT)) +    { +      vty_out (vty, "%% Neighbor is not a Route-Server client%s", +            VTY_NEWLINE); +      return CMD_WARNING; +    } + +  table = peer->rib[AFI_IP][SAFI_UNICAST]; + +  return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal); +} + +ALIAS (show_ip_bgp_view_rsclient, +       show_ip_bgp_rsclient_cmd, +       "show ip bgp rsclient (A.B.C.D|X:X::X:X)", +       SHOW_STR +       IP_STR +       BGP_STR +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR) + +DEFUN (show_ip_bgp_view_rsclient_route, +       show_ip_bgp_view_rsclient_route_cmd, +       "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "BGP view name\n" +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR +       "Network in the BGP routing table to display\n") +{ +  struct bgp *bgp; +  struct peer *peer; + +  /* BGP structure lookup. */ +  if (argc == 3) +    { +      bgp = bgp_lookup_by_name (argv[0]); +      if (bgp == NULL) +	{ +	  vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } +  else +    { +      bgp = bgp_get_default (); +      if (bgp == NULL) +	{ +	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } + +  if (argc == 3) +    peer = peer_lookup_in_view (vty, argv[0], argv[1]); +  else +    peer = peer_lookup_in_view (vty, NULL, argv[0]); + +  if (! peer) +    return CMD_WARNING; + +  if (! peer->afc[AFI_IP][SAFI_UNICAST]) +    { +      vty_out (vty, "%% Activate the neighbor for the address family first%s", +            VTY_NEWLINE); +      return CMD_WARNING; +} + +  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], +              PEER_FLAG_RSERVER_CLIENT)) +    { +      vty_out (vty, "%% Neighbor is not a Route-Server client%s", +            VTY_NEWLINE); +      return CMD_WARNING; +    } +  +  return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST],  +                                  (argc == 3) ? argv[2] : argv[1], +                                  AFI_IP, SAFI_UNICAST, NULL, 0); +} + +ALIAS (show_ip_bgp_view_rsclient_route, +       show_ip_bgp_rsclient_route_cmd, +       "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D", +       SHOW_STR +       IP_STR +       BGP_STR +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR +       "Network in the BGP routing table to display\n") + +DEFUN (show_ip_bgp_view_rsclient_prefix, +       show_ip_bgp_view_rsclient_prefix_cmd, +       "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "BGP view name\n" +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") +{ +  struct bgp *bgp; +  struct peer *peer; + +  /* BGP structure lookup. */ +  if (argc == 3) +    { +      bgp = bgp_lookup_by_name (argv[0]); +      if (bgp == NULL) +	{ +	  vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } +  else +    { +      bgp = bgp_get_default (); +      if (bgp == NULL) +	{ +	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +	  return CMD_WARNING; +	} +    } + +  if (argc == 3) +    peer = peer_lookup_in_view (vty, argv[0], argv[1]); +  else +  peer = peer_lookup_in_view (vty, NULL, argv[0]); + +  if (! peer) +    return CMD_WARNING; +     +  if (! peer->afc[AFI_IP][SAFI_UNICAST]) +    { +      vty_out (vty, "%% Activate the neighbor for the address family first%s", +            VTY_NEWLINE); +      return CMD_WARNING; +} + +  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], +              PEER_FLAG_RSERVER_CLIENT)) +{ +      vty_out (vty, "%% Neighbor is not a Route-Server client%s", +            VTY_NEWLINE); +    return CMD_WARNING; +    } +     +  return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST],  +                                  (argc == 3) ? argv[2] : argv[1], +                                  AFI_IP, SAFI_UNICAST, NULL, 1); +} + +ALIAS (show_ip_bgp_view_rsclient_prefix, +       show_ip_bgp_rsclient_prefix_cmd, +       "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", +       SHOW_STR +       IP_STR +       BGP_STR +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR +       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n") + +  #ifdef HAVE_IPV6  DEFUN (show_bgp_view_neighbor_routes,         show_bgp_view_neighbor_routes_cmd, @@ -8347,6 +9474,198 @@ ALIAS (show_bgp_view_neighbor_damp,         "Neighbor to display information about\n"         "Neighbor to display information about\n"         "Display the dampened routes received from neighbor\n") + +DEFUN (show_bgp_view_rsclient, +       show_bgp_view_rsclient_cmd, +       "show bgp view WORD rsclient (A.B.C.D|X:X::X:X)", +       SHOW_STR +       BGP_STR +       "BGP view\n" +       "BGP view name\n" +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR) +{ +  struct bgp_table *table; +  struct peer *peer; + +  if (argc == 2) +    peer = peer_lookup_in_view (vty, argv[0], argv[1]); +  else +    peer = peer_lookup_in_view (vty, NULL, argv[0]); + +  if (! peer) +    return CMD_WARNING; + +  if (! peer->afc[AFI_IP6][SAFI_UNICAST]) +    { +      vty_out (vty, "%% Activate the neighbor for the address family first%s", +            VTY_NEWLINE); +      return CMD_WARNING; +    } + +  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], +              PEER_FLAG_RSERVER_CLIENT)) +    { +      vty_out (vty, "%% Neighbor is not a Route-Server client%s", +            VTY_NEWLINE); +      return CMD_WARNING; +    } + +  table = peer->rib[AFI_IP6][SAFI_UNICAST]; + +  return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal); +} + +ALIAS (show_bgp_view_rsclient, +       show_bgp_rsclient_cmd, +       "show bgp rsclient (A.B.C.D|X:X::X:X)", +       SHOW_STR +       BGP_STR +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR) + +DEFUN (show_bgp_view_rsclient_route, +       show_bgp_view_rsclient_route_cmd, +       "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X", +       SHOW_STR +       BGP_STR +       "BGP view\n" +       "BGP view name\n" +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR +       "Network in the BGP routing table to display\n") +{ +  struct bgp *bgp; +  struct peer *peer; + +  /* BGP structure lookup. */ +  if (argc == 3) +    { +      bgp = bgp_lookup_by_name (argv[0]); +      if (bgp == NULL) +        { +          vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); +          return CMD_WARNING; +        } +    } +  else +    { +      bgp = bgp_get_default (); +      if (bgp == NULL) +        { +          vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +          return CMD_WARNING; +        } +    } + +  if (argc == 3) +    peer = peer_lookup_in_view (vty, argv[0], argv[1]); +  else +    peer = peer_lookup_in_view (vty, NULL, argv[0]); + +  if (! peer) +    return CMD_WARNING; + +  if (! peer->afc[AFI_IP6][SAFI_UNICAST]) +    { +      vty_out (vty, "%% Activate the neighbor for the address family first%s", +            VTY_NEWLINE); +      return CMD_WARNING; +    } + +  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], +              PEER_FLAG_RSERVER_CLIENT)) +    { +      vty_out (vty, "%% Neighbor is not a Route-Server client%s", +            VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], +                                  (argc == 3) ? argv[2] : argv[1], +                                  AFI_IP6, SAFI_UNICAST, NULL, 0); +} + +ALIAS (show_bgp_view_rsclient_route, +       show_bgp_rsclient_route_cmd, +       "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X", +       SHOW_STR +       BGP_STR +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR +       "Network in the BGP routing table to display\n") + +DEFUN (show_bgp_view_rsclient_prefix, +       show_bgp_view_rsclient_prefix_cmd, +       "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", +       SHOW_STR +       BGP_STR +       "BGP view\n" +       "BGP view name\n" +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR +       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n") +{ +  struct bgp *bgp; +  struct peer *peer; + +  /* BGP structure lookup. */ +  if (argc == 3) +    { +      bgp = bgp_lookup_by_name (argv[0]); +      if (bgp == NULL) +        { +          vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); +          return CMD_WARNING; +        } +    } +  else +    { +      bgp = bgp_get_default (); +      if (bgp == NULL) +        { +          vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); +          return CMD_WARNING; +        } +    } + +  if (argc == 3) +    peer = peer_lookup_in_view (vty, argv[0], argv[1]); +  else +    peer = peer_lookup_in_view (vty, NULL, argv[0]); + +  if (! peer) +    return CMD_WARNING; + +  if (! peer->afc[AFI_IP6][SAFI_UNICAST]) +    { +      vty_out (vty, "%% Activate the neighbor for the address family first%s", +            VTY_NEWLINE); +      return CMD_WARNING; +    } + +  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], +              PEER_FLAG_RSERVER_CLIENT)) +    { +      vty_out (vty, "%% Neighbor is not a Route-Server client%s", +            VTY_NEWLINE); +      return CMD_WARNING; +    } + +  return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], +                                  (argc == 3) ? argv[2] : argv[1], +                                  AFI_IP6, SAFI_UNICAST, NULL, 1); +} + +ALIAS (show_bgp_view_rsclient_prefix, +       show_bgp_rsclient_prefix_cmd, +       "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", +       SHOW_STR +       BGP_STR +       "Information about Route Server Client\n" +       NEIGHBOR_ADDR_STR +       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n") +  #endif /* HAVE_IPV6 */  struct bgp_table *bgp_distance_table; @@ -9243,6 +10562,12 @@ bgp_route_init ()    install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd);    install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd);    install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd);    install_element (ENABLE_NODE, &show_ip_bgp_cmd);    install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd); @@ -9311,6 +10636,12 @@ bgp_route_init ()    install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd);    install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd);    install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_rsclient_route_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_rsclient_prefix_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_route_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_prefix_cmd);   /* BGP dampening clear commands */    install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd); @@ -9389,6 +10720,9 @@ bgp_route_init ()    install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_flap_cmd);    install_element (VIEW_NODE, &show_bgp_neighbor_damp_cmd);    install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_damp_cmd); +  install_element (VIEW_NODE, &show_bgp_rsclient_cmd); +  install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd); +  install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd);    install_element (VIEW_NODE, &show_bgp_view_cmd);    install_element (VIEW_NODE, &show_bgp_view_ipv6_cmd);    install_element (VIEW_NODE, &show_bgp_view_route_cmd); @@ -9407,6 +10741,9 @@ bgp_route_init ()    install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd);    install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd);    install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd);  +  install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd); +  install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); +  install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd);    install_element (ENABLE_NODE, &show_bgp_cmd);    install_element (ENABLE_NODE, &show_bgp_ipv6_cmd); @@ -9458,6 +10795,9 @@ bgp_route_init ()    install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_flap_cmd);    install_element (ENABLE_NODE, &show_bgp_neighbor_damp_cmd);    install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_damp_cmd); +  install_element (ENABLE_NODE, &show_bgp_rsclient_cmd); +  install_element (ENABLE_NODE, &show_bgp_rsclient_route_cmd); +  install_element (ENABLE_NODE, &show_bgp_rsclient_prefix_cmd);    install_element (ENABLE_NODE, &show_bgp_view_cmd);    install_element (ENABLE_NODE, &show_bgp_view_ipv6_cmd);    install_element (ENABLE_NODE, &show_bgp_view_route_cmd); @@ -9476,6 +10816,9 @@ bgp_route_init ()    install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd);    install_element (ENABLE_NODE, &show_bgp_view_neighbor_damp_cmd);    install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); +  install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd); +  install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd); +  install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd);    /* old command */    install_element (VIEW_NODE, &show_ipv6_bgp_cmd); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 273ed41a..9aad7238 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -109,10 +109,15 @@ struct bgp_static  #define FILTER_LIST_OUT_NAME(F) ((F)->aslist[FILTER_OUT].name)  #define FILTER_LIST_OUT(F)      ((F)->aslist[FILTER_OUT].aslist) -#define ROUTE_MAP_IN_NAME(F)    ((F)->map[FILTER_IN].name) -#define ROUTE_MAP_IN(F)         ((F)->map[FILTER_IN].map) -#define ROUTE_MAP_OUT_NAME(F)   ((F)->map[FILTER_OUT].name) -#define ROUTE_MAP_OUT(F)        ((F)->map[FILTER_OUT].map) +#define ROUTE_MAP_IN_NAME(F)    ((F)->map[RMAP_IN].name) +#define ROUTE_MAP_IN(F)         ((F)->map[RMAP_IN].map) +#define ROUTE_MAP_OUT_NAME(F)   ((F)->map[RMAP_OUT].name) +#define ROUTE_MAP_OUT(F)        ((F)->map[RMAP_OUT].map) + +#define ROUTE_MAP_IMPORT_NAME(F)    ((F)->map[RMAP_IMPORT].name) +#define ROUTE_MAP_IMPORT(F)    ((F)->map[RMAP_IMPORT].map) +#define ROUTE_MAP_EXPORT_NAME(F)    ((F)->map[RMAP_EXPORT].name) +#define ROUTE_MAP_EXPORT(F)    ((F)->map[RMAP_EXPORT].map)  #define UNSUPPRESS_MAP_NAME(F)  ((F)->usmap.name)  #define UNSUPPRESS_MAP(F)       ((F)->usmap.map) @@ -124,6 +129,8 @@ void bgp_announce_route (struct peer *, afi_t, safi_t);  void bgp_announce_route_all (struct peer *);  void bgp_default_originate (struct peer *, afi_t, safi_t, int);  void bgp_soft_reconfig_in (struct peer *, afi_t, safi_t); +void bgp_soft_reconfig_rsclient (struct peer *, afi_t, safi_t); +void bgp_check_local_routes_rsclient (struct peer *rsclient, afi_t afi, safi_t safi);  void bgp_clear_route (struct peer *, afi_t, safi_t);  void bgp_clear_route_all (struct peer *);  void bgp_clear_adj_in (struct peer *, afi_t, safi_t); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 261f6b87..c49c2e99 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -95,6 +95,103 @@ o Local extention  */  + /* 'match peer (A.B.C.D|X:X::X:X)' */ + +/* Compares the peer specified in the 'match peer' clause with the peer +    received in bgp_info->peer. If it is the same, or if the peer structure +    received is a peer_group containing it, returns RMAP_MATCH. */ +route_map_result_t +route_match_peer (void *rule, struct prefix *prefix, route_map_object_t type, +      void *object) +{ +  union sockunion *su; +  union sockunion *su2; +  struct peer_group *group; +  struct peer *peer; +  struct listnode *nn; + +  if (type == RMAP_BGP) +    { +      su = rule; +      peer = ((struct bgp_info *) object)->peer; + +      if ( ! CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT) && +           ! CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_EXPORT) ) +        return RMAP_NOMATCH; + +      /* If su='0.0.0.0' (command 'match peer local'), and it's a NETWORK, +          REDISTRIBUTE or DEFAULT_GENERATED route => return RMAP_MATCH */ +      su2 = sockunion_str2su ("0.0.0.0"); +      if ( sockunion_same (su, su2) ) +        { +          if ( CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_NETWORK) || +               CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE) || +               CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_DEFAULT)) +            { +              XFREE (MTYPE_SOCKUNION, su2); + +              return RMAP_MATCH; +            } +          else +            return RMAP_NOMATCH; +        } +      XFREE (MTYPE_SOCKUNION, su2); + +      if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +        { +          if (sockunion_same (su, &peer->su)) +            return RMAP_MATCH; + +          return RMAP_NOMATCH; +        } +      else +        { +          group = peer->group; +          LIST_LOOP (group->peer, peer, nn) +            { +              if (sockunion_same (su, &peer->su)) +                return RMAP_MATCH; + +              return RMAP_NOMATCH; +            } +        } +    } +  return RMAP_NOMATCH; +} + +void * +route_match_peer_compile (char *arg) +{ +  union sockunion *su; +  int ret; + +  su = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union sockunion)); + +  ret = str2sockunion ( (arg)? arg : "0.0.0.0", su); +  if (ret < 0) { +    XFREE (MTYPE_ROUTE_MAP_COMPILED, su); +    return NULL; +  } + +  return su; +} + +/* Free route map's compiled `ip address' value. */ +void +route_match_peer_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip address matching. */ +struct route_map_rule_cmd route_match_peer_cmd = +{ +  "peer", +  route_match_peer, +  route_match_peer_compile, +  route_match_peer_free +}; +  /* `match ip address IP_ACCESS_LIST' */  /* Match function should return 1 if match is success else return @@ -643,7 +740,8 @@ route_set_ip_nexthop (void *rule, struct prefix *prefix,        if (rins->peer_address)  	{ -	  if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN)  +         if ((CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN) || +           CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT))  	      && peer->su_remote   	      && sockunion_family (peer->su_remote) == AF_INET)  	    { @@ -1974,7 +2072,7 @@ bgp_route_map_update (char *unused)  	      {  		filter = &peer->filter[afi][safi]; -		for (direct = FILTER_IN; direct < FILTER_MAX; direct++) +               for (direct = RMAP_IN; direct < RMAP_MAX; direct++)  		  {  		    if (filter->map[direct].name)  		      filter->map[direct].map =  @@ -1996,7 +2094,7 @@ bgp_route_map_update (char *unused)  	      {  		filter = &group->conf->filter[afi][safi]; -		for (direct = FILTER_IN; direct < FILTER_MAX; direct++) +               for (direct = RMAP_IN; direct < RMAP_MAX; direct++)  		  {  		    if (filter->map[direct].name)  		      filter->map[direct].map =  @@ -2064,6 +2162,57 @@ bgp_route_map_update (char *unused)      }  } +DEFUN (match_peer, +       match_peer_cmd, +       "match peer (A.B.C.D|X:X::X:X)", +       MATCH_STR +       "Match peer address\n" +       "IPv6 address of peer\n" +       "IP address of peer\n") +{ +  return bgp_route_match_add (vty, vty->index, "peer", argv[0]); +} + +DEFUN (match_peer_local, +        match_peer_local_cmd, +        "match peer local", +        MATCH_STR +        "Match peer address\n" +        "Static or Redistributed routes\n") +{ +  return bgp_route_match_add (vty, vty->index, "peer", NULL); +} + +DEFUN (no_match_peer, +       no_match_peer_cmd, +       "no match peer", +       NO_STR +       MATCH_STR +       "Match peer address\n") +{ + if (argc == 0) +   return bgp_route_match_delete (vty, vty->index, "peer", NULL); + +  return bgp_route_match_delete (vty, vty->index, "peer", argv[0]); +} + +ALIAS (no_match_peer, +       no_match_peer_val_cmd, +       "no match peer (A.B.C.D|X:X::X:X)", +       NO_STR +       MATCH_STR +       "Match peer address\n" +       "IPv6 address of peer\n" +       "IP address of peer\n") + +ALIAS (no_match_peer, +       no_match_peer_local_cmd, +       "no match peer local", +       NO_STR +       MATCH_STR +       "Match peer address\n" +       "Static or Redistributed routes\n") +  DEFUN (match_ip_address,          match_ip_address_cmd,         "match ip address (<1-199>|<1300-2699>|WORD)", @@ -3239,6 +3388,7 @@ bgp_route_map_init ()    route_map_add_hook (bgp_route_map_update);    route_map_delete_hook (bgp_route_map_update); +  route_map_install_match (&route_match_peer_cmd);    route_map_install_match (&route_match_ip_address_cmd);    route_map_install_match (&route_match_ip_next_hop_cmd);    route_map_install_match (&route_match_ip_address_prefix_list_cmd); @@ -3264,6 +3414,11 @@ bgp_route_map_init ()    route_map_install_set (&route_set_ecommunity_rt_cmd);    route_map_install_set (&route_set_ecommunity_soo_cmd); +  install_element (RMAP_NODE, &match_peer_cmd); +  install_element (RMAP_NODE, &match_peer_local_cmd); +  install_element (RMAP_NODE, &no_match_peer_cmd); +  install_element (RMAP_NODE, &no_match_peer_val_cmd); +  install_element (RMAP_NODE, &no_match_peer_local_cmd);    install_element (RMAP_NODE, &match_ip_address_cmd);    install_element (RMAP_NODE, &no_match_ip_address_cmd);    install_element (RMAP_NODE, &no_match_ip_address_val_cmd); diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index a2a3c97b..c468173d 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -38,6 +38,9 @@ bgp_table_init (void)    rt = XMALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table));    memset (rt, 0, sizeof (struct bgp_table)); + +  rt->type = BGP_TABLE_MAIN; +    return rt;  } diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 52eb6a49..f979ac6f 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -18,8 +18,19 @@ along with GNU Zebra; see the file COPYING.  If not, write to the Free  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */ +typedef enum +{ +  BGP_TABLE_MAIN, +  BGP_TABLE_RSCLIENT, +} bgp_table_t; +  struct bgp_table  { +  bgp_table_t type; + +  /* The owner of this 'bgp_table' structure. */ +  void *owner; +    struct bgp_node *top;  }; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index c7de8eb6..92918bdf 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -39,6 +39,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "bgpd/bgp_open.h"  #include "bgpd/bgp_route.h"  #include "bgpd/bgp_zebra.h" +#include "bgpd/bgp_table.h"  /* Utility function to get address family from current node.  */  afi_t @@ -1648,7 +1649,7 @@ DEFUN (no_neighbor_dont_capability_negotiate,  int  peer_af_flag_modify_vty (struct vty *vty, char *peer_str, afi_t afi, -			 safi_t safi, u_int16_t flag, int set) +			 safi_t safi, u_int32_t flag, int set)  {    int ret;    struct peer *peer; @@ -1667,14 +1668,14 @@ peer_af_flag_modify_vty (struct vty *vty, char *peer_str, afi_t afi,  int  peer_af_flag_set_vty (struct vty *vty, char *peer_str, afi_t afi, -		      safi_t safi, u_int16_t flag) +		      safi_t safi, u_int32_t flag)  {    return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 1);  }  int  peer_af_flag_unset_vty (struct vty *vty, char *peer_str, afi_t afi, -			safi_t safi, u_int16_t flag) +			safi_t safi, u_int32_t flag)  {    return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 0);  } @@ -1923,6 +1924,134 @@ DEFUN (no_neighbor_route_reflector_client,  				 PEER_FLAG_REFLECTOR_CLIENT);  } +int +peer_rsclient_set_vty (struct vty *vty, char *peer_str, int afi, int safi) +{ +  int ret; +  struct bgp *bgp; +  struct peer *peer; +  struct peer_group *group; +  struct listnode *nn; +  struct bgp_filter *pfilter; +  struct bgp_filter *gfilter; + +  bgp = vty->index; + +  peer = peer_and_group_lookup_vty (vty, peer_str); +  if ( ! peer ) +    return CMD_WARNING; + +  /* If it is already a RS-Client, don't do anything. */ +  if ( CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ) +    return CMD_SUCCESS; + +  if ( ! peer_rsclient_active (peer) ) +    listnode_add_sort (bgp->rsclient, peer); + +  ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); +  if (ret < 0) +    return bgp_vty_return (vty, ret); + +  peer->rib[afi][safi] = bgp_table_init (); +  peer->rib[afi][safi]->type = BGP_TABLE_RSCLIENT; +  peer->rib[afi][safi]->owner = peer; + +  /* Check for existing 'network' and 'redistribute' routes. */ +  bgp_check_local_routes_rsclient (peer, afi, safi); + +  /* Check for routes for peers configured with 'soft-reconfiguration'. */ +  bgp_soft_reconfig_rsclient (peer, afi, safi); + +  if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) +    { +      group = peer->group; +      gfilter = &peer->filter[afi][safi]; + +      LIST_LOOP(group->peer, peer, nn) +        { +          pfilter = &peer->filter[afi][safi]; + +          /* Members of a non-RS-Client group should not be RS-Clients, as that  +             is checked when the become part of the peer-group */ +          ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); +          if (ret < 0) +            return bgp_vty_return (vty, ret); + +          /* Make peer's RIB point to group's RIB. */ +          peer->rib[afi][safi] = group->conf->rib[afi][safi]; + +          /* Import policy. */ +          if (pfilter->map[RMAP_IMPORT].name) +            free (pfilter->map[RMAP_IMPORT].name); +          if (gfilter->map[RMAP_IMPORT].name) +            { +              pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); +              pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map; +            } +          else +            { +              pfilter->map[RMAP_IMPORT].name = NULL; +              pfilter->map[RMAP_IMPORT].map =NULL; +            } + +          /* Export policy. */ +          if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) +            { +              pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); +              pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map; +            } +        } +    } +  return CMD_SUCCESS; +} + +int +peer_rsclient_unset_vty (struct vty *vty, char *peer_str, int afi, int safi) +{ +  int ret; +  struct bgp *bgp; +  struct peer *peer; +  struct peer_group *group; +  struct listnode *nn; + +  bgp = vty->index; + +  peer = peer_and_group_lookup_vty (vty, peer_str); +  if ( ! peer ) +    return CMD_WARNING; + +  /* If it is not a RS-Client, don't do anything. */ +  if ( ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ) +    return CMD_SUCCESS; + +  if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) +    { +      group = peer->group; + +      LIST_LOOP (group->peer, peer, nn) +        { +          ret = peer_af_flag_unset (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); +          if (ret < 0) +            return bgp_vty_return (vty, ret); + +          peer->rib[afi][safi] = NULL; +        } + +        peer = group->conf; +    } + +  ret = peer_af_flag_unset (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); +  if (ret < 0) +    return bgp_vty_return (vty, ret); + +  if ( ! peer_rsclient_active (peer) ) +    listnode_delete (bgp->rsclient, peer); + +  bgp_table_finish (peer->rib[bgp_node_afi(vty)][bgp_node_safi(vty)]); + +  return CMD_SUCCESS; +} +  /* neighbor route-server-client. */  DEFUN (neighbor_route_server_client,         neighbor_route_server_client_cmd, @@ -1931,9 +2060,8 @@ DEFUN (neighbor_route_server_client,         NEIGHBOR_ADDR_STR2         "Configure a neighbor as Route Server client\n")  { -  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), -			       bgp_node_safi (vty), -			       PEER_FLAG_RSERVER_CLIENT); +  return peer_rsclient_set_vty (vty, argv[0], bgp_node_afi(vty), +                  bgp_node_safi(vty));  }  DEFUN (no_neighbor_route_server_client, @@ -1944,9 +2072,35 @@ DEFUN (no_neighbor_route_server_client,         NEIGHBOR_ADDR_STR2         "Configure a neighbor as Route Server client\n")  { +  return peer_rsclient_unset_vty (vty, argv[0], bgp_node_afi(vty), +                  bgp_node_safi(vty)); +} + +DEFUN (neighbor_nexthop_local_unchanged, +       neighbor_nexthop_local_unchanged_cmd, +       NEIGHBOR_CMD2 "nexthop-local unchanged", +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Configure treatment of outgoing link-local nexthop attribute\n" +       "Leave link-local nexthop unchanged for this peer\n") +{ +  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), +                                bgp_node_safi (vty), +                                PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED ); +} + +DEFUN (no_neighbor_nexthop_local_unchanged, +       no_neighbor_nexthop_local_unchanged_cmd, +       NO_NEIGHBOR_CMD2 "nexthop-local unchanged", +       NO_STR +       NEIGHBOR_STR +       NEIGHBOR_ADDR_STR2 +       "Configure treatment of outgoing link-local-nexthop attribute\n" +       "Leave link-local nexthop unchanged for this peer\n") +{    return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),  				 bgp_node_safi (vty), -				 PEER_FLAG_RSERVER_CLIENT); +                                PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED );  }  DEFUN (neighbor_attr_unchanged, @@ -3265,17 +3419,21 @@ peer_route_map_set_vty (struct vty *vty, char *ip_str, afi_t afi, safi_t safi,  {    int ret;    struct peer *peer; -  int direct = FILTER_IN; +  int direct = RMAP_IN;    peer = peer_and_group_lookup_vty (vty, ip_str);    if (! peer)      return CMD_WARNING;    /* Check filter direction. */ -  if (strncmp (direct_str, "i", 1) == 0) -    direct = FILTER_IN; +  if (strncmp (direct_str, "in", 2) == 0) +    direct = RMAP_IN;    else if (strncmp (direct_str, "o", 1) == 0) -    direct = FILTER_OUT; +    direct = RMAP_OUT; +  else if (strncmp (direct_str, "im", 2) == 0) +    direct = RMAP_IMPORT; +  else if (strncmp (direct_str, "e", 1) == 0) +    direct = RMAP_EXPORT;    ret = peer_route_map_set (peer, afi, safi, direct, name_str); @@ -3288,18 +3446,21 @@ peer_route_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi,  {    int ret;    struct peer *peer; -  int direct = FILTER_IN; +  int direct = RMAP_IN;    peer = peer_and_group_lookup_vty (vty, ip_str);    if (! peer)      return CMD_WARNING;    /* Check filter direction. */ -  if (strncmp (direct_str, "i", 1) == 0) -    direct = FILTER_IN; +  if (strncmp (direct_str, "in", 2) == 0) +    direct = RMAP_IN;    else if (strncmp (direct_str, "o", 1) == 0) - -    direct = FILTER_OUT; +    direct = RMAP_OUT; +  else if (strncmp (direct_str, "im", 2) == 0) +    direct = RMAP_IMPORT; +  else if (strncmp (direct_str, "e", 1) == 0) +    direct = RMAP_EXPORT;    ret = peer_route_map_unset (peer, afi, safi, direct); @@ -3308,13 +3469,15 @@ peer_route_map_unset_vty (struct vty *vty, char *ip_str, afi_t afi,  DEFUN (neighbor_route_map,         neighbor_route_map_cmd, -       NEIGHBOR_CMD2 "route-map WORD (in|out)", +       NEIGHBOR_CMD2 "route-map WORD (in|out|import|export)",         NEIGHBOR_STR         NEIGHBOR_ADDR_STR2         "Apply route map to neighbor\n"         "Name of route map\n"         "Apply map to incoming routes\n" -       "Apply map to outbound routes\n") +       "Apply map to outbound routes\n" +       "Apply map to routes going into a Route-Server client's table\n" +       "Apply map to routes coming from a Route-Server client")  {    return peer_route_map_set_vty (vty, argv[0], bgp_node_afi (vty),  				 bgp_node_safi (vty), argv[1], argv[2]); @@ -3322,14 +3485,16 @@ DEFUN (neighbor_route_map,  DEFUN (no_neighbor_route_map,         no_neighbor_route_map_cmd, -       NO_NEIGHBOR_CMD2 "route-map WORD (in|out)", +       NO_NEIGHBOR_CMD2 "route-map WORD (in|out|import|export)",         NO_STR         NEIGHBOR_STR         NEIGHBOR_ADDR_STR2         "Apply route map to neighbor\n"         "Name of route map\n"         "Apply map to incoming routes\n" -       "Apply map to outbound routes\n") +       "Apply map to outbound routes\n" +       "Apply map to routes going into a Route-Server client's table\n" +       "Apply map to routes coming from a Route-Server client")  {    return peer_route_map_unset_vty (vty, argv[0], bgp_node_afi (vty),  				   bgp_node_safi (vty), argv[2]); @@ -5990,6 +6155,166 @@ ALIAS (clear_bgp_as_soft,         "Clear peers with the AS number\n"         "Soft reconfig\n") +/* RS-client soft reconfiguration. */ +#ifdef HAVE_IPV6 +DEFUN (clear_bgp_all_rsclient, +       clear_bgp_all_rsclient_cmd, +       "clear bgp * rsclient", +       CLEAR_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig for rsclient RIB\n") +{ +  if (argc == 1) +    return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, +                          BGP_CLEAR_SOFT_RSCLIENT, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, +                        BGP_CLEAR_SOFT_RSCLIENT, NULL); +} + +ALIAS (clear_bgp_all_rsclient, +       clear_bgp_ipv6_all_rsclient_cmd, +       "clear bgp ipv6 * rsclient", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "Clear all peers\n" +       "Soft reconfig for rsclient RIB\n") + +ALIAS (clear_bgp_all_rsclient, +       clear_bgp_instance_all_rsclient_cmd, +       "clear bgp view WORD * rsclient", +       CLEAR_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Soft reconfig for rsclient RIB\n") + +ALIAS (clear_bgp_all_rsclient, +       clear_bgp_ipv6_instance_all_rsclient_cmd, +       "clear bgp ipv6 view WORD * rsclient", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Soft reconfig for rsclient RIB\n") +#endif /* HAVE_IPV6 */ + +DEFUN (clear_ip_bgp_all_rsclient, +       clear_ip_bgp_all_rsclient_cmd, +       "clear ip bgp * rsclient", +       CLEAR_STR +       IP_STR +       BGP_STR +       "Clear all peers\n" +       "Soft reconfig for rsclient RIB\n") +{ +  if (argc == 1) +    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, +                          BGP_CLEAR_SOFT_RSCLIENT, NULL); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, +                        BGP_CLEAR_SOFT_RSCLIENT, NULL); +} + +ALIAS (clear_ip_bgp_all_rsclient, +       clear_ip_bgp_instance_all_rsclient_cmd, +       "clear ip bgp view WORD * rsclient", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "Clear all peers\n" +       "Soft reconfig for rsclient RIB\n") + +#ifdef HAVE_IPV6 +DEFUN (clear_bgp_peer_rsclient, +       clear_bgp_peer_rsclient_cmd, +       "clear bgp (A.B.C.D|X:X::X:X) rsclient", +       CLEAR_STR +       BGP_STR +       "BGP neighbor IP address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig for rsclient RIB\n") +{ +  if (argc == 2) +    return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_peer, +                          BGP_CLEAR_SOFT_RSCLIENT, argv[1]); + +  return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, +                        BGP_CLEAR_SOFT_RSCLIENT, argv[0]); +} + +ALIAS (clear_bgp_peer_rsclient, +       clear_bgp_ipv6_peer_rsclient_cmd, +       "clear bgp ipv6 (A.B.C.D|X:X::X:X) rsclient", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "BGP neighbor IP address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig for rsclient RIB\n") + +ALIAS (clear_bgp_peer_rsclient, +       clear_bgp_instance_peer_rsclient_cmd, +       "clear bgp view WORD (A.B.C.D|X:X::X:X) rsclient", +       CLEAR_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "BGP neighbor IP address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig for rsclient RIB\n") + +ALIAS (clear_bgp_peer_rsclient, +       clear_bgp_ipv6_instance_peer_rsclient_cmd, +       "clear bgp ipv6 view WORD (A.B.C.D|X:X::X:X) rsclient", +       CLEAR_STR +       BGP_STR +       "Address family\n" +       "BGP view\n" +       "view name\n" +       "BGP neighbor IP address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig for rsclient RIB\n") +#endif /* HAVE_IPV6 */ + +DEFUN (clear_ip_bgp_peer_rsclient, +       clear_ip_bgp_peer_rsclient_cmd, +       "clear ip bgp (A.B.C.D|X:X::X:X) rsclient", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP neighbor IP address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig for rsclient RIB\n") +{ +  if (argc == 2) +    return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_peer, +                          BGP_CLEAR_SOFT_RSCLIENT, argv[1]); + +  return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, +                        BGP_CLEAR_SOFT_RSCLIENT, argv[0]); +} + +ALIAS (clear_ip_bgp_peer_rsclient, +       clear_ip_bgp_instance_peer_rsclient_cmd, +       "clear ip bgp view WORD (A.B.C.D|X:X::X:X) rsclient", +       CLEAR_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "view name\n" +       "BGP neighbor IP address to clear\n" +       "BGP IPv6 neighbor to clear\n" +       "Soft reconfig for rsclient RIB\n") + +  /* Show BGP peer's summary information. */  int  bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) @@ -6443,14 +6768,18 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi)    if (filter->plist[FILTER_IN].name        || filter->dlist[FILTER_IN].name        || filter->aslist[FILTER_IN].name -      || filter->map[FILTER_IN].name) +      || filter->map[RMAP_IN].name)      vty_out (vty, "  Inbound path policy configured%s", VTY_NEWLINE);    if (filter->plist[FILTER_OUT].name        || filter->dlist[FILTER_OUT].name        || filter->aslist[FILTER_OUT].name -      || filter->map[FILTER_OUT].name +      || filter->map[RMAP_OUT].name        || filter->usmap.name)      vty_out (vty, "  Outbound path policy configured%s", VTY_NEWLINE); +  if (filter->map[RMAP_IMPORT].name) +    vty_out (vty, "  Import policy for this RS-client configured%s", VTY_NEWLINE); +  if (filter->map[RMAP_EXPORT].name) +    vty_out (vty, "  Export policy for this RS-client configured%s", VTY_NEWLINE);    /* prefix-list */    if (filter->plist[FILTER_IN].name) @@ -6489,15 +6818,25 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi)  	     VTY_NEWLINE);    /* route-map. */ -  if (filter->map[FILTER_IN].name) +  if (filter->map[RMAP_IN].name)      vty_out (vty, "  Route map for incoming advertisements is %s%s%s", -	     filter->map[FILTER_IN].map ? "*" : "", -	     filter->map[FILTER_IN].name, +            filter->map[RMAP_IN].map ? "*" : "", +            filter->map[RMAP_IN].name,  	     VTY_NEWLINE); -  if (filter->map[FILTER_OUT].name) +  if (filter->map[RMAP_OUT].name)      vty_out (vty, "  Route map for outgoing advertisements is %s%s%s", -	     filter->map[FILTER_OUT].map ? "*" : "", -	     filter->map[FILTER_OUT].name, +            filter->map[RMAP_OUT].map ? "*" : "", +            filter->map[RMAP_OUT].name, +            VTY_NEWLINE); +  if (filter->map[RMAP_IMPORT].name) +    vty_out (vty, "  Route map for advertisements going into this RS-client's table is %s%s%s", +            filter->map[RMAP_IMPORT].map ? "*" : "", +            filter->map[RMAP_IMPORT].name, +            VTY_NEWLINE); +  if (filter->map[RMAP_EXPORT].name) +    vty_out (vty, "  Route map for advertisements coming from this RS-client is %s%s%s", +            filter->map[RMAP_EXPORT].map ? "*" : "", +            filter->map[RMAP_EXPORT].name,  	     VTY_NEWLINE);    /* unsuppress-map */ @@ -7156,6 +7495,262 @@ DEFUN (show_ip_bgp_attr_info,    return CMD_SUCCESS;  } +int +bgp_write_rsclient_summary (struct vty *vty, struct peer *rsclient, +        afi_t afi, safi_t safi) +{ +  char timebuf[BGP_UPTIME_LEN]; +  char rmbuf[14]; +  char *rmname; +  struct peer *peer; +  struct listnode *nn; +  int len; +  int count = 0; + +  if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_GROUP)) +    { +      LIST_LOOP (rsclient->group->peer, peer, nn) +        { +          count++; +          bgp_write_rsclient_summary (vty, peer, afi, safi); +        } +      return count; +    } + +  len = vty_out (vty, "%s", rsclient->host); +  len = 16 - len; + +  if (len < 1) +    vty_out (vty, "%s%*s", VTY_NEWLINE, 16, " "); +  else +    vty_out (vty, "%*s", len, " "); + +  switch (rsclient->version) +    { +      case BGP_VERSION_4: +        vty_out (vty, "4 "); +        break; +      case BGP_VERSION_MP_4_DRAFT_00: +        vty_out (vty, "4-"); +        break; +    } + +  vty_out (vty, "%5d ", rsclient->as); + +  rmname = ROUTE_MAP_EXPORT_NAME(&rsclient->filter[afi][safi]); +  if ( rmname && strlen (rmname) > 13 ) +    { +      sprintf (rmbuf, "%13s", "..."); +      rmname = strncpy (rmbuf, rmname, 10); +    } +  else if (! rmname) +    rmname = "<none>"; +  vty_out (vty, " %13s ", rmname); + +  rmname = ROUTE_MAP_IMPORT_NAME(&rsclient->filter[afi][safi]); +  if ( rmname && strlen (rmname) > 13 ) +    { +      sprintf (rmbuf, "%13s", "..."); +      rmname = strncpy (rmbuf, rmname, 10); +    } +  else if (! rmname) +    rmname = "<none>"; +  vty_out (vty, " %13s ", rmname); + +  vty_out (vty, "%8s", peer_uptime (rsclient->uptime, timebuf, BGP_UPTIME_LEN)); + +  if (CHECK_FLAG (rsclient->flags, PEER_FLAG_SHUTDOWN)) +    vty_out (vty, " Idle (Admin)"); +  else if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_PREFIX_OVERFLOW)) +    vty_out (vty, " Idle (PfxCt)"); +  else +    vty_out (vty, " %-11s", LOOKUP(bgp_status_msg, rsclient->status)); + +  vty_out (vty, "%s", VTY_NEWLINE); + +  return 1; +} + +int +bgp_show_rsclient_summary (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) +{ +  struct peer *peer; +  struct listnode *nn; +  int count = 0; + +  /* Header string for each address family. */ +  static char header[] = "Neighbor        V    AS  Export-Policy  Import-Policy  Up/Down  State"; + +  LIST_LOOP (bgp->rsclient, peer, nn) +    { +      if (peer->afc[afi][safi] && +         CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +       { +         if (! count) +           { +             vty_out (vty, +                      "Route Server's BGP router identifier %s%s", +                      inet_ntoa (bgp->router_id), VTY_NEWLINE); +             vty_out (vty, +              "Route Server's local AS number %d%s", bgp->as, +                       VTY_NEWLINE); + +             vty_out (vty, "%s", VTY_NEWLINE); +             vty_out (vty, "%s%s", header, VTY_NEWLINE); +           } + +         count += bgp_write_rsclient_summary (vty, peer, afi, safi); +       } +    } + +  if (count) +    vty_out (vty, "%sTotal number of Route Server Clients %d%s", VTY_NEWLINE, +            count, VTY_NEWLINE); +  else +    vty_out (vty, "No %s Route Server Client is configured%s", +            afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); + +  return CMD_SUCCESS; +} + +int +bgp_show_rsclient_summary_vty (struct vty *vty, char *name, afi_t afi, safi_t safi) +{ +  struct bgp *bgp; + +  if (name) +    { +      bgp = bgp_lookup_by_name (name); + +      if (! bgp) +       { +         vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); +         return CMD_WARNING; +       } + +      bgp_show_rsclient_summary (vty, bgp, afi, safi); +      return CMD_SUCCESS; +    } + +  bgp = bgp_get_default (); + +  if (bgp) +    bgp_show_rsclient_summary (vty, bgp, afi, safi); + +  return CMD_SUCCESS; +} + +/* 'show bgp rsclient' commands. */ +DEFUN (show_ip_bgp_rsclient_summary, +       show_ip_bgp_rsclient_summary_cmd, +       "show ip bgp rsclient summary", +       SHOW_STR +       IP_STR +       BGP_STR +       "Information about Route Server Clients\n" +       "Summary of all Route Server Clients\n") +{ +  return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_rsclient_summary, +       show_ip_bgp_instance_rsclient_summary_cmd, +       "show ip bgp view WORD rsclient summary", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "View name\n" +       "Information about Route Server Clients\n" +       "Summary of all Route Server Clients\n") +{ +  return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_ipv4_rsclient_summary, +      show_ip_bgp_ipv4_rsclient_summary_cmd, +      "show ip bgp ipv4 (unicast|multicast) rsclient summary", +       SHOW_STR +       IP_STR +       BGP_STR +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Information about Route Server Clients\n" +       "Summary of all Route Server Clients\n") +{ +  if (strncmp (argv[0], "m", 1) == 0) +    return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); + +  return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); +} + +DEFUN (show_ip_bgp_instance_ipv4_rsclient_summary, +      show_ip_bgp_instance_ipv4_rsclient_summary_cmd, +      "show ip bgp view WORD ipv4 (unicast|multicast) rsclient summary", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP view\n" +       "View name\n" +       "Address family\n" +       "Address Family modifier\n" +       "Address Family modifier\n" +       "Information about Route Server Clients\n" +       "Summary of all Route Server Clients\n") +{ +  if (strncmp (argv[1], "m", 1) == 0) +    return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); + +  return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); +} + +#ifdef HAVE_IPV6 +DEFUN (show_bgp_rsclient_summary, +       show_bgp_rsclient_summary_cmd, +       "show bgp rsclient summary", +       SHOW_STR +       BGP_STR +       "Information about Route Server Clients\n" +       "Summary of all Route Server Clients\n") +{ +  return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); +} + +DEFUN (show_bgp_instance_rsclient_summary, +       show_bgp_instance_rsclient_summary_cmd, +       "show bgp view WORD rsclient summary", +       SHOW_STR +       BGP_STR +       "BGP view\n" +       "View name\n" +       "Information about Route Server Clients\n" +       "Summary of all Route Server Clients\n") +{ +  return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); +} + +ALIAS (show_bgp_rsclient_summary, +      show_bgp_ipv6_rsclient_summary_cmd, +      "show bgp ipv6 rsclient summary", +       SHOW_STR +       BGP_STR +       "Address family\n" +       "Information about Route Server Clients\n" +       "Summary of all Route Server Clients\n") + +ALIAS (show_bgp_instance_rsclient_summary, +      show_bgp_instance_ipv6_rsclient_summary_cmd, +       "show bgp view WORD ipv6 rsclient summary", +       SHOW_STR +       BGP_STR +       "BGP view\n" +       "View name\n" +       "Address family\n" +       "Information about Route Server Clients\n" +       "Summary of all Route Server Clients\n") +#endif /* HAVE IPV6 */ +  /* Redistribute VTY commands.  */  /* Utility function to convert user input route type string to route @@ -8066,6 +8661,10 @@ bgp_vty_init ()    install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd);    install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd); +  /* "nexthop-local unchanged" commands */ +  install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd); +  install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd); +    /* "transparent-as" and "transparent-nexthop" for old version       compatibility.  */    install_element (BGP_NODE, &neighbor_transparent_as_cmd); @@ -8562,6 +9161,22 @@ bgp_vty_init ()    install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd);  #endif /* HAVE_IPV6 */ +  /* "clear ip bgp neighbor rsclient" */ +  install_element (ENABLE_NODE, &clear_ip_bgp_all_rsclient_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_rsclient_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_peer_rsclient_cmd); +  install_element (ENABLE_NODE, &clear_ip_bgp_instance_peer_rsclient_cmd); +#ifdef HAVE_IPV6 +  install_element (ENABLE_NODE, &clear_bgp_all_rsclient_cmd); +  install_element (ENABLE_NODE, &clear_bgp_instance_all_rsclient_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_all_rsclient_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_all_rsclient_cmd); +  install_element (ENABLE_NODE, &clear_bgp_peer_rsclient_cmd); +  install_element (ENABLE_NODE, &clear_bgp_instance_peer_rsclient_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_rsclient_cmd); +  install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_peer_rsclient_cmd); +#endif /* HAVE_IPV6 */ +    /* "show ip bgp summary" commands. */    install_element (VIEW_NODE, &show_ip_bgp_summary_cmd);    install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd); @@ -8635,6 +9250,27 @@ bgp_vty_init ()    install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd);  #endif /* HAVE_IPV6 */ +  /* "show ip bgp rsclient" commands. */ +  install_element (VIEW_NODE, &show_ip_bgp_rsclient_summary_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_rsclient_summary_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); + +#ifdef HAVE_IPV6 +  install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd); +  install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd); +  install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd); +  install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); +  install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd); +  install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_summary_cmd); +  install_element (ENABLE_NODE, &show_bgp_instance_rsclient_summary_cmd); +  install_element (ENABLE_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); +#endif /* HAVE_IPV6 */ +    /* "show ip bgp paths" commands. */    install_element (VIEW_NODE, &show_ip_bgp_paths_cmd);    install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 47df3c83..6afbe959 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -531,6 +531,23 @@ bgp_default_local_preference_unset (struct bgp *bgp)    return 0;  } +/* If peer is RSERVER_CLIENT in at least one address family and is not member +    of a peer_group for that family, return 1. +    Used to check wether the peer is included in list bgp->rsclient. */ +int +peer_rsclient_active (struct peer *peer) +{ +  int i; +  int j; + +  for (i=AFI_IP; i < AFI_MAX; i++) +    for (j=SAFI_UNICAST; j < SAFI_MAX; j++) +      if (CHECK_FLAG(peer->af_flags[i][j], PEER_FLAG_RSERVER_CLIENT) +            && ! peer->af_group[i][j]) +        return 1; +  return 0; +} +  /* Peer comparison function for sorting.  */  static int  peer_cmp (struct peer *p1, struct peer *p2) @@ -572,6 +589,9 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi)  	  free (filter->aslist[i].name);  	  filter->aslist[i].name = NULL;  	} +   } + for (i = RMAP_IN; i < RMAP_MAX; i++) +       {        if (filter->map[i].name)  	{  	  free (filter->map[i].name); @@ -1092,7 +1112,18 @@ peer_delete (struct peer *peer)    /* Delete from all peer list. */    if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) +    {      listnode_delete (bgp->peer, peer); +      if (peer_rsclient_active (peer)) +        listnode_delete (bgp->rsclient, peer); +    } + +  /* Free RIB for any family in which peer is RSERVER_CLIENT, and is not +      member of a peer_group. */ +  for (afi = AFI_IP; afi < AFI_MAX; afi++) +    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +      if (peer->rib[afi][safi] && ! peer->af_group[afi][safi]) +        bgp_table_finish (peer->rib[afi][safi]);    /* Buffer.  */    if (peer->ibuf) @@ -1134,6 +1165,9 @@ peer_delete (struct peer *peer)  	      free (filter->plist[i].name);  	    if (filter->aslist[i].name)  	      free (filter->aslist[i].name); +     } +   for (i = RMAP_IN; i < RMAP_MAX; i++) +      {  	    if (filter->map[i].name)  	      free (filter->map[i].name);  	  } @@ -1300,6 +1334,34 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,    /* allowas-in */    peer->allowas_in[afi][safi] = conf->allowas_in[afi][safi]; +  /* route-server-client */ +  if (CHECK_FLAG(conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +    { +      /* Make peer's RIB point to group's RIB. */ +      peer->rib[afi][safi] = group->conf->rib[afi][safi]; + +      /* Import policy. */ +      if (pfilter->map[RMAP_IMPORT].name) +        free (pfilter->map[RMAP_IMPORT].name); +      if (gfilter->map[RMAP_IMPORT].name) +        { +          pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); +          pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map; +        } +      else +        { +          pfilter->map[RMAP_IMPORT].name = NULL; +          pfilter->map[RMAP_IMPORT].map = NULL; +        } + +      /* Export policy. */ +      if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) +        { +          pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); +          pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map; +        } +    } +    /* default-originate route-map */    if (conf->default_rmap[afi][safi].name)      { @@ -1355,12 +1417,12 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,        pfilter->aslist[in].name = strdup (gfilter->aslist[in].name);        pfilter->aslist[in].aslist = gfilter->aslist[in].aslist;      } -  if (gfilter->map[in].name && ! pfilter->map[in].name) +  if (gfilter->map[RMAP_IN].name && ! pfilter->map[RMAP_IN].name)      { -      if (pfilter->map[in].name) -	free (pfilter->map[in].name); -      pfilter->map[in].name = strdup (gfilter->map[in].name); -      pfilter->map[in].map = gfilter->map[in].map; +      if (pfilter->map[RMAP_IN].name) +        free (pfilter->map[RMAP_IN].name); +      pfilter->map[RMAP_IN].name = strdup (gfilter->map[RMAP_IN].name); +      pfilter->map[RMAP_IN].map = gfilter->map[RMAP_IN].map;      }    /* outbound filter apply */ @@ -1406,19 +1468,42 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer,        pfilter->aslist[out].name = NULL;        pfilter->aslist[out].aslist = NULL;      } -  if (gfilter->map[out].name) +  if (gfilter->map[RMAP_OUT].name) +    { +      if (pfilter->map[RMAP_OUT].name) +        free (pfilter->map[RMAP_OUT].name); +      pfilter->map[RMAP_OUT].name = strdup (gfilter->map[RMAP_OUT].name); +      pfilter->map[RMAP_OUT].map = gfilter->map[RMAP_OUT].map; +    } +  else +    { +      if (pfilter->map[RMAP_OUT].name) +        free (pfilter->map[RMAP_OUT].name); +      pfilter->map[RMAP_OUT].name = NULL; +      pfilter->map[RMAP_OUT].map = NULL; +    } + + /* RS-client's import/export route-maps. */ +  if (gfilter->map[RMAP_IMPORT].name)      { -      if (pfilter->map[out].name) -	free (pfilter->map[out].name); -      pfilter->map[out].name = strdup (gfilter->map[out].name); -      pfilter->map[out].map = gfilter->map[out].map; +      if (pfilter->map[RMAP_IMPORT].name) +        free (pfilter->map[RMAP_IMPORT].name); +      pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); +      pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map;      }    else      { -      if (pfilter->map[out].name) -	free (pfilter->map[out].name); -      pfilter->map[out].name = NULL; -      pfilter->map[out].map = NULL; +      if (pfilter->map[RMAP_IMPORT].name) +        free (pfilter->map[RMAP_IMPORT].name); +      pfilter->map[RMAP_IMPORT].name = NULL; +      pfilter->map[RMAP_IMPORT].map = NULL; +    } +  if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) +    { +      if (pfilter->map[RMAP_EXPORT].name) +        free (pfilter->map[RMAP_EXPORT].name); +      pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); +      pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map;      }    if (gfilter->usmap.name) @@ -1601,6 +1686,35 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,  	  UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);  	}      } + +  if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +    { +      /* If it's not configured as RSERVER_CLIENT in any other address +          family, without being member of a peer_group, remove it from +          list bgp->rsclient.*/ +      if (! peer_rsclient_active (peer)) +        listnode_delete (bgp->rsclient, peer); + +      bgp_table_finish (peer->rib[afi][safi]); + +      /* Import policy. */ +      if (peer->filter[afi][safi].map[RMAP_IMPORT].name) +        { +          free (peer->filter[afi][safi].map[RMAP_IMPORT].name); +          peer->filter[afi][safi].map[RMAP_IMPORT].name = NULL; +          peer->filter[afi][safi].map[RMAP_IMPORT].map = NULL; +        } + +      /* Export policy. */ +      if (! CHECK_FLAG(group->conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) +              && peer->filter[afi][safi].map[RMAP_EXPORT].name) +        { +          free (peer->filter[afi][safi].map[RMAP_EXPORT].name); +          peer->filter[afi][safi].map[RMAP_EXPORT].name = NULL; +          peer->filter[afi][safi].map[RMAP_EXPORT].map = NULL; +        } +    } +    peer_group2peer_config_copy (group, peer, afi, safi);    if (peer->status == Established) @@ -1629,6 +1743,9 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer,    peer->afc[afi][safi] = 0;    peer_af_flag_reset (peer, afi, safi); +  if (peer->rib[afi][safi]) +    peer->rib[afi][safi] = NULL; +    if (! peer_group_active (peer))      {        listnode_delete (group->peer, peer); @@ -1672,6 +1789,9 @@ bgp_create (as_t *as, char *name)    bgp->group = list_new ();    bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp; +  bgp->rsclient = list_new (); +  bgp->rsclient->cmp = (int (*)(void*, void*)) peer_cmp; +    for (afi = AFI_IP; afi < AFI_MAX; afi++)      for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)        { @@ -1826,6 +1946,9 @@ bgp_delete (struct bgp *bgp)        peer_delete (peer);      } +  bgp->rsclient->del = (void (*)(void *)) peer_delete; +  list_delete (bgp->rsclient); +    listnode_delete (bm->bgp, bgp);    if (bgp->name) @@ -2007,6 +2130,7 @@ struct peer_flag_action peer_af_flag_action_list[] =      { PEER_FLAG_ALLOWAS_IN,               0, peer_change_reset_in },      { PEER_FLAG_ORF_PREFIX_SM,            1, peer_change_reset },      { PEER_FLAG_ORF_PREFIX_RM,            1, peer_change_reset }, +    { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED,  0, peer_change_reset_out },      { 0, 0, 0 }    }; @@ -3551,10 +3675,12 @@ peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct)    if (! peer->afc[afi][safi])      return BGP_ERR_PEER_INACTIVE; -  if (direct != FILTER_IN && direct != FILTER_OUT) +  if (direct != RMAP_IN && direct != RMAP_OUT && +      direct != RMAP_IMPORT && direct != RMAP_EXPORT)      return BGP_ERR_INVALID_VALUE; -  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) +  if ( (direct == RMAP_OUT || direct == RMAP_IMPORT) +      && peer_is_group_member (peer, afi, safi))      return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;    filter = &peer->filter[afi][safi]; @@ -3662,10 +3788,12 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,    if (! peer->afc[afi][safi])      return BGP_ERR_PEER_INACTIVE; -  if (direct != FILTER_IN && direct != FILTER_OUT) +  if (direct != RMAP_IN && direct != RMAP_OUT && +      direct != RMAP_IMPORT && direct != RMAP_EXPORT)      return BGP_ERR_INVALID_VALUE; -  if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) +  if ( (direct == RMAP_OUT || direct == RMAP_IMPORT) +      && peer_is_group_member (peer, afi, safi))      return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;    filter = &peer->filter[afi][safi]; @@ -3950,6 +4078,14 @@ peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi,    if (! peer->afc[afi][safi])      return BGP_ERR_AF_UNCONFIGURED; +  if (stype == BGP_CLEAR_SOFT_RSCLIENT) +    { +      if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) +        return 0; +      bgp_check_local_routes_rsclient (peer, afi, safi); +      bgp_soft_reconfig_rsclient (peer, afi, safi); +    } +    if (stype == BGP_CLEAR_SOFT_OUT || stype == BGP_CLEAR_SOFT_BOTH)      bgp_announce_route (peer, afi, safi); @@ -4086,14 +4222,23 @@ bgp_config_write_filter (struct vty *vty, struct peer *peer,  	     filter->plist[out].name, VTY_NEWLINE);    /* route-map. */ -  if (filter->map[in].name) -    if (! gfilter || ! gfilter->map[in].name -	|| strcmp (filter->map[in].name, gfilter->map[in].name) != 0) +  if (filter->map[RMAP_IN].name) +    if (! gfilter || ! gfilter->map[RMAP_IN].name +       || strcmp (filter->map[RMAP_IN].name, gfilter->map[RMAP_IN].name) != 0)        vty_out (vty, " neighbor %s route-map %s in%s", addr,  -	       filter->map[in].name, VTY_NEWLINE); -  if (filter->map[out].name && ! gfilter) +              filter->map[RMAP_IN].name, VTY_NEWLINE); +  if (filter->map[RMAP_OUT].name && ! gfilter)      vty_out (vty, " neighbor %s route-map %s out%s", addr,  -	     filter->map[out].name, VTY_NEWLINE); +            filter->map[RMAP_OUT].name, VTY_NEWLINE); +  if (filter->map[RMAP_IMPORT].name && ! gfilter) +    vty_out (vty, " neighbor %s route-map %s import%s", addr, +        filter->map[RMAP_IMPORT].name, VTY_NEWLINE); +  if (filter->map[RMAP_EXPORT].name) +    if (! gfilter || ! gfilter->map[RMAP_EXPORT].name +    || strcmp (filter->map[RMAP_EXPORT].name, +                    gfilter->map[RMAP_EXPORT].name) != 0) +    vty_out (vty, " neighbor %s route-map %s export%s", addr, +        filter->map[RMAP_EXPORT].name, VTY_NEWLINE);    /* unsuppress-map */    if (filter->usmap.name && ! gfilter) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 818f7dc8..61472d85 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -65,6 +65,9 @@ struct bgp    /* BGP peer group.  */    struct list *group; +  /* BGP route-server-clients. */ +  struct list *rsclient; +    /* BGP configuration.  */    u_int16_t config;  #define BGP_CONFIG_ROUTER_ID              (1 << 0) @@ -186,6 +189,12 @@ struct bgp_rd    u_char val[BGP_RD_SIZE];  }; +#define RMAP_IN           0 +#define RMAP_OUT        1 +#define RMAP_IMPORT   2 +#define RMAP_EXPORT   3 +#define RMAP_MAX        4 +  /* BGP filter structure. */  struct bgp_filter  { @@ -215,7 +224,7 @@ struct bgp_filter    {      char *name;      struct route_map *map; -  } map[FILTER_MAX]; +  } map[RMAP_MAX];    /* Unsuppress-map.  */    struct @@ -250,6 +259,9 @@ struct peer    /* Local router ID. */    struct in_addr local_id; +  /* Peer specific RIB when configured as route-server-client. */ +  struct bgp_table *rib[AFI_MAX][SAFI_MAX]; +    /* Packet receive and send buffer. */    struct stream *ibuf;    struct stream_fifo *obuf; @@ -341,6 +353,7 @@ struct peer  #define PEER_FLAG_ORF_PREFIX_RM             (1 << 13) /* orf capability receive-mode */  #define PEER_FLAG_MAX_PREFIX                (1 << 14) /* maximum prefix */  #define PEER_FLAG_MAX_PREFIX_WARNING        (1 << 15) /* maximum prefix warning-only */ +#define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED   (1 << 16) /* leave link-local nexthop unchanged */     /* default-originate route-map.  */    struct @@ -480,6 +493,8 @@ struct peer  #define PEER_RMAP_TYPE_REDISTRIBUTE   (1 << 3) /* redistribute route-map */  #define PEER_RMAP_TYPE_DEFAULT        (1 << 4) /* default-originate route-map */  #define PEER_RMAP_TYPE_NOSET          (1 << 5) /* not allow to set commands */ +#define PEER_RMAP_TYPE_IMPORT         (1 << 6) /* neighbor route-map import */ +#define PEER_RMAP_TYPE_EXPORT         (1 << 7) /* neighbor route-map export */  };  /* This structure's member directly points incoming packet data @@ -689,7 +704,8 @@ enum bgp_clear_type    BGP_CLEAR_SOFT_OUT,    BGP_CLEAR_SOFT_IN,    BGP_CLEAR_SOFT_BOTH, -  BGP_CLEAR_SOFT_IN_ORF_PREFIX +  BGP_CLEAR_SOFT_IN_ORF_PREFIX, +  BGP_CLEAR_SOFT_RSCLIENT  };  /* Macros. */ @@ -797,6 +813,8 @@ int bgp_timers_unset (struct bgp *);  int bgp_default_local_preference_set (struct bgp *, u_int32_t);  int bgp_default_local_preference_unset (struct bgp *); +int peer_rsclient_active (struct peer *); +  int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t);  int peer_group_remote_as (struct bgp *, char *, as_t *);  int peer_delete (struct peer *peer); diff --git a/lib/routemap.c b/lib/routemap.c index 9995334e..9d6bbcfd 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  #include "prefix.h"  #include "routemap.h"  #include "command.h" +#include "log.h"  /* Vector for route match rules. */  static vector route_match_vec; @@ -221,9 +222,11 @@ vty_show_route_map_entry (struct vty *vty, struct route_map *map)                   rule->cmd->str, rule->rule_str, VTY_NEWLINE);        vty_out (vty, "  Action:%s", VTY_NEWLINE); -      if (index->exitpolicy == RMAP_GOTO) +       +      if (index->nextrm) +        vty_out (vty, "    Call %s%s", index->nextrm, VTY_NEWLINE); +      else if (index->exitpolicy == RMAP_GOTO)          vty_out (vty, "    Goto %d%s", index->nextpref, VTY_NEWLINE); -                else if (index->exitpolicy == RMAP_NEXT)          {            vty_out (vty, "    Goto next, (entry "); @@ -298,6 +301,10 @@ route_map_index_delete (struct route_map_index *index, int notify)    else      index->map->head = index->next; +  /* Free 'char *nextrm' if not NULL */ +  if (index->nextrm) +    free (index->nextrm); +      /* Execute event hook. */    if (route_map_master.event_hook && notify)      (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED, @@ -688,18 +695,26 @@ route_map_delete_set (struct route_map_index *index, char *set_name,      deny      deny    |     cont                        | -   action) Apply Set statements, accept route -      If NEXT is specified, goto NEXT statement -      If GOTO is specified, goto the first clause where pref > nextpref -      If nothing is specified, do as Cisco and finish -   deny)   If NEXT is specified, goto NEXT statement -      If nothing is specified, finally will be denied by route-map. -   cont)   Goto Next index +   action) +      -Apply Set statements, accept route +      -If Call statement is present jump to the specified route-map, if it +         denies the route we finish. +      -If NEXT is specified, goto NEXT statement +      -If GOTO is specified, goto the first clause where pref > nextpref +      -If nothing is specified, do as Cisco and finish +   deny) +      -Route is denied by route-map. +   cont) +      -Goto Next index     If we get no matches after we've processed all updates, then the route     is dropped too. -   Some notes on the new "NEXT" and "GOTO" +   Some notes on the new "CALL", "NEXT" and "GOTO" +     call WORD        - If this clause is matched, then the set statements +                        are executed and then we jump to route-map 'WORD'. If +                        this route-map denies the route, we finish, in other case we +                        do whatever the exit policy (EXIT, NEXT or GOTO) tells.       on-match next    - If this clause is matched, then the set statements                          are executed and then we drop through to the next clause       on-match goto n  - If this clause is matched, then the set statments @@ -746,10 +761,20 @@ route_map_result_t  route_map_apply (struct route_map *map, struct prefix *prefix,                   route_map_object_t type, void *object)  { +  static int recursion = 0;    int ret = 0;    struct route_map_index *index;    struct route_map_rule *set; +  if (recursion > RMAP_RECURSION_LIMIT) +    { +      zlog (NULL, LOG_WARNING, +            "route-map recursion limit (%d) reached, discarding route", +            RMAP_RECURSION_LIMIT); +      recursion = 0; +      return RMAP_DENYMATCH; +    } +    if (map == NULL)      return RMAP_DENYMATCH; @@ -771,6 +796,25 @@ route_map_apply (struct route_map *map, struct prefix *prefix,                for (set = index->set_list.head; set; set = set->next)                  ret = (*set->cmd->func_apply) (set->value, prefix,                                                 type, object); + +              /* Call another route-map if available */ +              if (index->nextrm) +                { +                  struct route_map *nextrm = +                                    route_map_lookup_by_name (index->nextrm); + +                  if (nextrm) /* Target route-map found, jump to it */ +                    { +                      recursion++; +                      ret = route_map_apply (nextrm, prefix, type, object); +                      recursion--; +                    } + +                  /* If nextrm returned 'deny', finish. */ +                  if (ret == RMAP_DENYMATCH) +                    return ret; +                } +                                switch (index->exitpolicy)                  {                    case RMAP_EXIT: @@ -781,8 +825,9 @@ route_map_apply (struct route_map *map, struct prefix *prefix,                      {                        /* Find the next clause to jump to */                        struct route_map_index *next = index->next; +                      int nextpref = index->nextpref; -                      while (next && next->pref < index->nextpref) +                      while (next && next->pref < nextpref)                          {                            index = next;                            next = next->next; @@ -798,9 +843,6 @@ route_map_apply (struct route_map *map, struct prefix *prefix,            else if (index->type == RMAP_DENY)              /* 'deny' */              { -              if (index->exitpolicy == RMAP_NEXT) -                continue; -              else                  return RMAP_DENYMATCH;              }          } @@ -1046,7 +1088,7 @@ DEFUN (no_rmap_onmatch_goto,         "no on-match goto",         NO_STR         "Exit policy on matches\n" -       "Next clause\n") +       "Goto Clause number\n")  {    struct route_map_index *index; @@ -1103,6 +1145,49 @@ DEFUN (rmap_show_name,      return vty_show_route_map (vty, argv[0]);  } +ALIAS (rmap_onmatch_goto, +      rmap_continue_index_cmd, +      "continue <1-65536>", +      "Exit policy on matches\n" +      "Goto Clause number\n") + +DEFUN (rmap_call, +       rmap_call_cmd, +       "call WORD", +       "Jump to another Route-Map after match+set\n" +       "Target route-map name\n") +{ +  struct route_map_index *index; + +  index = vty->index; +  if (index) +    { +      if (index->nextrm) +          free (index->nextrm); +      index->nextrm = strdup (argv[0]); +    } +  return CMD_SUCCESS; +} + +DEFUN (no_rmap_call, +       no_rmap_call_cmd, +       "no call", +       NO_STR +       "Jump to another Route-Map after match+set\n") +{ +  struct route_map_index *index; + +  index = vty->index; + +  if (index->nextrm) +    { +      free (index->nextrm); +      index->nextrm = NULL; +    } + +  return CMD_SUCCESS; +} +  /* Configuration write function. */  int  route_map_config_write (struct vty *vty) @@ -1135,9 +1220,10 @@ route_map_config_write (struct vty *vty)  	  vty_out (vty, " set %s %s%s", rule->cmd->str,  		   rule->rule_str ? rule->rule_str : "",  		   VTY_NEWLINE); +   if (index->nextrm) +     vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);  	if (index->exitpolicy == RMAP_GOTO) -	  vty_out (vty, " on-match goto %d%s", index->nextpref, -		   VTY_NEWLINE); +      vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);  	if (index->exitpolicy == RMAP_NEXT)  	  vty_out (vty," on-match next%s", VTY_NEWLINE); @@ -1173,7 +1259,16 @@ route_map_init_vty ()    install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);    install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);    install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd); - +   +  /* Install the continue stuff (ALIAS of on-match). */ +  install_element (RMAP_NODE, &rmap_continue_cmd); +  install_element (RMAP_NODE, &no_rmap_continue_cmd); +  install_element (RMAP_NODE, &rmap_continue_index_cmd); +   +  /* Install the call stuff. */ +  install_element (RMAP_NODE, &rmap_call_cmd); +  install_element (RMAP_NODE, &no_rmap_call_cmd); +       /* Install show command */    install_element (ENABLE_NODE, &rmap_show_cmd);    install_element (ENABLE_NODE, &rmap_show_name_cmd); diff --git a/lib/routemap.h b/lib/routemap.h index e37f1e7b..4fd9e5e9 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -67,6 +67,9 @@ typedef enum    RMAP_EVENT_INDEX_DELETED  } route_map_event_t; +/* Depth limit in RMAP recursion using RMAP_CALL. */ +#define RMAP_RECURSION_LIMIT      10 +  /* Route map rule structure for matching and setting. */  struct route_map_rule_cmd  { @@ -118,6 +121,9 @@ struct route_map_index    /* If we're using "GOTO", to where do we go? */    int nextpref; +  /* If we're using "CALL", to which route-map do ew go? */ +  char *nextrm; +    /* Matching rule list. */    struct route_map_rule_list match_list;    struct route_map_rule_list set_list;  | 
