*: merge branch stable/0.99.23

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index ed8464d..04cbb8a 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -973,7 +973,8 @@
     }
 
   /* next-hop-set */
-  if (transparent || reflect
+  if (transparent
+      || (reflect && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF_ALL))
       || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)
 	  && ((p->family == AF_INET && attr->nexthop.s_addr)
 #ifdef HAVE_IPV6
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 36d177d..c498f58 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -93,7 +93,7 @@
       tag               :  (This will not be implemented by bgpd)
       weight            :  Done
 
-o Local extention
+o Local extensions
 
   set ipv6 next-hop global: Done
   set ipv6 next-hop local : Done
@@ -101,6 +101,26 @@
 
 */ 
 
+ /* generic as path object to be shared in multiple rules */
+
+static void *
+route_aspath_compile (const char *arg)
+{
+  struct aspath *aspath;
+
+  aspath = aspath_str2aspath (arg);
+  if (! aspath)
+    return NULL;
+  return aspath;
+}
+
+static void
+route_aspath_free (void *rule)
+{
+  struct aspath *aspath = rule;
+  aspath_free (aspath);
+}
+
  /* 'match peer (A.B.C.D|X:X::X:X)' */
 
 /* Compares the peer specified in the 'match peer' clause with the peer
@@ -1228,33 +1248,13 @@
   return RMAP_OKAY;
 }
 
-/* Compile function for as-path prepend. */
-static void *
-route_set_aspath_prepend_compile (const char *arg)
-{
-  struct aspath *aspath;
-
-  aspath = aspath_str2aspath (arg);
-  if (! aspath)
-    return NULL;
-  return aspath;
-}
-
-/* Compile function for as-path prepend. */
-static void
-route_set_aspath_prepend_free (void *rule)
-{
-  struct aspath *aspath = rule;
-  aspath_free (aspath);
-}
-
-/* Set metric rule structure. */
+/* Set as-path prepend rule structure. */
 struct route_map_rule_cmd route_set_aspath_prepend_cmd = 
 {
   "as-path prepend",
   route_set_aspath_prepend,
-  route_set_aspath_prepend_compile,
-  route_set_aspath_prepend_free,
+  route_aspath_compile,
+  route_aspath_free,
 };
 
 /* `set as-path exclude ASn' */
@@ -1282,37 +1282,13 @@
   return RMAP_OKAY;
 }
 
-/* FIXME: consider using route_set_aspath_prepend_compile() and
- * route_set_aspath_prepend_free(), which two below function are
- * exact clones of.
- */
-
-/* Compile function for as-path exclude. */
-static void *
-route_set_aspath_exclude_compile (const char *arg)
-{
-  struct aspath *aspath;
-
-  aspath = aspath_str2aspath (arg);
-  if (! aspath)
-    return NULL;
-  return aspath;
-}
-
-static void
-route_set_aspath_exclude_free (void *rule)
-{
-  struct aspath *aspath = rule;
-  aspath_free (aspath);
-}
-
 /* Set ASn exlude rule structure. */
 struct route_map_rule_cmd route_set_aspath_exclude_cmd = 
 {
   "as-path exclude",
   route_set_aspath_exclude,
-  route_set_aspath_exclude_compile,
-  route_set_aspath_exclude_free,
+  route_aspath_compile,
+  route_aspath_free,
 };
 
 /* `set community COMMUNITY' */
@@ -1669,7 +1645,7 @@
   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
 }
 
-/* Set metric rule structure. */
+/* Set origin rule structure. */
 struct route_map_rule_cmd route_set_origin_cmd = 
 {
   "origin",
@@ -2155,7 +2131,7 @@
   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
 }
 
