--- embedaddon/quagga/bgpd/bgpd.c 2012/02/21 17:26:12 1.1.1.1 +++ embedaddon/quagga/bgpd/bgpd.c 2016/11/02 10:09:10 1.1.1.4 @@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330 #include "stream.h" #include "command.h" #include "sockunion.h" +#include "sockopt.h" #include "network.h" #include "memory.h" #include "filter.h" @@ -35,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330 #include "plist.h" #include "linklist.h" #include "workqueue.h" +#include "table.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -54,13 +56,15 @@ Software Foundation, Inc., 59 Temple Place - Suite 330 #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_encap.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_vty.h" +#include "bgpd/bgp_mpath.h" #ifdef HAVE_SNMP #include "bgpd/bgp_snmp.h" #endif /* HAVE_SNMP */ - + /* BGP process wide configuration. */ static struct bgp_master bgp_master; @@ -71,7 +75,7 @@ struct bgp_master *bm; /* BGP community-list. */ struct community_list_handler *bgp_clist; - + /* BGP global flag manipulation. */ int bgp_option_set (int flag) @@ -81,6 +85,7 @@ bgp_option_set (int flag) case BGP_OPT_NO_FIB: case BGP_OPT_MULTIPLE_INSTANCE: case BGP_OPT_CONFIG_CISCO: + case BGP_OPT_NO_LISTEN: SET_FLAG (bm->options, flag); break; default: @@ -113,7 +118,7 @@ bgp_option_check (int flag) { return CHECK_FLAG (bm->options, flag); } - + /* BGP flag manipulation. */ int bgp_flag_set (struct bgp *bgp, int flag) @@ -134,7 +139,7 @@ bgp_flag_check (struct bgp *bgp, int flag) { return CHECK_FLAG (bgp->flags, flag); } - + /* Internal function to set BGP structure configureation flag. */ static void bgp_config_set (struct bgp *bgp, int config) @@ -153,7 +158,7 @@ bgp_config_check (struct bgp *bgp, int config) { return CHECK_FLAG (bgp->config, config); } - + /* Set BGP router identifier. */ int bgp_router_id_set (struct bgp *bgp, struct in_addr *id) @@ -173,7 +178,7 @@ bgp_router_id_set (struct bgp *bgp, struct in_addr *id { IPV4_ADDR_COPY (&peer->local_id, id); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_RID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -200,10 +205,10 @@ bgp_cluster_id_set (struct bgp *bgp, struct in_addr *c /* Clear all IBGP peer. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { - if (peer_sort (peer) != BGP_PEER_IBGP) + if (peer->sort != BGP_PEER_IBGP) continue; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -228,10 +233,10 @@ bgp_cluster_id_unset (struct bgp *bgp) /* Clear all IBGP peer. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { - if (peer_sort (peer) != BGP_PEER_IBGP) + if (peer->sort != BGP_PEER_IBGP) continue; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -240,7 +245,7 @@ bgp_cluster_id_unset (struct bgp *bgp) } return 0; } - + /* time_t value that is monotonicly increasing * and uneffected by adjustments to system clock */ @@ -271,7 +276,7 @@ bgp_timers_unset (struct bgp *bgp) return 0; } - + /* BGP confederation configuration. */ int bgp_confederation_id_set (struct bgp *bgp, as_t as) @@ -300,7 +305,7 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as) if (peer_sort (peer) == BGP_PEER_EBGP) { peer->local_as = as; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -320,7 +325,7 @@ bgp_confederation_id_set (struct bgp *bgp, as_t as) /* Reset the local_as to be our EBGP one */ if (peer_sort (peer) == BGP_PEER_EBGP) peer->local_as = as; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -349,7 +354,7 @@ bgp_confederation_id_unset (struct bgp *bgp) if (peer_sort (peer) != BGP_PEER_IBGP) { peer->local_as = bgp->as; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -413,7 +418,7 @@ bgp_confederation_peers_add (struct bgp *bgp, as_t as) if (peer->as == as) { peer->local_as = bgp->as; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -469,7 +474,7 @@ bgp_confederation_peers_remove (struct bgp *bgp, as_t if (peer->as == as) { peer->local_as = bgp->confed_id; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -483,7 +488,7 @@ bgp_confederation_peers_remove (struct bgp *bgp, as_t return 0; } - + /* Local preference configuration. */ int bgp_default_local_preference_set (struct bgp *bgp, u_int32_t local_pref) @@ -506,7 +511,7 @@ bgp_default_local_preference_unset (struct bgp *bgp) return 0; } - + /* If peer is RSERVER_CLIENT in at least one address family and is not member of a peer_group for that family, return 1. Used to check wether the peer is included in list bgp->rsclient. */ @@ -593,7 +598,7 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi /* Clear ORF info */ peer->orf_plist[afi][safi] = NULL; sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); - prefix_bgp_orf_remove_all (orf_name); + prefix_bgp_orf_remove_all (afi, orf_name); /* Set default neighbor send-community. */ if (! bgp_option_check (BGP_OPT_CONFIG_CISCO)) @@ -644,9 +649,9 @@ peer_global_config_reset (struct peer *peer) peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; } -/* Check peer's AS number and determin is this peer IBGP or EBGP */ -int -peer_sort (struct peer *peer) +/* Check peer's AS number and determines if this peer is IBGP or EBGP */ +static bgp_peer_sort_t +peer_calc_sort (struct peer *peer) { struct bgp *bgp; @@ -695,7 +700,15 @@ peer_sort (struct peer *peer) } } -static inline void +/* Calculate and cache the peer "sort" */ +bgp_peer_sort_t +peer_sort (struct peer *peer) +{ + peer->sort = peer_calc_sort (peer); + return peer->sort; +} + +static void peer_free (struct peer *peer) { assert (peer->status == Deleted); @@ -711,22 +724,40 @@ peer_free (struct peer *peer) BGP_EVENT_FLUSH (peer); if (peer->desc) - XFREE (MTYPE_PEER_DESC, peer->desc); + { + XFREE (MTYPE_PEER_DESC, peer->desc); + peer->desc = NULL; + } /* Free allocated host character. */ if (peer->host) - XFREE (MTYPE_BGP_PEER_HOST, peer->host); - + { + XFREE (MTYPE_BGP_PEER_HOST, peer->host); + peer->host = NULL; + } + /* Update source configuration. */ if (peer->update_source) - sockunion_free (peer->update_source); + { + sockunion_free (peer->update_source); + peer->update_source = NULL; + } if (peer->update_if) - XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + { + XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); + peer->update_if = NULL; + } if (peer->clear_node_queue) - work_queue_free (peer->clear_node_queue); + { + work_queue_free(peer->clear_node_queue); + peer->clear_node_queue = NULL; + } + if (peer->notify.data) + XFREE(MTYPE_TMP, peer->notify.data); + bgp_sync_delete (peer); memset (peer, 0, sizeof (struct peer)); @@ -735,10 +766,14 @@ peer_free (struct peer *peer) /* increase reference count on a struct peer */ struct peer * -peer_lock (struct peer *peer) +peer_lock_with_caller (const char *name, struct peer *peer) { assert (peer && (peer->lock >= 0)); - + +#if 0 + zlog_debug("%s peer_lock %p %d", name, peer, peer->lock); +#endif + peer->lock++; return peer; @@ -748,30 +783,22 @@ peer_lock (struct peer *peer) * struct peer is freed and NULL returned if last reference */ struct peer * -peer_unlock (struct peer *peer) +peer_unlock_with_caller (const char *name, struct peer *peer) { assert (peer && (peer->lock > 0)); - + +#if 0 + zlog_debug("%s peer_unlock %p %d", name, peer, peer->lock); +#endif + peer->lock--; if (peer->lock == 0) { -#if 0 - zlog_debug ("unlocked and freeing"); - zlog_backtrace (LOG_DEBUG); -#endif peer_free (peer); return NULL; } -#if 0 - if (peer->lock == 1) - { - zlog_debug ("unlocked to 1"); - zlog_backtrace (LOG_DEBUG); - } -#endif - return peer; } @@ -796,7 +823,6 @@ peer_new (struct bgp *bgp) peer->fd = -1; peer->v_start = BGP_INIT_START_TIMER; peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; - peer->v_asorig = BGP_DEFAULT_ASORIGINATE; peer->status = Idle; peer->ostatus = Idle; peer->weight = 0; @@ -822,6 +848,7 @@ peer_new (struct bgp *bgp) peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE); peer->obuf = stream_fifo_new (); peer->work = stream_new (BGP_MAX_PACKET_SIZE); + peer->scratch = stream_new (BGP_MAX_PACKET_SIZE); bgp_sync_init (peer); @@ -865,7 +892,7 @@ peer_create (union sockunion *su, struct bgp *bgp, as_ peer->readtime = peer->resettime = bgp_clock (); /* Default TTL set. */ - peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1); + peer->ttl = (peer->sort == BGP_PEER_IBGP) ? 255 : 1; /* Make peer's address string. */ sockunion2str (su, buf, SU_ADDRSTRLEN); @@ -896,12 +923,13 @@ peer_create_accept (struct bgp *bgp) static void peer_as_change (struct peer *peer, as_t as) { - int type; + bgp_peer_sort_t type; + struct peer *conf; /* Stop peer. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -921,10 +949,17 @@ peer_as_change (struct peer *peer, as_t as) peer->local_as = peer->bgp->as; /* Advertisement-interval reset */ - if (peer_sort (peer) == BGP_PEER_IBGP) - peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + conf = NULL; + if (peer->group) + conf = peer->group->conf; + + if (conf && CHECK_FLAG (conf->config, PEER_CONFIG_ROUTEADV)) + peer->v_routeadv = conf->routeadv; else - peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + if (peer_sort (peer) == BGP_PEER_IBGP) + peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* TTL reset */ if (peer_sort (peer) == BGP_PEER_IBGP) @@ -941,10 +976,16 @@ peer_as_change (struct peer *peer, as_t as) PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_ENCAP], + PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MPLS_VPN], + PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP], + PEER_FLAG_REFLECTOR_CLIENT); } /* local-as reset */ @@ -952,6 +993,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); } } @@ -1016,9 +1058,9 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4) && afi == AFI_IP && safi == SAFI_UNICAST) - peer = peer_create (su, bgp, local_as, *as, 0, 0); + peer_create (su, bgp, local_as, *as, 0, 0); else - peer = peer_create (su, bgp, local_as, *as, afi, safi); + peer_create (su, bgp, local_as, *as, afi, safi); } return 0; @@ -1147,7 +1189,7 @@ peer_nsf_stop (struct peer *peer) UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) - for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) + for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) peer->nsf[afi][safi] = 0; if (peer->t_gr_restart) @@ -1256,20 +1298,41 @@ peer_delete (struct peer *peer) /* Buffers. */ if (peer->ibuf) - stream_free (peer->ibuf); + { + stream_free (peer->ibuf); + peer->ibuf = NULL; + } + if (peer->obuf) - stream_fifo_free (peer->obuf); + { + stream_fifo_free (peer->obuf); + peer->obuf = NULL; + } + if (peer->work) - stream_free (peer->work); - peer->obuf = NULL; - peer->work = peer->ibuf = NULL; + { + stream_free (peer->work); + peer->work = NULL; + } + if (peer->scratch) + { + stream_free(peer->scratch); + peer->scratch = NULL; + } + /* Local and remote addresses. */ if (peer->su_local) - sockunion_free (peer->su_local); + { + sockunion_free (peer->su_local); + peer->su_local = NULL; + } + if (peer->su_remote) - sockunion_free (peer->su_remote); - peer->su_local = peer->su_remote = NULL; + { + sockunion_free (peer->su_remote); + peer->su_remote = NULL; + } /* Free filter related memory. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) @@ -1280,38 +1343,54 @@ peer_delete (struct peer *peer) for (i = FILTER_IN; i < FILTER_MAX; i++) { if (filter->dlist[i].name) - free (filter->dlist[i].name); + { + free(filter->dlist[i].name); + filter->dlist[i].name = NULL; + } + if (filter->plist[i].name) - free (filter->plist[i].name); + { + free(filter->plist[i].name); + filter->plist[i].name = NULL; + } + if (filter->aslist[i].name) - free (filter->aslist[i].name); - - filter->dlist[i].name = NULL; - filter->plist[i].name = NULL; - filter->aslist[i].name = NULL; + { + free(filter->aslist[i].name); + filter->aslist[i].name = NULL; + } } + for (i = RMAP_IN; i < RMAP_MAX; i++) { if (filter->map[i].name) - free (filter->map[i].name); - filter->map[i].name = NULL; + { + free (filter->map[i].name); + filter->map[i].name = NULL; + } } if (filter->usmap.name) - free (filter->usmap.name); + { + free (filter->usmap.name); + filter->usmap.name = NULL; + } if (peer->default_rmap[afi][safi].name) - free (peer->default_rmap[afi][safi].name); - - filter->usmap.name = NULL; - peer->default_rmap[afi][safi].name = NULL; + { + free (peer->default_rmap[afi][safi].name); + peer->default_rmap[afi][safi].name = NULL; + } } + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETING)) + bgp_peer_clear_node_queue_drain_immediate(peer); + peer_unlock (peer); /* initial reference */ return 0; } - + static int peer_group_cmp (struct peer_group *g1, struct peer_group *g2) { @@ -1325,8 +1404,11 @@ peer_group_active (struct peer *peer) if (peer->af_group[AFI_IP][SAFI_UNICAST] || peer->af_group[AFI_IP][SAFI_MULTICAST] || peer->af_group[AFI_IP][SAFI_MPLS_VPN] + || peer->af_group[AFI_IP][SAFI_ENCAP] || peer->af_group[AFI_IP6][SAFI_UNICAST] - || peer->af_group[AFI_IP6][SAFI_MULTICAST]) + || peer->af_group[AFI_IP6][SAFI_MULTICAST] + || peer->af_group[AFI_IP6][SAFI_MPLS_VPN] + || peer->af_group[AFI_IP6][SAFI_ENCAP]) return 1; return 0; } @@ -1440,19 +1522,17 @@ peer_group2peer_config_copy (struct peer_group *group, peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; /* advertisement-interval reset */ - if (peer_sort (peer) == BGP_PEER_IBGP) - peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + if (CHECK_FLAG (conf->config, PEER_CONFIG_ROUTEADV)) + peer->v_routeadv = conf->routeadv; else - peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + if (peer_sort (peer) == BGP_PEER_IBGP) + peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* password apply */ - if (peer->password) - XFREE (MTYPE_PEER_PASSWORD, peer->password); - - if (conf->password) + if (conf->password && !peer->password) peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, conf->password); - else - peer->password = NULL; bgp_md5_set (peer); @@ -1691,7 +1771,6 @@ peer_group_delete (struct peer_group *group) for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - peer->group = NULL; peer_delete (peer); } list_delete (group->peer); @@ -1721,7 +1800,6 @@ peer_group_remote_as_delete (struct peer_group *group) for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - peer->group = NULL; peer_delete (peer); } list_delete_all_node (group->peer); @@ -1806,10 +1884,13 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, if (first_member) { /* Advertisement-interval reset */ - if (peer_sort (group->conf) == BGP_PEER_IBGP) - group->conf->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; - else - group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + if (! CHECK_FLAG (group->conf->config, PEER_CONFIG_ROUTEADV)) + { + if (peer_sort (group->conf) == BGP_PEER_IBGP) + group->conf->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + } /* ebgp-multihop reset */ if (peer_sort (group->conf) == BGP_PEER_IBGP) @@ -1820,6 +1901,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); } } @@ -1862,7 +1944,7 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, peer_group2peer_config_copy (group, peer, afi, safi); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_RMAP_BIND; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -1905,7 +1987,7 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer, peer_global_config_reset (peer); } - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_RMAP_UNBIND; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -1916,7 +1998,19 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer, return 0; } - + + +static int +bgp_startup_timer_expire (struct thread *thread) +{ + struct bgp *bgp; + + bgp = THREAD_ARG (thread); + bgp->t_startup = NULL; + + return 0; +} + /* BGP instance creation by `router bgp' commands. */ static struct bgp * bgp_create (as_t *as, const char *name) @@ -1947,6 +2041,8 @@ bgp_create (as_t *as, const char *name) bgp->route[afi][safi] = bgp_table_init (afi, safi); bgp->aggregate[afi][safi] = bgp_table_init (afi, safi); bgp->rib[afi][safi] = bgp_table_init (afi, safi); + bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS; + bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS; } bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; @@ -1954,12 +2050,16 @@ bgp_create (as_t *as, const char *name) bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; bgp->restart_time = BGP_DEFAULT_RESTART_TIME; bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + bgp_flag_set (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); bgp->as = *as; if (name) bgp->name = strdup (name); + THREAD_TIMER_ON (bm->master, bgp->t_startup, bgp_startup_timer_expire, + bgp, bgp->restart_time); + return bgp; } @@ -1967,7 +2067,7 @@ bgp_create (as_t *as, const char *name) struct bgp * bgp_get_default (void) { - if (bm->bgp->head) + if (bm && bm->bgp && bm->bgp->head) return (listgetdata (listhead (bm->bgp))); return NULL; } @@ -2048,17 +2148,19 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *n } } + bgp = bgp_create (as, name); + bgp_router_id_set(bgp, &router_id_zebra); + *bgp_val = bgp; + /* Create BGP server socket, if first instance. */ - if (list_isempty(bm->bgp)) + if (list_isempty(bm->bgp) + && !bgp_option_check (BGP_OPT_NO_LISTEN)) { if (bgp_socket (bm->port, bm->address) < 0) return BGP_ERR_INVALID_VALUE; } - bgp = bgp_create (as, name); listnode_add (bm->bgp, bgp); - bgp_router_id_set(bgp, &router_id_zebra); - *bgp_val = bgp; return 0; } @@ -2069,11 +2171,15 @@ bgp_delete (struct bgp *bgp) { struct peer *peer; struct peer_group *group; - struct listnode *node; - struct listnode *next; + struct listnode *node, *pnode; + struct listnode *next, *pnext; afi_t afi; int i; + SET_FLAG(bgp->flags, BGP_FLAG_DELETING); + + THREAD_OFF (bgp->t_startup); + /* Delete static route. */ bgp_static_delete (bgp); @@ -2084,10 +2190,28 @@ bgp_delete (struct bgp *bgp) bgp_redistribute_unset (bgp, afi, i); for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer)) - peer_delete (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)) - peer_group_delete (group); + { + for (ALL_LIST_ELEMENTS (group->peer, pnode, pnext, 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_group_delete (group); + } assert (listcount (bgp->rsclient) == 0); @@ -2095,7 +2219,16 @@ bgp_delete (struct bgp *bgp) peer_delete(bgp->peer_self); bgp->peer_self = NULL; } - + + /* + * Free pending deleted routes. Unfortunately, it also has to process + * all the pending activity for other instances of struct bgp. + * + * This call was added to achieve clean memory allocation at exit, + * for the sake of valgrind. + */ + bgp_process_queues_drain_immediate(); + /* Remove visibility via the master list - there may however still be * routes to be processed still referencing the struct bgp. */ @@ -2149,7 +2282,7 @@ bgp_free (struct bgp *bgp) } XFREE (MTYPE_BGP, bgp); } - + struct peer * peer_lookup (struct bgp *bgp, union sockunion *su) { @@ -2218,7 +2351,7 @@ peer_lookup_with_open (union sockunion *su, as_t remot } return NULL; } - + /* If peer is configured at least one address family return 1. */ int peer_active (struct peer *peer) @@ -2226,8 +2359,11 @@ peer_active (struct peer *peer) if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] + || peer->afc[AFI_IP][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_UNICAST] - || peer->afc[AFI_IP6][SAFI_MULTICAST]) + || peer->afc[AFI_IP6][SAFI_MULTICAST] + || peer->afc[AFI_IP6][SAFI_MPLS_VPN] + || peer->afc[AFI_IP6][SAFI_ENCAP]) return 1; return 0; } @@ -2239,12 +2375,15 @@ peer_active_nego (struct peer *peer) if (peer->afc_nego[AFI_IP][SAFI_UNICAST] || peer->afc_nego[AFI_IP][SAFI_MULTICAST] || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] + || peer->afc_nego[AFI_IP][SAFI_ENCAP] || peer->afc_nego[AFI_IP6][SAFI_UNICAST] - || peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) + || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] + || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] + || peer->afc_nego[AFI_IP6][SAFI_ENCAP]) return 1; return 0; } - + /* peer_flag_change_type. */ enum peer_change_type { @@ -2261,6 +2400,9 @@ peer_change_action (struct peer *peer, afi_t afi, safi if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return; + if (peer->status != Established) + return; + if (type == peer_change_reset) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); @@ -2320,6 +2462,7 @@ static const struct peer_flag_action peer_af_flag_acti { 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 }, { 0, 0, 0 } }; @@ -2395,7 +2538,7 @@ peer_flag_modify_action (struct peer *peer, u_int32_t if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) peer_nsf_stop (peer); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); else @@ -2407,7 +2550,7 @@ peer_flag_modify_action (struct peer *peer, u_int32_t BGP_EVENT_ADD (peer, BGP_Stop); } } - else if (peer->status == Established) + else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; @@ -2660,7 +2803,7 @@ peer_af_flag_unset (struct peer *peer, afi_t afi, safi { return peer_af_flag_modify (peer, afi, safi, flag, 0); } - + /* EBGP multihop configuration. */ int peer_ebgp_multihop_set (struct peer *peer, int ttl) @@ -2669,7 +2812,7 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) struct listnode *node, *nnode; struct peer *peer1; - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) return 0; /* see comment in peer_ttl_security_hops_set() */ @@ -2683,7 +2826,7 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { - if (peer_sort (peer1) == BGP_PEER_IBGP) + if (peer1->sort == BGP_PEER_IBGP) continue; if (peer1->gtsm_hops != 0) @@ -2701,7 +2844,7 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } else @@ -2709,7 +2852,7 @@ peer_ebgp_multihop_set (struct peer *peer, int ttl) group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) continue; peer->ttl = group->conf->ttl; @@ -2727,7 +2870,7 @@ peer_ebgp_multihop_unset (struct peer *peer) struct peer_group *group; struct listnode *node, *nnode; - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) return 0; if (peer->gtsm_hops != 0 && peer->ttl != MAXTTL) @@ -2740,7 +2883,7 @@ peer_ebgp_multihop_unset (struct peer *peer) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } else @@ -2748,7 +2891,7 @@ peer_ebgp_multihop_unset (struct peer *peer) group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) continue; peer->ttl = 1; @@ -2759,7 +2902,7 @@ peer_ebgp_multihop_unset (struct peer *peer) } return 0; } - + /* Neighbor description. */ int peer_description_set (struct peer *peer, char *desc) @@ -2782,7 +2925,7 @@ peer_description_unset (struct peer *peer) return 0; } - + /* Neighbor update-source. */ int peer_update_source_if_set (struct peer *peer, const char *ifname) @@ -2810,7 +2953,7 @@ peer_update_source_if_set (struct peer *peer, const ch if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -2842,7 +2985,7 @@ peer_update_source_if_set (struct peer *peer, const ch peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -2879,7 +3022,7 @@ peer_update_source_addr_set (struct peer *peer, union if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -2910,7 +3053,7 @@ peer_update_source_addr_set (struct peer *peer, union peer->update_source = sockunion_dup (su); - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -2961,7 +3104,7 @@ peer_update_source_unset (struct peer *peer) if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -2991,7 +3134,7 @@ peer_update_source_unset (struct peer *peer) peer->update_if = NULL; } - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -3002,7 +3145,7 @@ peer_update_source_unset (struct peer *peer) } return 0; } - + int peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi, const char *rmap) @@ -3107,7 +3250,7 @@ peer_default_originate_unset (struct peer *peer, afi_t } return 0; } - + int peer_port_set (struct peer *peer, u_int16_t port) { @@ -3121,7 +3264,7 @@ peer_port_unset (struct peer *peer) peer->port = BGP_PORT_DEFAULT; return 0; } - + /* neighbor weight. */ int peer_weight_set (struct peer *peer, u_int16_t weight) @@ -3169,7 +3312,7 @@ peer_weight_unset (struct peer *peer) } return 0; } - + int peer_timers_set (struct peer *peer, u_int32_t keepalive, u_int32_t holdtime) { @@ -3239,10 +3382,13 @@ peer_timers_unset (struct peer *peer) return 0; } - + int peer_timers_connect_set (struct peer *peer, u_int32_t connect) { + struct peer_group *group; + struct listnode *node, *nnode; + if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; @@ -3256,12 +3402,26 @@ peer_timers_connect_set (struct peer *peer, u_int32_t /* Set value to timer setting. */ peer->v_connect = connect; + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + /* peer-group member updates. */ + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + SET_FLAG (peer->config, PEER_CONFIG_CONNECT); + peer->connect = connect; + peer->v_connect = connect; + } return 0; } int peer_timers_connect_unset (struct peer *peer) { + struct peer_group *group; + struct listnode *node, *nnode; + if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; @@ -3272,12 +3432,26 @@ peer_timers_connect_unset (struct peer *peer) /* Set timer setting to default value. */ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; - return 0; + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + /* peer-group member updates. */ + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + UNSET_FLAG (peer->config, PEER_CONFIG_CONNECT); + peer->connect = 0; + peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; + } + return 0; } - + int peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv) { + struct peer_group *group; + struct listnode *node, *nnode; + if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; @@ -3288,26 +3462,57 @@ peer_advertise_interval_set (struct peer *peer, u_int3 peer->routeadv = routeadv; peer->v_routeadv = routeadv; + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + /* peer-group member updates. */ + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + SET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); + peer->routeadv = routeadv; + peer->v_routeadv = routeadv; + } + return 0; } int peer_advertise_interval_unset (struct peer *peer) { + struct peer_group *group; + struct listnode *node, *nnode; + if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); peer->routeadv = 0; - if (peer_sort (peer) == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + + if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + return 0; + + /* peer-group member updates. */ + group = peer->group; + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) + { + UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); + peer->routeadv = 0; + + if (peer->sort == BGP_PEER_IBGP) + peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; + else + peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; + } return 0; } - + /* neighbor interface */ int peer_interface_set (struct peer *peer, const char *str) @@ -3328,7 +3533,7 @@ peer_interface_unset (struct peer *peer) return 0; } - + /* Allow-as in. */ int peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num) @@ -3389,9 +3594,9 @@ peer_allowas_in_unset (struct peer *peer, afi_t afi, s } return 0; } - + 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; @@ -3407,9 +3612,14 @@ peer_local_as_set (struct peer *peer, as_t as, int no_ 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; @@ -3418,9 +3628,14 @@ peer_local_as_set (struct peer *peer, as_t as, int no_ 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) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -3441,7 +3656,12 @@ peer_local_as_set (struct peer *peer, as_t as, int no_ else UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); - if (peer->status == Established) + 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 (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -3468,10 +3688,11 @@ 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)) { - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -3488,8 +3709,9 @@ 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) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, @@ -3500,7 +3722,7 @@ peer_local_as_unset (struct peer *peer) } return 0; } - + /* Set password for authenticating with the peer. */ int peer_password_set (struct peer *peer, const char *password) @@ -3523,8 +3745,8 @@ peer_password_set (struct peer *peer, const char *pass if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->status == Established) - bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); + 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); @@ -3541,7 +3763,7 @@ peer_password_set (struct peer *peer, const char *pass peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password); - if (peer->status == Established) + 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); @@ -3569,7 +3791,7 @@ peer_password_unset (struct peer *peer) && strcmp (peer->group->conf->password, peer->password) == 0) return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; - if (peer->status == Established) + 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); @@ -3592,7 +3814,7 @@ peer_password_unset (struct peer *peer) if (!peer->password) continue; - if (peer->status == Established) + 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); @@ -3605,7 +3827,7 @@ peer_password_unset (struct peer *peer) return 0; } - + /* Set distribute list to the peer. */ int peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct, @@ -3765,7 +3987,7 @@ peer_distribute_update (struct access_list *access) } } } - + /* Set prefix list to the peer. */ int peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct, @@ -3924,7 +4146,7 @@ peer_prefix_list_update (struct prefix_list *plist) } } } - + int peer_aslist_set (struct peer *peer, afi_t afi, safi_t safi, int direct, const char *name) @@ -4078,7 +4300,7 @@ peer_aslist_update (void) } } } - + /* Set route-map to the peer. */ int peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct, @@ -4186,7 +4408,7 @@ peer_route_map_unset (struct peer *peer, afi_t afi, sa } return 0; } - + /* Set unsuppress-map to the peer. */ int peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi, @@ -4268,7 +4490,7 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t af } return 0; } - + int peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi, u_int32_t max, u_char threshold, @@ -4363,21 +4585,46 @@ peer_maximum_prefix_unset (struct peer *peer, afi_t af } return 0; } - + +static int is_ebgp_multihop_configured (struct peer *peer) +{ + struct peer_group *group; + struct listnode *node, *nnode; + struct peer *peer1; + + if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) + { + group = peer->group; + if ((peer_sort(peer) != BGP_PEER_IBGP) && + (group->conf->ttl != 1)) + return 1; + + for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) + { + if ((peer_sort (peer1) != BGP_PEER_IBGP) && + (peer1->ttl != 1)) + return 1; + } + } + else + { + if ((peer_sort(peer) != BGP_PEER_IBGP) && + (peer->ttl != 1)) + return 1; + } + return 0; +} + /* Set # of hops between us and BGP peer. */ int peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) { struct peer_group *group; struct listnode *node, *nnode; - struct peer *peer1; int ret; zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host); - if (peer_sort (peer) == BGP_PEER_IBGP) - return BGP_ERR_NO_IBGP_WITH_TTLHACK; - /* We cannot configure ttl-security hops when ebgp-multihop is already set. For non peer-groups, the check is simple. For peer-groups, it's slightly messy, because we need to check both the peer-group structure @@ -4386,38 +4633,23 @@ peer_ttl_security_hops_set (struct peer *peer, int gts mess of this configuration parameter, and OpenBGPD got it right. */ - if (peer->gtsm_hops == 0) { - if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) - { - group = peer->group; - if (group->conf->ttl != 1) - return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; + if (peer->gtsm_hops == 0) + { + if (is_ebgp_multihop_configured (peer)) + return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) - { - if (peer_sort (peer1) == BGP_PEER_IBGP) - continue; - - if (peer1->ttl != 1) - return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - } - } - else - { - if (peer->ttl != 1) - return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; - } - /* specify MAXTTL on outgoing packets */ - ret = peer_ebgp_multihop_set (peer, MAXTTL); - if (ret != 0) - return ret; - } + /* specify MAXTTL on outgoing packets */ + /* Routine handles iBGP peers correctly */ + ret = peer_ebgp_multihop_set (peer, MAXTTL); + if (ret != 0) + return ret; + } peer->gtsm_hops = gtsm_hops; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + if (peer->fd >= 0) sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - gtsm_hops); } else @@ -4425,9 +4657,6 @@ peer_ttl_security_hops_set (struct peer *peer, int gts group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - if (peer_sort (peer) == BGP_PEER_IBGP) - continue; - peer->gtsm_hops = group->conf->gtsm_hops; /* Change setting of existing peer @@ -4462,9 +4691,6 @@ peer_ttl_security_hops_unset (struct peer *peer) zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer->host); - if (peer_sort (peer) == BGP_PEER_IBGP) - return 0; - /* if a peer-group member, then reset to peer-group default rather than 0 */ if (peer_group_active (peer)) peer->gtsm_hops = peer->group->conf->gtsm_hops; @@ -4474,7 +4700,7 @@ peer_ttl_security_hops_unset (struct peer *peer) opeer = peer; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { - if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP) + if (peer->fd >= 0) sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0); } else @@ -4482,9 +4708,6 @@ peer_ttl_security_hops_unset (struct peer *peer) group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { - if (peer_sort (peer) == BGP_PEER_IBGP) - continue; - peer->gtsm_hops = 0; if (peer->fd >= 0) @@ -4494,7 +4717,7 @@ peer_ttl_security_hops_unset (struct peer *peer) return peer_ebgp_multihop_unset (opeer); } - + int peer_clear (struct peer *peer) { @@ -4515,7 +4738,7 @@ peer_clear (struct peer *peer) } peer->v_start = BGP_INIT_START_TIMER; - if (peer->status == Established) + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_RESET); else @@ -4534,6 +4757,8 @@ peer_clear_soft (struct peer *peer, afi_t afi, safi_t if (! peer->afc[afi][safi]) return BGP_ERR_AF_UNCONFIGURED; + peer->rtt = sockopt_tcp_rtt (peer->fd); + if (stype == BGP_CLEAR_SOFT_RSCLIENT) { if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) @@ -4599,7 +4824,7 @@ peer_clear_soft (struct peer *peer, afi_t afi, safi_t } return 0; } - + /* Display peer uptime.*/ /* XXX: why does this function return char * when it takes buffer? */ char * @@ -4628,10 +4853,11 @@ peer_uptime (time_t uptime2, char *buf, size_t len) uptime1 = bgp_clock (); uptime1 -= uptime2; tm = gmtime (&uptime1); - + /* Making formatted timer strings. */ #define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 +#define ONE_WEEK_SECOND ONE_DAY_SECOND*7 +#define ONE_YEAR_SECOND ONE_DAY_SECOND*365 if (uptime1 < ONE_DAY_SECOND) snprintf (buf, len, "%02d:%02d:%02d", @@ -4639,12 +4865,16 @@ peer_uptime (time_t uptime2, char *buf, size_t len) else if (uptime1 < ONE_WEEK_SECOND) snprintf (buf, len, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); - else + else if (uptime1 < ONE_YEAR_SECOND) snprintf (buf, len, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + else + snprintf (buf, len, "%02dy%02dw%dd", + tm->tm_year - 70, tm->tm_yday/7, + tm->tm_yday - ((tm->tm_yday/7) * 7)); return buf; } - + static void bgp_config_write_filter (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi) @@ -4720,12 +4950,10 @@ static void bgp_config_write_peer (struct vty *vty, struct bgp *bgp, struct peer *peer, afi_t afi, safi_t safi) { - struct bgp_filter *filter; struct peer *g_peer = NULL; char buf[SU_ADDRSTRLEN]; char *addr; - filter = &peer->filter[afi][safi]; addr = peer->host; if (peer_group_active (peer)) g_peer = peer->group->conf; @@ -4758,10 +4986,12 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bg /* 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) @@ -4799,7 +5029,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bg vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE); /* EBGP multihop. */ - if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1 && + if (peer->sort != BGP_PEER_IBGP && peer->ttl != 1 && !(peer->gtsm_hops != 0 && peer->ttl == MAXTTL)) if (! peer_group_active (peer) || g_peer->ttl != peer->ttl) @@ -4807,7 +5037,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bg VTY_NEWLINE); /* ttl-security hops */ - if (peer_sort (peer) != BGP_PEER_IBGP && peer->gtsm_hops != 0) + if (peer->gtsm_hops != 0) if (! peer_group_active (peer) || g_peer->gtsm_hops != peer->gtsm_hops) vty_out (vty, " neighbor %s ttl-security hops %d%s", addr, peer->gtsm_hops, VTY_NEWLINE); @@ -4833,7 +5063,8 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bg VTY_NEWLINE); /* advertisement-interval */ - if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV)) + if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV) && + ! peer_group_active (peer)) vty_out (vty, " neighbor %s advertisement-interval %d%s", addr, peer->v_routeadv, VTY_NEWLINE); @@ -4843,7 +5074,8 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bg vty_out (vty, " neighbor %s timers %d %d%s", addr, peer->keepalive, peer->holdtime, VTY_NEWLINE); - if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT)) + if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT) && + ! peer_group_active (peer)) vty_out (vty, " neighbor %s timers connect %d%s", addr, peer->connect, VTY_NEWLINE); @@ -4882,7 +5114,7 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bg vty_out (vty, " neighbor %s strict-capability-match%s", addr, VTY_NEWLINE); - if (! peer_group_active (peer)) + if (! peer->af_group[AFI_IP][SAFI_UNICAST]) { if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) { @@ -4937,7 +5169,9 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bg /* Nexthop self. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF) && ! peer->af_group[afi][safi]) - vty_out (vty, " neighbor %s next-hop-self%s", addr, VTY_NEWLINE); + vty_out (vty, " neighbor %s next-hop-self%s%s", addr, + 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) @@ -5014,6 +5248,11 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bg && ! peer->af_group[afi][safi]) vty_out (vty, " neighbor %s route-server-client%s", addr, VTY_NEWLINE); + /* Nexthop-local unchanged. */ + if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) + && ! peer->af_group[afi][safi]) + vty_out (vty, " neighbor %s nexthop-local unchanged%s", addr, VTY_NEWLINE); + /* Allow AS in. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) if (! peer_group_active (peer) @@ -5069,14 +5308,22 @@ bgp_config_write_family_header (struct vty *vty, afi_t if (safi == SAFI_MULTICAST) vty_out (vty, "ipv4 multicast"); else if (safi == SAFI_MPLS_VPN) - vty_out (vty, "vpnv4 unicast"); + vty_out (vty, "vpnv4"); + else if (safi == SAFI_ENCAP) + vty_out (vty, "encap"); } else if (afi == AFI_IP6) { - vty_out (vty, "ipv6"); - - if (safi == SAFI_MULTICAST) - vty_out (vty, " multicast"); + if (safi == SAFI_MPLS_VPN) + vty_out (vty, "vpnv6"); + else if (safi == SAFI_ENCAP) + vty_out (vty, "encapv6"); + else + { + vty_out (vty, "ipv6"); + if (safi == SAFI_MULTICAST) + vty_out (vty, " multicast"); + } } vty_out (vty, "%s", VTY_NEWLINE); @@ -5117,6 +5364,9 @@ bgp_config_write_family (struct vty *vty, struct bgp * } } } + + bgp_config_write_maxpaths (vty, bgp, afi, safi, &write); + if (write) vty_out (vty, " exit-address-family%s", VTY_NEWLINE); @@ -5177,8 +5427,8 @@ bgp_config_write (struct vty *vty) VTY_NEWLINE); /* BGP log-neighbor-changes. */ - if (bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) - vty_out (vty, " bgp log-neighbor-changes%s", VTY_NEWLINE); + if (!bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) + vty_out (vty, " no bgp log-neighbor-changes%s", VTY_NEWLINE); /* BGP configuration. */ if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED)) @@ -5240,6 +5490,9 @@ bgp_config_write (struct vty *vty) vty_out (vty, " bgp bestpath as-path ignore%s", VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_CONFED)) vty_out (vty, " bgp bestpath as-path confed%s", VTY_NEWLINE); + 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_COMPARE_ROUTER_ID)) vty_out (vty, " bgp bestpath compare-routerid%s", VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED) @@ -5290,6 +5543,9 @@ bgp_config_write (struct vty *vty) bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST); } + /* maximum-paths */ + bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write); + /* Distance configuration. */ bgp_config_write_distance (vty, bgp); @@ -5303,12 +5559,23 @@ bgp_config_write (struct vty *vty) /* IPv4 VPN configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MPLS_VPN); + /* ENCAPv4 configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_ENCAP); + /* IPv6 unicast configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_UNICAST); /* IPv6 multicast configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MULTICAST); + /* IPv6 VPN configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MPLS_VPN); + + /* ENCAPv6 configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_ENCAP); + + vty_out (vty, " exit%s", VTY_NEWLINE); + write++; } return write; @@ -5327,7 +5594,7 @@ bgp_master_init (void) bm->start_time = bgp_clock (); } - + void bgp_init (void) { @@ -5335,7 +5602,7 @@ bgp_init (void) bgp_vty_init (); /* Init zebra. */ - bgp_zebra_init (); + bgp_zebra_init (bm->master); /* BGP inits. */ bgp_attr_init (); @@ -5343,8 +5610,10 @@ bgp_init (void) bgp_dump_init (); bgp_route_init (); bgp_route_map_init (); + bgp_address_init (); bgp_scan_init (); bgp_mplsvpn_init (); + bgp_encap_init (); /* Access list initialize. */ access_list_init ();