bgpd: add replace-as modifier for BGP neighbor

Added replace-as modifier for BGP neighbors when using
local-as. If the replace-as modifier is specified, only the
replacement AS as specified by the local-as modifier is
prepended to the AS_PATH, not the process's AS.

In bgp_attr.c, I decided that

if (peer->change_local_as) {
  /* If replace-as is specified, we only use the change_local_as when
     advertising routes. */
  if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) {
    aspath = aspath_add_seq (aspath, peer->local_as);
  }
  aspath = aspath_add_seq (aspath, peer->change_local_as);
} else {
  aspath = aspath_add_seq (aspath, peer->local_as);
}

was clearer than the alternative that didn't duplicate the prepending of the
process's AS:

/* First, append the process local AS unless we have an alternate local_as
 * and we're replacing it (as opposed to just prepending it). */
if (! (peer->change_local_as
       && CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) ) {
  aspath = aspath_add_seq (aspath, peer->local_as);
}

if (peer->change_local_as)
  aspath = aspath_add_seq (aspath, peer->change_local_as);
}

But I could be convinced otherwise.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index cb7ff1f..0f28894 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1570,7 +1570,7 @@
   if (! peer)
     return CMD_WARNING;
 
-  ret = peer_local_as_set (peer, atoi (argv[1]), 0);
+  ret = peer_local_as_set (peer, atoi (argv[1]), 0, 0);
   return bgp_vty_return (vty, ret);
 }
 
@@ -1590,10 +1590,32 @@
   if (! peer)
     return CMD_WARNING;
 
-  ret = peer_local_as_set (peer, atoi (argv[1]), 1);
+  ret = peer_local_as_set (peer, atoi (argv[1]), 1, 0);
   return bgp_vty_return (vty, ret);
 }
 
+DEFUN (neighbor_local_as_no_prepend_replace_as,
+       neighbor_local_as_no_prepend_replace_as_cmd,
+       NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE " no-prepend replace-as",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify a local-as number\n"
+       "AS number used as local AS\n"
+       "Do not prepend local-as to updates from ebgp peers\n"
+       "Do not prepend local-as to updates from ibgp peers\n")
+{
+  struct peer *peer;
+  int ret;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  ret = peer_local_as_set (peer, atoi (argv[1]), 1, 1);
+  return bgp_vty_return (vty, ret);
+}
+
+
 DEFUN (no_neighbor_local_as,
        no_neighbor_local_as_cmd,
        NO_NEIGHBOR_CMD2 "local-as",
@@ -1631,6 +1653,17 @@
        "Specify a local-as number\n"
        "AS number used as local AS\n"
        "Do not prepend local-as to updates from ebgp peers\n")
+
+ALIAS (no_neighbor_local_as,
+       no_neighbor_local_as_val3_cmd,
+       NO_NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE " no-prepend replace-as",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify a local-as number\n"
+       "AS number used as local AS\n"
+       "Do not prepend local-as to updates from ebgp peers\n"
+       "Do not prepend local-as to updates from ibgp peers\n")
 
 DEFUN (neighbor_password,
        neighbor_password_cmd,
@@ -7494,10 +7527,12 @@
   /* Configured IP address. */
   vty_out (vty, "BGP neighbor is %s, ", p->host);
   vty_out (vty, "remote AS %u, ", p->as);
-  vty_out (vty, "local AS %u%s, ",
+  vty_out (vty, "local AS %u%s%s, ",
 	   p->change_local_as ? p->change_local_as : p->local_as,
 	   CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ?
-	   " no-prepend" : "");
+	   " no-prepend" : "",
+	   CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ?
+	   " replace-as" : "");
   vty_out (vty, "%s link%s",
 	   p->as == p->local_as ? "internal" : "external",
 	   VTY_NEWLINE);
@@ -9175,9 +9210,11 @@
   /* "neighbor local-as" commands. */
   install_element (BGP_NODE, &neighbor_local_as_cmd);
   install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd);
+  install_element (BGP_NODE, &neighbor_local_as_no_prepend_replace_as_cmd);
   install_element (BGP_NODE, &no_neighbor_local_as_cmd);
   install_element (BGP_NODE, &no_neighbor_local_as_val_cmd);
   install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd);
+  install_element (BGP_NODE, &no_neighbor_local_as_val3_cmd);
 
   /* "neighbor password" commands. */
   install_element (BGP_NODE, &neighbor_password_cmd);