-/* Set metric rule structure. */
+/* Set originator-id rule structure. */
 struct route_map_rule_cmd route_set_originator_id_cmd = 
 {
   "originator-id",
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 3c6973b..a818fe7 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -2093,25 +2093,41 @@
 /* neighbor next-hop-self. */
 DEFUN (neighbor_nexthop_self,
        neighbor_nexthop_self_cmd,
-       NEIGHBOR_CMD2 "next-hop-self",
+       NEIGHBOR_CMD2 "next-hop-self {all}",
        NEIGHBOR_STR
        NEIGHBOR_ADDR_STR2
-       "Disable the next hop calculation for this neighbor\n")
+       "Disable the next hop calculation for this neighbor\n"
+       "Apply also to ibgp-learned routes when acting as a route reflector\n")
 {
-  return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
-			       bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF);
+  u_int32_t flags = PEER_FLAG_NEXTHOP_SELF, unset = 0;
+  int rc;
+
+  /* Check if "all" is specified */
+  if (argv[1] != NULL)
+    flags |= PEER_FLAG_NEXTHOP_SELF_ALL;
+  else
+    unset |= PEER_FLAG_NEXTHOP_SELF_ALL;
+
+  rc = peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty),
+			     bgp_node_safi (vty), flags);
+  if ( rc == CMD_SUCCESS && unset )
+    rc = peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
+				 bgp_node_safi (vty), unset);
+  return rc;
 }
 
 DEFUN (no_neighbor_nexthop_self,
        no_neighbor_nexthop_self_cmd,
-       NO_NEIGHBOR_CMD2 "next-hop-self",
+       NO_NEIGHBOR_CMD2 "next-hop-self {all}",
        NO_STR
        NEIGHBOR_STR
        NEIGHBOR_ADDR_STR2
-       "Disable the next hop calculation for this neighbor\n")
+       "Disable the next hop calculation for this neighbor\n"
+       "Apply also to ibgp-learned routes when acting as a route reflector\n")
 {
   return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty),
-				 bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF);
+				 bgp_node_safi (vty),
+				 PEER_FLAG_NEXTHOP_SELF|PEER_FLAG_NEXTHOP_SELF_ALL);
 }
 
 /* neighbor remove-private-AS. */
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 19b96fa..4d374cc 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2355,6 +2355,7 @@
     { 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 },
+    { PEER_FLAG_NEXTHOP_SELF_ALL,         1, peer_change_reset_out },
     { 0, 0, 0 }
   };
 
@@ -4990,7 +4991,9 @@
   /* Nexthop self. */
   if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF)
       && ! peer->af_group[afi][safi])
-    vty_out (vty, " neighbor %s next-hop-self%s", addr, VTY_NEWLINE);
+    vty_out (vty, " neighbor %s next-hop-self%s%s", addr,
+	     peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF_ALL) ?
+	     " all" : "", VTY_NEWLINE);
 
   /* Remove private AS. */
   if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index a1b1273..eae803d 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -412,6 +412,7 @@
 #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 */
+#define PEER_FLAG_NEXTHOP_SELF_ALL          (1 << 17) /* next-hop-self all */
 
   /* MD5 password */
   char *password;
diff --git a/doc/bgpd.texi b/doc/bgpd.texi
index cb9789b..de70970 100644
--- a/doc/bgpd.texi
+++ b/doc/bgpd.texi
@@ -299,10 +299,12 @@
 use should be avoided.
 @end deffn
 
-@deffn {BGP} {neighbor @var{peer} next-hop-self} {}
-@deffnx {BGP} {no neighbor @var{peer} next-hop-self} {}
+@deffn {BGP} {neighbor @var{peer} next-hop-self [all]} {}
+@deffnx {BGP} {no neighbor @var{peer} next-hop-self [all]} {}
 This command specifies an announced route's nexthop as being equivalent
-to the address of the bgp router.
+to the address of the bgp router if it is learned via eBGP.
+If the optional keyword @code{all} is specified the modifiation is done
+also for routes learned via iBGP.
 @end deffn
 
 @deffn {BGP} {neighbor @var{peer} update-source @var{<ifname|address>}} {}
diff --git a/ripd/ripd.c b/ripd/ripd.c
index dfeb951..8a7fef8 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -2169,7 +2169,7 @@
 
   /* Reset stream and RTE counter. */
   stream_reset (s);
-  rtemax = (RIP_PACKET_MAXSIZ - 4) / 20;
+  rtemax = RIP_MAX_RTE;
 
   /* Get RIP interface. */
   ri = ifc->ifp->info;
diff --git a/ripd/ripd.h b/ripd/ripd.h
index 45b07b9..0fc2fd3 100644
--- a/ripd/ripd.h
+++ b/ripd/ripd.h
@@ -49,7 +49,7 @@
 #define RIP_RTE_SIZE                    20
 
 /* Max count of routing table entry in one rip packet. */
-#define RIP_MAX_RTE                     25
+#define RIP_MAX_RTE   ((RIP_PACKET_MAXSIZ - RIP_HEADER_SIZE) / RIP_RTE_SIZE)
 
 /* RIP version 2 multicast address. */
 #ifndef INADDR_RIP_GROUP