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.
diff --git a/ChangeLog b/ChangeLog
index 68186fd..d6a0ab4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 d745d87..c8f5ed6 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1365,8 +1365,7 @@
   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 cf65964..6b49e2c 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -58,16 +58,15 @@
 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_unlock_node (prn);
       table = prn->info;
     }
-  else
-    table = bgp->rib[afi][safi];
 
   rn = bgp_node_get (table, p);
 
@@ -455,6 +452,77 @@
 }
 
 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 @@
   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 @@
       || (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 @@
   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 @@
 #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 @@
       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 @@
 }
 
 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)
 {
-  struct prefix *p;
-  struct bgp_info *ri;
+  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 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 @@
 	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 @@
       SET_FLAG (new_select->flags, BGP_INFO_SELECTED);
       UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED);
     }
+      }
+
+    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)
+    return 0;
+
+      /* Address family configuration check. */
+      if (! peer->afc_nego[afi][safi])
+    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))
+    return 0;
+
+  switch (rn->table->type)
+    {
+      case BGP_TABLE_MAIN:
+      /* Announcement to peer->conf.  If the route is filtered,
+         withdraw it. */
+        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)
     {
-      /* Announce route to Established peer. */
-      if (peer->status != Established)
-	continue;
-
-      /* Address family configuration check. */
-      if (! peer->afc_nego[afi][safi])
-	continue;
-
-      /* 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;
-
-      /* 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);
-      else
-	bgp_adj_out_unset (rn, peer, p, afi, safi);
+      bgp_process_announce_selected (peer, new_select, rn, &attr, afi, safi);
     }
 
   /* FIB update. */
@@ -875,6 +1254,20 @@
 }
 
 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 @@
 {
   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 @@
   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 @@
     }
 }
 
+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 @@
   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 @@
 }
 
 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 @@
   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 @@
 	  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 @@
       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 @@
 
 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 @@
     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 @@
     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 @@
 }
 
 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 @@
 
 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 @@
   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 @@
 {
   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 @@
 }
 
 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 @@
   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 @@
       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 @@
 }
 
 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 @@
   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 @@
 }
 
 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 @@
 	      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 @@
 		}
 	    }
 
-	  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 @@
 
       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 @@
 }
 
 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 @@
 		   ? 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 @@
 
 	    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 @@
   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 @@
 
 /* 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 @@
   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 @@
 
   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 @@
     {
       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 @@
   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 @@
 				  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 @@
        "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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 273ed41..9aad723 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -109,10 +109,15 @@
 #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_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 261f6b8..c49c2e9 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -95,6 +95,103 @@
 
 */ 
 
+ /* '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 @@
 
       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 @@
 	      {
 		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 @@
 	      {
 		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 @@
     }
 }
 
+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 @@
   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 @@
   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 a2a3c97..c468173 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -38,6 +38,9 @@
 
   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 52eb6a4..f979ac6 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -18,8 +18,19 @@
 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 c7de8eb..92918bd 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -39,6 +39,7 @@
 #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 @@
 
 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 @@
 
 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 @@
 				 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 @@
        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 @@
        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 @@
 {
   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 @@
 {
   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 @@
 
 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 (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 @@
        "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 @@
   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 @@
 	     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 @@
   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 @@
   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 @@
   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 @@
   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 47df3c8..6afbe95 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -531,6 +531,23 @@
   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 @@
 	  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 @@
 
   /* 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 @@
 	      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 @@
   /* 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 @@
       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 @@
       pfilter->aslist[out].name = NULL;
       pfilter->aslist[out].aslist = NULL;
     }
-  if (gfilter->map[out].name)
+  if (gfilter->map[RMAP_OUT].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_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[out].name)
-	free (pfilter->map[out].name);
-      pfilter->map[out].name = NULL;
-      pfilter->map[out].map = NULL;
+      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[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[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 @@
 	  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->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->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 @@
       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 @@
     { 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 @@
   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 @@
   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 @@
   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 @@
 	     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 818f7dc..61472d8 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -65,6 +65,9 @@
   /* 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 @@
   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 @@
   {
     char *name;
     struct route_map *map;
-  } map[FILTER_MAX];
+  } map[RMAP_MAX];
 
   /* Unsuppress-map.  */
   struct
@@ -250,6 +259,9 @@
   /* 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 @@
 #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 @@
 #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 @@
   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_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 9995334..9d6bbcf 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -26,6 +26,7 @@
 #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 @@
                  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 @@
   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 @@
     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_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 @@
               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 @@
                     {
                       /* 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 @@
           else if (index->type == RMAP_DENY)
             /* 'deny' */
             {
-              if (index->exitpolicy == RMAP_NEXT)
-                continue;
-              else
                 return RMAP_DENYMATCH;
             }
         }
@@ -1046,7 +1088,7 @@
        "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 @@
     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 @@
 	  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 @@
   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 e37f1e7..4fd9e5e 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -67,6 +67,9 @@
   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 @@
   /* 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;