]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: add replace-as modifier for BGP neighbor
authorAndrew Certain <certain@amazon.com>
Wed, 7 Nov 2012 23:50:07 +0000 (23:50 +0000)
committerDavid Lamparter <equinox@opensourcerouting.org>
Fri, 30 Nov 2012 20:10:00 +0000 (21:10 +0100)
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>
bgpd/bgp_attr.c
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/bgpd.h

index cdc99ab3ac60ed8ddb1b3d1c655bb5334c707f58..f48a5438b6b663ddbbb8887b8eb7f557fafea958 100644 (file)
@@ -2085,9 +2085,16 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
        }
       else
        {
-         aspath = aspath_add_seq (aspath, peer->local_as);
-         if (peer->change_local_as)
+         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);
+          }
        }
     }
   else if (peer->sort == BGP_PEER_CONFED)
index cb7ff1fa36d0b2a1bcf0d627ff0385e75d931031..0f28894819b0abf529d5a83ee990ee1f3c48b5d2 100644 (file)
@@ -1570,7 +1570,7 @@ DEFUN (neighbor_local_as,
   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 @@ DEFUN (neighbor_local_as_no_prepend,
   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 @@ ALIAS (no_neighbor_local_as,
        "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")
 \f
 DEFUN (neighbor_password,
        neighbor_password_cmd,
@@ -7494,10 +7527,12 @@ bgp_show_peer (struct vty *vty, struct peer *p)
   /* 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 @@ bgp_vty_init (void)
   /* "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);
index 69c8c0a33dddae4aceb90a41344fe7683523f669..908bdd94f88b392105b4dca887ca5579f3840e3d 100644 (file)
@@ -962,6 +962,7 @@ peer_as_change (struct peer *peer, as_t as)
     {
       peer->change_local_as = 0;
       UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+      UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
     }
 }
 
@@ -1830,6 +1831,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
        {
          group->conf->change_local_as = 0;
          UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+         UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
        }
     }
 
@@ -3405,7 +3407,7 @@ peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi)
 }
 \f
 int
-peer_local_as_set (struct peer *peer, as_t as, int no_prepend)
+peer_local_as_set (struct peer *peer, as_t as, int no_prepend, int replace_as)
 {
   struct bgp *bgp = peer->bgp;
   struct peer_group *group;
@@ -3421,9 +3423,14 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend)
   if (peer_group_active (peer))
     return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER;
 
+  if (peer->as == as)
+    return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS;
+
   if (peer->change_local_as == as &&
       ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && no_prepend)
-       || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && ! no_prepend)))
+       || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && ! no_prepend)) &&
+      ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) && replace_as)
+       || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) && ! replace_as)))
     return 0;
 
   peer->change_local_as = as;
@@ -3432,6 +3439,11 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend)
   else
     UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
 
+  if (replace_as)
+    SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+  else
+    UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+
   if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
     {
       if (peer->status == Established)
@@ -3455,6 +3467,11 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend)
       else
        UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
 
+      if (replace_as)
+        SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+      else
+        UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+
       if (peer->status == Established)
        {
          peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
@@ -3482,6 +3499,7 @@ peer_local_as_unset (struct peer *peer)
 
   peer->change_local_as = 0;
   UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+  UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
 
   if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
     {
@@ -3502,6 +3520,7 @@ peer_local_as_unset (struct peer *peer)
     {
       peer->change_local_as = 0;
       UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+      UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
 
       if (peer->status == Established)
        {
@@ -4770,10 +4789,12 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
       /* local-as. */
       if (peer->change_local_as)
        if (! peer_group_active (peer))
-         vty_out (vty, " neighbor %s local-as %u%s%s", addr,
+         vty_out (vty, " neighbor %s local-as %u%s%s%s", addr,
                   peer->change_local_as,
                   CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ?
-                  " no-prepend" : "", VTY_NEWLINE);
+                  " no-prepend" : "",
+                  CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ?
+                  " replace-as" : "", VTY_NEWLINE);
 
       /* Description. */
       if (peer->desc)
index 63e326af9e5a07a3eceb6b8cc0e2b5b5205ec5c7..0746f0dd72fc8ed03d90e9095edd0a6caa6353fd 100644 (file)
@@ -381,6 +381,7 @@ struct peer
 #define PEER_FLAG_DYNAMIC_CAPABILITY        (1 << 5) /* dynamic capability */
 #define PEER_FLAG_DISABLE_CONNECTED_CHECK   (1 << 6) /* disable-connected-check */
 #define PEER_FLAG_LOCAL_AS_NO_PREPEND       (1 << 7) /* local-as no-prepend */
+#define PEER_FLAG_LOCAL_AS_REPLACE_AS       (1 << 8) /* local-as no-prepend replace-as */
 
   /* NSF mode (graceful restart) */
   u_char nsf[AFI_MAX][SAFI_MAX];
@@ -814,6 +815,7 @@ enum bgp_clear_type
 #define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK  -30
 #define BGP_ERR_NO_IBGP_WITH_TTLHACK           -31
 #define BGP_ERR_MAX                            -32
+#define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS    -33
 
 extern struct bgp_master *bm;
 
@@ -941,7 +943,7 @@ extern int peer_distribute_unset (struct peer *, afi_t, safi_t, int);
 extern int peer_allowas_in_set (struct peer *, afi_t, safi_t, int);
 extern int peer_allowas_in_unset (struct peer *, afi_t, safi_t);
 
-extern int peer_local_as_set (struct peer *, as_t, int);
+extern int peer_local_as_set (struct peer *, as_t, int, int);
 extern int peer_local_as_unset (struct peer *);
 
 extern int peer_prefix_list_set (struct peer *, afi_t, safi_t, int, const char *);