bgpd: implement "next-hop-self all"

As specified in:
http://www.cisco.com/c/en/us/td/docs/ios-xml/ios/iproute_bgp/command/irg-cr-book/bgp-m1.html#wp4972925610

This allows overriding next-hop for ibgp learned routes on an
RR for reflected routes.

Especially useful for using iBGP in DMVPN setups. See:
http://blog.ipspace.net/2014/04/changes-in-ibgp-next-hop-processing.html

Signed-off-by: Timo Teräs <timo.teras@iki.fi>
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index f421ca5..232a6a1 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -976,7 +976,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_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>}} {}