diff options
Diffstat (limited to 'bgpd/bgpd.c')
-rw-r--r-- | bgpd/bgpd.c | 749 |
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) |