From 9d3f9705d8b386ccf006c106967c700141e5d049 Mon Sep 17 00:00:00 2001 From: Andrew Certain Date: Wed, 7 Nov 2012 23:50:07 +0000 Subject: 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 --- bgpd/bgp_attr.c | 11 +++++++++-- bgpd/bgp_vty.c | 45 +++++++++++++++++++++++++++++++++++++++++---- bgpd/bgpd.c | 29 +++++++++++++++++++++++++---- bgpd/bgpd.h | 4 +++- 4 files changed, 78 insertions(+), 11 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index cdc99ab3..f48a5438 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -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) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index cb7ff1fa..0f288948 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -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") 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); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 69c8c0a3..908bdd94 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -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) } 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) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 63e326af..0746f0dd 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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 *); -- cgit v1.2.1