summaryrefslogtreecommitdiffstats
path: root/bgpd/bgpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgpd.c')
-rw-r--r--bgpd/bgpd.c749
1 files changed, 590 insertions, 159 deletions
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 249d20f3..72ad1c19 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -61,6 +61,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_network.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_nht.h"
#ifdef HAVE_SNMP
#include "bgpd/bgp_snmp.h"
#endif /* HAVE_SNMP */
@@ -76,6 +77,44 @@ struct bgp_master *bm;
/* BGP community-list. */
struct community_list_handler *bgp_clist;
+
+static inline void
+bgp_session_reset(struct peer *peer)
+{
+ if (peer->doppelganger && (peer->doppelganger->status != Deleted)
+ && !(CHECK_FLAG(peer->doppelganger->flags, PEER_FLAG_CONFIG_NODE)))
+ peer_delete(peer->doppelganger);
+
+ BGP_EVENT_ADD (peer, BGP_Stop);
+}
+
+/*
+ * During session reset, we may delete the doppelganger peer, which would
+ * be the next node to the current node. If the session reset was invoked
+ * during walk of peer list, we would end up accessing the freed next
+ * node. This function moves the next node along.
+ */
+static inline void
+bgp_session_reset_safe(struct peer *peer, struct listnode **nnode)
+{
+ struct listnode *n;
+ struct peer *npeer;
+
+ n = (nnode) ? *nnode : NULL;
+ npeer = (n) ? listgetdata(n) : NULL;
+
+ if (peer->doppelganger && (peer->doppelganger->status != Deleted)
+ && !(CHECK_FLAG(peer->doppelganger->flags, PEER_FLAG_CONFIG_NODE)))
+ {
+ if (peer->doppelganger == npeer)
+ /* nnode and *nnode are confirmed to be non-NULL here */
+ *nnode = (*nnode)->next;
+ peer_delete(peer->doppelganger);
+ }
+
+ BGP_EVENT_ADD (peer, BGP_Stop);
+}
+
/* BGP global flag manipulation. */
int
bgp_option_set (int flag)
@@ -311,9 +350,8 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as)
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
-
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, &nnode);
}
}
else
@@ -332,7 +370,7 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, &nnode);
}
}
}
@@ -362,7 +400,7 @@ bgp_confederation_id_unset (struct bgp *bgp)
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, &nnode);
}
}
return 0;
@@ -425,7 +463,7 @@ bgp_confederation_peers_add (struct bgp *bgp, as_t as)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, &nnode);
}
}
}
@@ -481,7 +519,7 @@ bgp_confederation_peers_remove (struct bgp *bgp, as_t as)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, &nnode);
}
}
}
@@ -530,7 +568,7 @@ peer_rsclient_active (struct peer *peer)
}
/* Peer comparison function for sorting. */
-static int
+int
peer_cmp (struct peer *p1, struct peer *p2)
{
return sockunion_cmp (&p1->su, &p2->su);
@@ -759,6 +797,10 @@ peer_free (struct peer *peer)
XFREE(MTYPE_TMP, peer->notify.data);
bgp_sync_delete (peer);
+
+ if (peer->conf_if)
+ XFREE (MTYPE_PEER_CONF_IF, peer->conf_if);
+
memset (peer, 0, sizeof (struct peer));
XFREE (MTYPE_BGP_PEER, peer);
@@ -801,7 +843,7 @@ peer_unlock_with_caller (const char *name, struct peer *peer)
return peer;
}
-
+
/* Allocate new peer object, implicitely locked. */
static struct peer *
peer_new (struct bgp *bgp)
@@ -825,11 +867,11 @@ peer_new (struct bgp *bgp)
peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
peer->status = Idle;
peer->ostatus = Idle;
- peer->weight = 0;
- peer->password = NULL;
peer->bgp = bgp;
peer = peer_lock (peer); /* initial reference */
bgp_lock (bgp);
+ peer->weight = 0;
+ peer->password = NULL;
/* Set default flags. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
@@ -847,9 +889,22 @@ peer_new (struct bgp *bgp)
/* Create buffers. */
peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE);
peer->obuf = stream_fifo_new ();
- peer->work = stream_new (BGP_MAX_PACKET_SIZE);
+
+ /* We use a larger buffer for peer->work in the event that:
+ * - We RX a BGP_UPDATE where the attributes alone are just
+ * under BGP_MAX_PACKET_SIZE
+ * - The user configures an outbound route-map that does many as-path
+ * prepends or adds many communities. At most they can have CMD_ARGC_MAX
+ * args in a route-map so there is a finite limit on how large they can
+ * make the attributes.
+ *
+ * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid bounds
+ * checking for every single attribute as we construct an UPDATE.
+ */
+ peer->work = stream_new (BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW);
peer->scratch = stream_new (BGP_MAX_PACKET_SIZE);
+
bgp_sync_init (peer);
/* Get service port number. */
@@ -859,17 +914,149 @@ peer_new (struct bgp *bgp)
return peer;
}
+/*
+ * This function is invoked when a duplicate peer structure associated with
+ * a neighbor is being deleted. If this about-to-be-deleted structure is
+ * the one with all the config, then we have to copy over the info.
+ */
+void
+peer_xfer_config (struct peer *peer_dst, struct peer *peer_src)
+{
+ afi_t afi;
+ safi_t safi;
+
+ assert(peer_src);
+ assert(peer_dst);
+
+ /* The following function is used by both peer group config copy to
+ * individual peer and when we transfer config
+ */
+ if (peer_src->change_local_as)
+ peer_dst->change_local_as = peer_src->change_local_as;
+
+ /* peer flags apply */
+ peer_dst->flags = peer_src->flags;
+ peer_dst->cap = peer_src->cap;
+ peer_dst->config = peer_src->config;
+
+ peer_dst->local_as = peer_src->local_as;
+ peer_dst->ifindex = peer_src->ifindex;
+ peer_dst->port = peer_src->port;
+ peer_sort(peer_dst);
+ peer_dst->rmap_type = peer_src->rmap_type;
+
+ /* Timers */
+ peer_dst->holdtime = peer_src->holdtime;
+ peer_dst->keepalive = peer_src->keepalive;
+ peer_dst->connect = peer_src->connect;
+ peer_dst->v_holdtime = peer_src->v_holdtime;
+ peer_dst->v_keepalive = peer_src->v_keepalive;
+ peer_dst->routeadv = peer_src->routeadv;
+ peer_dst->v_routeadv = peer_src->v_routeadv;
+
+ /* password apply */
+ if (peer_src->password && !peer_dst->password)
+ peer_dst->password = XSTRDUP (MTYPE_PEER_PASSWORD, peer_src->password);
+
+ bgp_md5_set (peer_dst);
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ peer_dst->afc[afi][safi] = peer_src->afc[afi][safi];
+ peer_dst->af_flags[afi][safi] = peer_src->af_flags[afi][safi];
+ peer_dst->allowas_in[afi][safi] = peer_src->allowas_in[afi][safi];
+ }
+
+ /* update-source apply */
+ if (peer_src->update_source)
+ {
+ if (peer_dst->update_source)
+ sockunion_free (peer_dst->update_source);
+ if (peer_dst->update_if)
+ {
+ XFREE (MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
+ peer_dst->update_if = NULL;
+ }
+ peer_dst->update_source = sockunion_dup (peer_src->update_source);
+ }
+ else if (peer_src->update_if)
+ {
+ if (peer_dst->update_if)
+ XFREE (MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
+ if (peer_dst->update_source)
+ {
+ sockunion_free (peer_dst->update_source);
+ peer_dst->update_source = NULL;
+ }
+ peer_dst->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, peer_src->update_if);
+ }
+
+ if (peer_src->ifname)
+ {
+ if (peer_dst->ifname)
+ free(peer_dst->ifname);
+
+ peer_dst->ifname = strdup(peer_src->ifname);
+ }
+}
+
+/*
+ * Set or reset the peer address socketunion structure based on the
+ * learnt peer address. Currently via the source address of the
+ * ipv6 ND router-advertisement.
+ */
+void
+bgp_peer_conf_if_to_su_update (struct peer *peer)
+{
+ struct interface *ifp;
+ struct nbr_connected *ifc;
+
+ if (!peer->conf_if)
+ return;
+
+ if ((ifp = if_lookup_by_name(peer->conf_if)) &&
+ ifp->nbr_connected &&
+ (ifc = listnode_head(ifp->nbr_connected)))
+ {
+ peer->su.sa.sa_family = AF_INET6;
+ memcpy(&peer->su.sin6.sin6_addr, &ifc->address->u.prefix,
+ sizeof (struct in6_addr));
+#ifdef SIN6_LEN
+ peer->su.sin6.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+ }
+ else
+ {
+ /* This works as an indication of unresolved peer address
+ on a BGP interface*/
+ peer->su.sa.sa_family = AF_UNSPEC;
+ memset(&peer->su.sin6.sin6_addr, 0, sizeof (struct in6_addr));
+ }
+}
+
/* Create new BGP peer. */
-static struct peer *
-peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
- as_t remote_as, afi_t afi, safi_t safi)
+struct peer *
+peer_create (union sockunion *su, const char *conf_if, struct bgp *bgp,
+ as_t local_as, as_t remote_as, afi_t afi, safi_t safi)
{
int active;
struct peer *peer;
char buf[SU_ADDRSTRLEN];
peer = peer_new (bgp);
- peer->su = *su;
+ if (conf_if)
+ {
+ peer->conf_if = XSTRDUP (MTYPE_PEER_CONF_IF, conf_if);
+ bgp_peer_conf_if_to_su_update(peer);
+ peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, conf_if);
+ }
+ else if (su)
+ {
+ peer->su = *su;
+ sockunion2str (su, buf, SU_ADDRSTRLEN);
+ peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf);
+ }
peer->local_as = local_as;
peer->as = remote_as;
peer->local_id = bgp->router_id;
@@ -894,9 +1081,7 @@ peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
/* Default TTL set. */
peer->ttl = (peer->sort == BGP_PEER_IBGP) ? 255 : 1;
- /* Make peer's address string. */
- sockunion2str (su, buf, SU_ADDRSTRLEN);
- peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf);
+ SET_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE);
/* Set up peer's events and timers. */
if (! active && peer_active (peer))
@@ -905,6 +1090,26 @@ peer_create (union sockunion *su, struct bgp *bgp, as_t local_as,
return peer;
}
+struct peer *
+peer_conf_interface_get(struct bgp *bgp, const char *conf_if, afi_t afi,
+ safi_t safi)
+{
+ struct peer *peer;
+
+ peer = peer_lookup_by_conf_if (bgp, conf_if);
+ if (!peer)
+ {
+ if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)
+ && afi == AFI_IP && safi == SAFI_UNICAST)
+ peer = peer_create (NULL, conf_if, bgp, bgp->as, 0, 0, 0);
+ else
+ peer = peer_create (NULL, conf_if, bgp, bgp->as, 0, afi, safi);
+
+ }
+
+ return peer;
+}
+
/* Make accept BGP peer. Called from bgp_accept (). */
struct peer *
peer_create_accept (struct bgp *bgp)
@@ -912,7 +1117,7 @@ peer_create_accept (struct bgp *bgp)
struct peer *peer;
peer = peer_new (bgp);
-
+
peer = peer_lock (peer); /* bgp peer list reference */
listnode_add_sort (bgp->peer, peer);
@@ -920,7 +1125,7 @@ peer_create_accept (struct bgp *bgp)
}
/* Change peer's AS number. */
-static void
+void
peer_as_change (struct peer *peer, as_t as)
{
bgp_peer_sort_t type;
@@ -936,7 +1141,7 @@ peer_as_change (struct peer *peer, as_t as)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
type = peer_sort (peer);
peer->as = as;
@@ -1000,13 +1205,16 @@ peer_as_change (struct peer *peer, as_t as)
/* If peer does not exist, create new one. If peer already exists,
set AS number to the peer. */
int
-peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
- afi_t afi, safi_t safi)
+peer_remote_as (struct bgp *bgp, union sockunion *su, const char *conf_if, as_t *as,
+ afi_t afi, safi_t safi)
{
struct peer *peer;
as_t local_as;
- peer = peer_lookup (bgp, su);
+ if (conf_if)
+ peer = peer_lookup_by_conf_if (bgp, conf_if);
+ else
+ peer = peer_lookup (bgp, su);
if (peer)
{
@@ -1043,6 +1251,8 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
}
else
{
+ if (conf_if)
+ return BGP_ERR_NO_INTERFACE_CONFIG;
/* If the peer is not part of our confederation, and its not an
iBGP peer then spoof the source AS */
@@ -1058,9 +1268,9 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as,
if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)
&& afi == AFI_IP && safi == SAFI_UNICAST)
- peer_create (su, bgp, local_as, *as, 0, 0);
+ peer = peer_create (su, conf_if, bgp, local_as, *as, 0, 0);
else
- peer_create (su, bgp, local_as, *as, afi, safi);
+ peer = peer_create (su, conf_if, bgp, local_as, *as, afi, safi);
}
return 0;
@@ -1195,13 +1405,13 @@ peer_nsf_stop (struct peer *peer)
if (peer->t_gr_restart)
{
BGP_TIMER_OFF (peer->t_gr_restart);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s graceful restart timer stopped", peer->host);
}
if (peer->t_gr_stale)
{
BGP_TIMER_OFF (peer->t_gr_stale);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
}
bgp_clear_route_all (peer);
@@ -1229,12 +1439,14 @@ peer_delete (struct peer *peer)
struct listnode *pn;
assert (peer->status != Deleted);
-
+
bgp = peer->bgp;
if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
peer_nsf_stop (peer);
+ SET_FLAG(peer->flags, PEER_FLAG_DELETE);
+
/* If this peer belongs to peer group, clear up the
relationship. */
if (peer->group)
@@ -1253,6 +1465,13 @@ peer_delete (struct peer *peer)
*/
peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
bgp_stop (peer);
+ UNSET_FLAG(peer->flags, PEER_FLAG_DELETE);
+
+ if (peer->doppelganger)
+ peer->doppelganger->doppelganger = NULL;
+ peer->doppelganger = NULL;
+
+ UNSET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
bgp_fsm_change_status (peer, Deleted);
/* Password configuration */
@@ -1266,7 +1485,7 @@ peer_delete (struct peer *peer)
}
bgp_timer_set (peer); /* stops all timers for Deleted */
-
+
/* Delete from all peer list. */
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
&& (pn = listnode_lookup (bgp->peer, peer)))
@@ -1281,12 +1500,15 @@ peer_delete (struct peer *peer)
peer_unlock (peer); /* rsclient list reference */
list_delete_node (bgp->rsclient, pn);
- /* Clear our own rsclient ribs. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- if (CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_RSERVER_CLIENT))
- bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT);
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+ {
+ /* Clear our own rsclient ribs. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_RSERVER_CLIENT))
+ bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT);
+ }
}
/* Free RIB for any family in which peer is RSERVER_CLIENT, and is not
@@ -1765,13 +1987,21 @@ peer_group_delete (struct peer_group *group)
{
struct bgp *bgp;
struct peer *peer;
+ struct peer *other;
struct listnode *node, *nnode;
bgp = group->bgp;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
+ other = peer->doppelganger;
+ peer->group = NULL;
peer_delete (peer);
+ if (other && other->status != Deleted)
+ {
+ other->group = NULL;
+ peer_delete(other);
+ }
}
list_delete (group->peer);
@@ -1792,7 +2022,7 @@ peer_group_delete (struct peer_group *group)
int
peer_group_remote_as_delete (struct peer_group *group)
{
- struct peer *peer;
+ struct peer *peer, *other;
struct listnode *node, *nnode;
if (! group->conf->as)
@@ -1800,7 +2030,16 @@ peer_group_remote_as_delete (struct peer_group *group)
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
{
+ other = peer->doppelganger;
+
+ peer->group = NULL;
peer_delete (peer);
+
+ if (other && other->status != Deleted)
+ {
+ other->group = NULL;
+ peer_delete(other);
+ }
}
list_delete_all_node (group->peer);
@@ -1811,10 +2050,9 @@ peer_group_remote_as_delete (struct peer_group *group)
/* Bind specified peer to peer group. */
int
-peer_group_bind (struct bgp *bgp, union sockunion *su,
+peer_group_bind (struct bgp *bgp, union sockunion *su, struct peer *peer,
struct peer_group *group, afi_t afi, safi_t safi, as_t *as)
{
- struct peer *peer;
int first_member = 0;
/* Check peer group's address family. */
@@ -1822,7 +2060,8 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
return BGP_ERR_PEER_GROUP_AF_UNCONFIGURED;
/* Lookup the peer. */
- peer = peer_lookup (bgp, su);
+ if (!peer)
+ peer = peer_lookup (bgp, su);
/* Create a new peer. */
if (! peer)
@@ -1830,13 +2069,14 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
if (! group->conf->as)
return BGP_ERR_PEER_GROUP_NO_REMOTE_AS;
- peer = peer_create (su, bgp, bgp->as, group->conf->as, afi, safi);
+ peer = peer_create (su, NULL, bgp, bgp->as, group->conf->as, afi, safi);
peer->group = group;
peer->af_group[afi][safi] = 1;
peer = peer_lock (peer); /* group->peer list reference */
listnode_add (group->peer, peer);
peer_group2peer_config_copy (group, peer, afi, safi);
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
return 0;
}
@@ -1943,6 +2183,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
}
peer_group2peer_config_copy (group, peer, afi, safi);
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
{
@@ -1951,7 +2192,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return 0;
}
@@ -1960,6 +2201,8 @@ int
peer_group_unbind (struct bgp *bgp, struct peer *peer,
struct peer_group *group, afi_t afi, safi_t safi)
{
+ struct peer *other;
+
if (! peer->af_group[afi][safi])
return 0;
@@ -1979,9 +2222,20 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer,
peer_unlock (peer); /* peer group list reference */
listnode_delete (group->peer, peer);
peer->group = NULL;
+ other = peer->doppelganger;
if (group->conf->as)
{
peer_delete (peer);
+ if (other && other->status != Deleted)
+ {
+ if (other->group)
+ {
+ peer_unlock(other);
+ listnode_delete(group->peer, other);
+ }
+ other->group = NULL;
+ peer_delete(other);
+ }
return 0;
}
peer_global_config_reset (peer);
@@ -1994,7 +2248,7 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return 0;
}
@@ -2045,6 +2299,7 @@ bgp_create (as_t *as, const char *name)
bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS;
}
+ bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
@@ -2057,6 +2312,10 @@ bgp_create (as_t *as, const char *name)
if (name)
bgp->name = strdup (name);
+ bgp->wpkt_quanta = BGP_WRITE_PACKET_MAX;
+ bgp->adv_quanta = BGP_ADV_FIFO_QUANTA;
+ bgp->wd_quanta = BGP_WD_FIFO_QUANTA;
+
THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire,
bgp, bgp->restart_time);
@@ -2152,6 +2411,9 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name)
bgp_router_id_set(bgp, &router_id_zebra);
*bgp_val = bgp;
+ bgp->t_rmap_update = NULL;
+ bgp->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER;
+
/* Create BGP server socket, if first instance. */
if (list_isempty(bm->bgp)
&& !bgp_option_check (BGP_OPT_NO_LISTEN))
@@ -2180,6 +2442,20 @@ bgp_delete (struct bgp *bgp)
THREAD_OFF (bgp->t_startup);
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
+ {
+ if (peer->status == Established ||
+ peer->status == OpenSent ||
+ peer->status == OpenConfirm)
+ {
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_PEER_UNCONFIG);
+ }
+ }
+
+ if (bgp->t_rmap_update)
+ BGP_TIMER_OFF(bgp->t_rmap_update);
+
/* Delete static route. */
bgp_static_delete (bgp);
@@ -2189,17 +2465,6 @@ bgp_delete (struct bgp *bgp)
if (i != ZEBRA_ROUTE_BGP)
bgp_redistribute_unset (bgp, afi, i);
- for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- /* Send notify to remote peer. */
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
- }
-
- peer_delete (peer);
- }
-
for (ALL_LIST_ELEMENTS (bgp->group, node, next, group))
{
for (ALL_LIST_ELEMENTS (group->peer, pnode, pnext, peer))
@@ -2213,6 +2478,17 @@ bgp_delete (struct bgp *bgp)
peer_group_delete (group);
}
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
+ {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ {
+ /* Send notify to remote peer. */
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
+ }
+
+ peer_delete (peer);
+ }
+
assert (listcount (bgp->rsclient) == 0);
if (bgp->peer_self) {
@@ -2284,25 +2560,28 @@ bgp_free (struct bgp *bgp)
}
struct peer *
-peer_lookup (struct bgp *bgp, union sockunion *su)
+peer_lookup_by_conf_if (struct bgp *bgp, const char *conf_if)
{
struct peer *peer;
struct listnode *node, *nnode;
+ if (!conf_if)
+ return NULL;
+
if (bgp != NULL)
{
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (sockunion_same (&peer->su, su)
+ if (peer->conf_if && !strcmp(peer->conf_if, conf_if)
&& ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
return peer;
}
else if (bm->bgp != NULL)
{
struct listnode *bgpnode, *nbgpnode;
-
+
for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp))
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (sockunion_same (&peer->su, su)
+ if (peer->conf_if && !strcmp(peer->conf_if, conf_if)
&& ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
return peer;
}
@@ -2310,44 +2589,27 @@ peer_lookup (struct bgp *bgp, union sockunion *su)
}
struct peer *
-peer_lookup_with_open (union sockunion *su, as_t remote_as,
- struct in_addr *remote_id, int *as)
+peer_lookup (struct bgp *bgp, union sockunion *su)
{
struct peer *peer;
- struct listnode *node;
- struct listnode *bgpnode;
- struct bgp *bgp;
-
- if (! bm->bgp)
- return NULL;
+ struct listnode *node, *nnode;
- for (ALL_LIST_ELEMENTS_RO (bm->bgp, bgpnode, bgp))
+ if (bgp != NULL)
{
- for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
- {
- if (sockunion_same (&peer->su, su)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- if (peer->as == remote_as
- && peer->remote_id.s_addr == remote_id->s_addr)
- return peer;
- if (peer->as == remote_as)
- *as = 1;
- }
- }
-
- for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
- {
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ if (sockunion_same (&peer->su, su)
+ && (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE)))
+ return peer;
+ }
+ else if (bm->bgp != NULL)
+ {
+ struct listnode *bgpnode, *nbgpnode;
+
+ for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp))
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
if (sockunion_same (&peer->su, su)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- {
- if (peer->as == remote_as
- && peer->remote_id.s_addr == 0)
- return peer;
- if (peer->as == remote_as)
- *as = 1;
- }
- }
+ && (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE)))
+ return peer;
}
return NULL;
}
@@ -2356,6 +2618,8 @@ peer_lookup_with_open (union sockunion *su, as_t remote_as,
int
peer_active (struct peer *peer)
{
+ if (BGP_PEER_SU_UNSPEC(peer))
+ return 0;
if (peer->afc[AFI_IP][SAFI_UNICAST]
|| peer->afc[AFI_IP][SAFI_MULTICAST]
|| peer->afc[AFI_IP][SAFI_MPLS_VPN]
@@ -2404,16 +2668,31 @@ peer_change_action (struct peer *peer, afi_t afi, safi_t safi,
return;
if (type == peer_change_reset)
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ {
+ /* If we're resetting session, we've to delete both peer struct */
+ if ((peer->doppelganger) && (peer->doppelganger->status != Deleted)
+ && (!CHECK_FLAG(peer->doppelganger->flags,
+ PEER_FLAG_CONFIG_NODE)))
+ peer_delete(peer->doppelganger);
+
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
else if (type == peer_change_reset_in)
{
if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
|| CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
else
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ {
+ if ((peer->doppelganger) && (peer->doppelganger->status != Deleted)
+ && (!CHECK_FLAG(peer->doppelganger->flags,
+ PEER_FLAG_CONFIG_NODE)))
+ peer_delete(peer->doppelganger);
+
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
}
else if (type == peer_change_reset_out)
bgp_announce_route (peer, afi, safi);
@@ -2458,11 +2737,14 @@ static const struct peer_flag_action peer_af_flag_action_list[] =
{ PEER_FLAG_NEXTHOP_UNCHANGED, 1, peer_change_reset_out },
{ PEER_FLAG_MED_UNCHANGED, 1, peer_change_reset_out },
{ PEER_FLAG_REMOVE_PRIVATE_AS, 1, peer_change_reset_out },
+ { PEER_FLAG_REMOVE_PRIVATE_AS_ALL, 1, peer_change_reset_out },
+ { PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,1, peer_change_reset_out },
{ PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in },
{ 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 },
+ { PEER_FLAG_AS_OVERRIDE, 1, peer_change_reset_out },
{ 0, 0, 0 }
};
@@ -2530,19 +2812,19 @@ peer_flag_modify_action (struct peer *peer, u_int32_t flag)
if (peer->t_pmax_restart)
{
BGP_TIMER_OFF (peer->t_pmax_restart);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Maximum-prefix restart timer canceled",
peer->host);
}
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop (peer);
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
+ peer_nsf_stop (peer);
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
else
{
@@ -2563,7 +2845,7 @@ peer_flag_modify_action (struct peer *peer, u_int32_t flag)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
/* Change specified peer flag. */
@@ -2706,6 +2988,11 @@ peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
&& peer_sort (peer) == BGP_PEER_IBGP)
return BGP_ERR_REMOVE_PRIVATE_AS;
+ /* as-override is not allowed for IBGP peers */
+ if (flag & PEER_FLAG_AS_OVERRIDE
+ && peer_sort (peer) == BGP_PEER_IBGP)
+ return BGP_ERR_AS_OVERRIDE;
+
/* When unset the peer-group member's flag we have to check
peer-group configuration. */
if (! set && peer->af_group[afi][safi])
@@ -2812,7 +3099,7 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl)
struct listnode *node, *nnode;
struct peer *peer1;
- if (peer->sort == BGP_PEER_IBGP)
+ if (peer->sort == BGP_PEER_IBGP || peer->conf_if)
return 0;
/* see comment in peer_ttl_security_hops_set() */
@@ -2960,7 +3247,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return 0;
}
@@ -2992,7 +3279,7 @@ peer_update_source_if_set (struct peer *peer, const char *ifname)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
return 0;
}
@@ -3016,6 +3303,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su)
{
XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
peer->update_if = NULL;
+
}
peer->update_source = sockunion_dup (su);
@@ -3029,7 +3317,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return 0;
}
@@ -3060,7 +3348,7 @@ peer_update_source_addr_set (struct peer *peer, union sockunion *su)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
return 0;
}
@@ -3111,7 +3399,7 @@ peer_update_source_unset (struct peer *peer)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return 0;
}
@@ -3141,7 +3429,7 @@ peer_update_source_unset (struct peer *peer)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
return 0;
}
@@ -3642,8 +3930,7 @@ peer_local_as_set (struct peer *peer, as_t as, int no_prepend, int replace_as)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
-
+ bgp_session_reset(peer);
return 0;
}
@@ -3718,7 +4005,7 @@ peer_local_as_unset (struct peer *peer)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
return 0;
}
@@ -3748,7 +4035,7 @@ peer_password_set (struct peer *peer, const char *password)
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
return (bgp_md5_set (peer) >= 0) ? BGP_SUCCESS : BGP_ERR_TCPSIG_FAILED;
}
@@ -3766,7 +4053,7 @@ peer_password_set (struct peer *peer, const char *password)
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
if (bgp_md5_set (peer) < 0)
ret = BGP_ERR_TCPSIG_FAILED;
@@ -3794,7 +4081,7 @@ peer_password_unset (struct peer *peer)
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
if (peer->password)
XFREE (MTYPE_PEER_PASSWORD, peer->password);
@@ -3817,7 +4104,7 @@ peer_password_unset (struct peer *peer)
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
XFREE (MTYPE_PEER_PASSWORD, peer->password);
peer->password = NULL;
@@ -4250,7 +4537,7 @@ peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct)
}
static void
-peer_aslist_update (void)
+peer_aslist_update (const char *aslist_name)
{
afi_t afi;
safi_t safi;
@@ -4300,8 +4587,42 @@ peer_aslist_update (void)
}
}
}
+static void
+peer_aslist_add (char *aslist_name)
+{
+ peer_aslist_update (aslist_name);
+ route_map_notify_dependencies((char *)aslist_name, RMAP_EVENT_ASLIST_ADDED);
+}
+
+static void
+peer_aslist_del (const char *aslist_name)
+{
+ peer_aslist_update (aslist_name);
+ route_map_notify_dependencies((char *)aslist_name, RMAP_EVENT_ASLIST_DELETED);
+}
+
/* Set route-map to the peer. */
+static void
+peer_reprocess_routes (struct peer *peer, int direct,
+ afi_t afi, safi_t safi)
+{
+ if (peer->status != Established)
+ return;
+
+ if (direct != RMAP_OUT)
+ {
+ if (CHECK_FLAG (peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG))
+ bgp_soft_reconfig_in (peer, afi, safi);
+ else if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+ }
+ else
+ bgp_announce_route(peer, afi, safi);
+}
+
int
peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
@@ -4325,12 +4646,15 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
if (filter->map[direct].name)
free (filter->map[direct].name);
-
+
filter->map[direct].name = strdup (name);
filter->map[direct].map = route_map_lookup_by_name (name);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ peer_reprocess_routes(peer, direct, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4344,6 +4668,7 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
free (filter->map[direct].name);
filter->map[direct].name = strdup (name);
filter->map[direct].map = route_map_lookup_by_name (name);
+ peer_reprocess_routes (peer, direct, afi, safi);
}
return 0;
}
@@ -4391,7 +4716,10 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
filter->map[direct].map = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ peer_reprocess_routes(peer, direct, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4405,6 +4733,7 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
free (filter->map[direct].name);
filter->map[direct].name = NULL;
filter->map[direct].map = NULL;
+ peer_reprocess_routes(peer, direct, afi, safi);
}
return 0;
}
@@ -4433,7 +4762,10 @@ peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
filter->usmap.map = route_map_lookup_by_name (name);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ bgp_announce_route (peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4447,6 +4779,7 @@ peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
free (filter->usmap.name);
filter->usmap.name = strdup (name);
filter->usmap.map = route_map_lookup_by_name (name);
+ bgp_announce_route (peer, afi, safi);
}
return 0;
}
@@ -4473,7 +4806,10 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
filter->usmap.map = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ bgp_announce_route(peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
@@ -4487,6 +4823,7 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
free (filter->usmap.name);
filter->usmap.name = NULL;
filter->usmap.map = NULL;
+ bgp_announce_route(peer, afi, safi);
}
return 0;
}
@@ -4511,24 +4848,33 @@ peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi,
else
UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
+ if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (! peer->af_group[afi][safi])
- continue;
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
+ {
+ if (! peer->af_group[afi][safi])
+ continue;
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
- peer->pmax[afi][safi] = max;
- peer->pmax_threshold[afi][safi] = threshold;
- peer->pmax_restart[afi][safi] = restart;
- if (warning)
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
- else
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+ SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+ peer->pmax[afi][safi] = max;
+ peer->pmax_threshold[afi][safi] = threshold;
+ peer->pmax_restart[afi][safi] = restart;
+ if (warning)
+ SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+ else
+ UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+
+ if ((peer->status == Established) && (peer->afc[afi][safi]))
+ bgp_maximum_prefix_overflow (peer, afi, safi, 1);
+ }
+ }
+ else
+ {
+ if ((peer->status == Established) && (peer->afc[afi][safi]))
+ bgp_maximum_prefix_overflow (peer, afi, safi, 1);
}
+
return 0;
}
@@ -4650,7 +4996,11 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
if (peer->fd >= 0)
- sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - gtsm_hops);
+ sockopt_minttl (peer->su.sa.sa_family, peer->fd,
+ MAXTTL + 1 - gtsm_hops);
+ if (peer->status != Established && peer->doppelganger)
+ sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd,
+ MAXTTL + 1 - gtsm_hops);
}
else
{
@@ -4672,9 +5022,9 @@ peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops)
}
else if (peer->status < Established)
{
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Min-ttl changed", peer->host);
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset(peer);
}
}
}
@@ -4702,6 +5052,9 @@ peer_ttl_security_hops_unset (struct peer *peer)
{
if (peer->fd >= 0)
sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
+
+ if (peer->status != Established && peer->doppelganger)
+ sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd, 0);
}
else
{
@@ -4712,14 +5065,24 @@ peer_ttl_security_hops_unset (struct peer *peer)
if (peer->fd >= 0)
sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
+
+ if (peer->status != Established && peer->doppelganger)
+ sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd, 0);
}
}
return peer_ebgp_multihop_unset (opeer);
}
+/*
+ * If peer clear is invoked in a loop for all peers on the BGP instance,
+ * it may end up freeing the doppelganger, and if this was the next node
+ * to the current node, we would end up accessing the freed next node.
+ * Pass along additional parameter which can be updated if next node
+ * is freed; only required when walking the peer list on BGP instance.
+ */
int
-peer_clear (struct peer *peer)
+peer_clear (struct peer *peer, struct listnode **nnode)
{
if (! CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
{
@@ -4729,7 +5092,7 @@ peer_clear (struct peer *peer)
if (peer->t_pmax_restart)
{
BGP_TIMER_OFF (peer->t_pmax_restart);
- if (BGP_DEBUG (events, EVENTS))
+ if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Maximum-prefix restart timer canceled",
peer->host);
}
@@ -4742,7 +5105,7 @@ peer_clear (struct peer *peer)
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_ADMIN_RESET);
else
- BGP_EVENT_ADD (peer, BGP_Stop);
+ bgp_session_reset_safe(peer, nnode);
}
return 0;
}
@@ -4954,7 +5317,11 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
char buf[SU_ADDRSTRLEN];
char *addr;
- addr = peer->host;
+ if (peer->conf_if)
+ addr = peer->conf_if;
+ else
+ addr = peer->host;
+
if (peer_group_active (peer))
g_peer = peer->group->conf;
@@ -4963,6 +5330,9 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
************************************/
if (afi == AFI_IP && safi == SAFI_UNICAST)
{
+ if (peer->conf_if)
+ vty_out (vty, " neighbor %s interface%s", addr, VTY_NEWLINE);
+
/* remote-as. */
if (! peer_group_active (peer))
{
@@ -5173,11 +5543,27 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
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)
- && ! peer->af_group[afi][safi])
- vty_out (vty, " neighbor %s remove-private-AS%s",
- addr, VTY_NEWLINE);
+ /* remove-private-AS */
+ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) && !peer->af_group[afi][safi])
+ {
+ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_ALL) &&
+ peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE))
+ vty_out (vty, " neighbor %s remove-private-AS all replace-AS%s", addr, VTY_NEWLINE);
+
+ else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE))
+ vty_out (vty, " neighbor %s remove-private-AS replace-AS%s", addr, VTY_NEWLINE);
+
+ else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_ALL))
+ vty_out (vty, " neighbor %s remove-private-AS all%s", addr, VTY_NEWLINE);
+
+ else
+ vty_out (vty, " neighbor %s remove-private-AS%s", addr, VTY_NEWLINE);
+ }
+
+ /* as-override */
+ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_AS_OVERRIDE) &&
+ !peer->af_group[afi][safi])
+ vty_out (vty, " neighbor %s as-override%s", addr, VTY_NEWLINE);
/* send-community print. */
if (! peer->af_group[afi][safi])
@@ -5357,7 +5743,7 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
{
if (peer->afc[afi][safi])
{
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ if (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE))
{
bgp_config_write_family_header (vty, afi, safi, &write);
bgp_config_write_peer (vty, bgp, peer, afi, safi);
@@ -5366,6 +5752,7 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
}
bgp_config_write_maxpaths (vty, bgp, afi, safi, &write);
+ bgp_config_write_table_map (vty, bgp, afi, safi, &write);
if (write)
vty_out (vty, " exit-address-family%s", VTY_NEWLINE);
@@ -5478,6 +5865,27 @@ bgp_config_write (struct vty *vty)
if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
vty_out (vty, " bgp deterministic-med%s", VTY_NEWLINE);
+ /* BGP update-delay. */
+ bgp_config_write_update_delay (vty, bgp);
+
+ if (bgp->v_maxmed_onstartup != BGP_MAXMED_ONSTARTUP_UNCONFIGURED)
+ {
+ vty_out (vty, " bgp max-med on-startup %d", bgp->v_maxmed_onstartup);
+ if (bgp->maxmed_onstartup_value != BGP_MAXMED_VALUE_DEFAULT)
+ vty_out (vty, " %d", bgp->maxmed_onstartup_value);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ if (bgp->v_maxmed_admin != BGP_MAXMED_ADMIN_UNCONFIGURED)
+ {
+ vty_out (vty, " bgp max-med administrative");
+ if (bgp->maxmed_admin_value != BGP_MAXMED_VALUE_DEFAULT)
+ vty_out (vty, " %d", bgp->maxmed_admin_value);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+
+ /* write quanta */
+ bgp_config_write_wpkt_quanta (vty, bgp);
+
/* BGP graceful-restart. */
if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME)
vty_out (vty, " bgp graceful-restart stalepath-time %d%s",
@@ -5493,6 +5901,10 @@ bgp_config_write (struct vty *vty)
if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) {
vty_out (vty, " bgp bestpath as-path multipath-relax%s", VTY_NEWLINE);
}
+ if (bgp_flag_check (bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) {
+ vty_out (vty, " bgp route-reflector allow-outbound-policy%s",
+ VTY_NEWLINE);
+ }
if (bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID))
vty_out (vty, " bgp bestpath compare-routerid%s", VTY_NEWLINE);
if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED)
@@ -5510,9 +5922,6 @@ bgp_config_write (struct vty *vty)
if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
vty_out (vty, " bgp network import-check%s", VTY_NEWLINE);
- /* BGP scan interval. */
- bgp_config_write_scan_time (vty);
-
/* BGP flag dampening. */
if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST],
BGP_CONFIG_DAMPENING))
@@ -5530,6 +5939,10 @@ bgp_config_write (struct vty *vty)
vty_out (vty, " timers bgp %d %d%s", bgp->default_keepalive,
bgp->default_holdtime, VTY_NEWLINE);
+ if (bgp->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER)
+ vty_out (vty, " bgp route-map delay-timer %d%s", bgp->rmap_update_timer,
+ VTY_NEWLINE);
+
/* peer-group */
for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
{
@@ -5539,12 +5952,13 @@ bgp_config_write (struct vty *vty)
/* Normal neighbor configuration. */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
+ if (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE))
bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST);
}
/* maximum-paths */
bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
+ bgp_config_write_table_map (vty, bgp, AFI_IP, SAFI_UNICAST, &write);
/* Distance configuration. */
bgp_config_write_distance (vty, bgp);
@@ -5598,12 +6012,16 @@ bgp_master_init (void)
void
bgp_init (void)
{
- /* BGP VTY commands installation. */
- bgp_vty_init ();
+
+ /* allocates some vital data structures used by peer commands in vty_init */
+ bgp_scan_init ();
/* Init zebra. */
bgp_zebra_init (bm->master);
+ /* BGP VTY commands installation. */
+ bgp_vty_init ();
+
/* BGP inits. */
bgp_attr_init ();
bgp_debug_init ();
@@ -5611,7 +6029,7 @@ bgp_init (void)
bgp_route_init ();
bgp_route_map_init ();
bgp_address_init ();
- bgp_scan_init ();
+ bgp_scan_vty_init();
bgp_mplsvpn_init ();
bgp_encap_init ();
@@ -5622,8 +6040,8 @@ bgp_init (void)
/* Filter list initialize. */
bgp_filter_init ();
- as_list_add_hook (peer_aslist_update);
- as_list_delete_hook (peer_aslist_update);
+ as_list_add_hook (peer_aslist_add);
+ as_list_delete_hook (peer_aslist_del);
/* Prefix list initialize.*/
prefix_list_init ();
@@ -5646,12 +6064,25 @@ bgp_terminate (void)
struct listnode *node, *nnode;
struct listnode *mnode, *mnnode;
+ /* Close the listener sockets first as this prevents peers from attempting
+ * to reconnect on receiving the peer unconfig message. In the presence
+ * of a large number of peers this will ensure that no peer is left with
+ * a dangling connection
+ */
+ /* reverse bgp_master_init */
+ bgp_close();
+ if (bm->listen_sockets)
+ list_free(bm->listen_sockets);
+ bm->listen_sockets = NULL;
+
for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (peer->status == Established)
+ if (peer->status == Established ||
+ peer->status == OpenSent ||
+ peer->status == OpenConfirm)
bgp_notify_send (peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_PEER_UNCONFIG);
-
+
bgp_cleanup_routes ();
if (bm->process_main_queue)