]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgpd.c
*: Convert `struct event_master` to `struct event_loop`
[mirror_frr.git] / bgpd / bgpd.c
index 284321c36a12df5b45e444c0bd54a8f73c3ce9a9..ae46efef2c13ea282e6141f7cc3a70bcceb6e122 100644 (file)
@@ -1,27 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /* BGP-4, BGP-4+ daemon program
  * Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * GNU Zebra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
 
 #include "prefix.h"
-#include "thread.h"
+#include "event.h"
 #include "buffer.h"
 #include "stream.h"
 #include "ringbuf.h"
@@ -92,7 +77,6 @@
 #include "bgpd/bgp_evpn_private.h"
 #include "bgpd/bgp_evpn_mh.h"
 #include "bgpd/bgp_mac.h"
-#include "bgpd/bgp_orr.h"
 #include "bgp_trace.h"
 
 DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
@@ -569,7 +553,7 @@ void bgp_tcp_keepalive_unset(struct bgp *bgp)
 }
 
 /* BGP confederation configuration.  */
-void bgp_confederation_id_set(struct bgp *bgp, as_t as)
+void bgp_confederation_id_set(struct bgp *bgp, as_t as, const char *as_str)
 {
        struct peer *peer;
        struct listnode *node, *nnode;
@@ -581,6 +565,9 @@ void bgp_confederation_id_set(struct bgp *bgp, as_t as)
        /* Remember - were we doing confederation before? */
        already_confed = bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION);
        bgp->confed_id = as;
+       if (bgp->confed_id_pretty)
+               XFREE(MTYPE_BGP, bgp->confed_id_pretty);
+       bgp->confed_id_pretty = XSTRDUP(MTYPE_BGP, as_str);
        bgp_config_set(bgp, BGP_CONFIG_CONFEDERATION);
 
        /* If we were doing confederation already, this is just an external
@@ -633,6 +620,7 @@ void bgp_confederation_id_unset(struct bgp *bgp)
        struct listnode *node, *nnode;
 
        bgp->confed_id = 0;
+       XFREE(MTYPE_BGP, bgp->confed_id_pretty);
        bgp_config_unset(bgp, BGP_CONFIG_CONFEDERATION);
 
        for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
@@ -660,14 +648,14 @@ bool bgp_confederation_peers_check(struct bgp *bgp, as_t as)
                return false;
 
        for (i = 0; i < bgp->confed_peers_cnt; i++)
-               if (bgp->confed_peers[i] == as)
+               if (bgp->confed_peers[i].as == as)
                        return true;
 
        return false;
 }
 
 /* Add an AS to the confederation set.  */
-void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
+void bgp_confederation_peers_add(struct bgp *bgp, as_t as, const char *as_str)
 {
        struct peer *peer;
        struct listnode *node, *nnode;
@@ -678,11 +666,13 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
        if (bgp_confederation_peers_check(bgp, as))
                return;
 
-       bgp->confed_peers =
-               XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
-                        (bgp->confed_peers_cnt + 1) * sizeof(as_t));
+       bgp->confed_peers = XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
+                                    (bgp->confed_peers_cnt + 1) *
+                                            sizeof(struct as_confed));
 
-       bgp->confed_peers[bgp->confed_peers_cnt] = as;
+       bgp->confed_peers[bgp->confed_peers_cnt].as = as;
+       bgp->confed_peers[bgp->confed_peers_cnt].as_pretty =
+               XSTRDUP(MTYPE_BGP, as_str);
        bgp->confed_peers_cnt++;
 
        if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) {
@@ -719,9 +709,15 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
                return;
 
        for (i = 0; i < bgp->confed_peers_cnt; i++)
-               if (bgp->confed_peers[i] == as)
-                       for (j = i + 1; j < bgp->confed_peers_cnt; j++)
-                               bgp->confed_peers[j - 1] = bgp->confed_peers[j];
+               if (bgp->confed_peers[i].as == as) {
+                       XFREE(MTYPE_BGP, bgp->confed_peers[i].as_pretty);
+                       for (j = i + 1; j < bgp->confed_peers_cnt; j++) {
+                               bgp->confed_peers[j - 1].as =
+                                       bgp->confed_peers[j].as;
+                               bgp->confed_peers[j - 1].as_pretty =
+                                       bgp->confed_peers[j].as_pretty;
+                       }
+               }
 
        bgp->confed_peers_cnt--;
 
@@ -730,9 +726,9 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
                        XFREE(MTYPE_BGP_CONFED_LIST, bgp->confed_peers);
                bgp->confed_peers = NULL;
        } else
-               bgp->confed_peers =
-                       XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
-                                bgp->confed_peers_cnt * sizeof(as_t));
+               bgp->confed_peers = XREALLOC(
+                       MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
+                       bgp->confed_peers_cnt * sizeof(struct as_confed));
 
        /* Now reset any peer who's remote AS has just been removed from the
           CONFED */
@@ -981,9 +977,10 @@ void peer_flag_inherit(struct peer *peer, uint64_t flag)
                COND_FLAG(peer->flags, flag, group_val);
 }
 
-int peer_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint32_t flag)
+bool peer_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
+                       uint64_t flag)
 {
-       return CHECK_FLAG(peer->af_flags[afi][safi], flag);
+       return !!CHECK_FLAG(peer->af_flags[afi][safi], flag);
 }
 
 void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi,
@@ -1129,9 +1126,9 @@ static void peer_free(struct peer *peer)
        bgp_timer_set(peer);
        bgp_reads_off(peer);
        bgp_writes_off(peer);
-       thread_cancel_event_ready(bm->master, peer);
+       event_cancel_event_ready(bm->master, peer);
        FOREACH_AFI_SAFI (afi, safi)
-               THREAD_OFF(peer->t_revalidate_all[afi][safi]);
+               EVENT_OFF(peer->t_revalidate_all[afi][safi]);
        assert(!peer->t_write);
        assert(!peer->t_read);
        BGP_EVENT_FLUSH(peer);
@@ -1157,6 +1154,7 @@ static void peer_free(struct peer *peer)
 
        XFREE(MTYPE_PEER_DESC, peer->desc);
        XFREE(MTYPE_BGP_PEER_HOST, peer->host);
+       XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
        XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
        XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
 
@@ -1178,6 +1176,8 @@ static void peer_free(struct peer *peer)
 
        XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
 
+       XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
+
        /* Remove BFD configuration. */
        if (peer->bfd_config)
                bgp_peer_remove_bfd_config(peer);
@@ -1185,6 +1185,11 @@ static void peer_free(struct peer *peer)
        FOREACH_AFI_SAFI (afi, safi)
                bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE);
 
+       if (peer->change_local_as_pretty)
+               XFREE(MTYPE_BGP, peer->change_local_as_pretty);
+       if (peer->as_pretty)
+               XFREE(MTYPE_BGP, peer->as_pretty);
+
        bgp_unlock(peer->bgp);
 
        memset(peer, 0, sizeof(struct peer));
@@ -1766,7 +1771,7 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp)
 struct peer *peer_create(union sockunion *su, const char *conf_if,
                         struct bgp *bgp, as_t local_as, as_t remote_as,
                         int as_type, struct peer_group *group,
-                        bool config_node)
+                        bool config_node, const char *as_str)
 {
        int active;
        struct peer *peer;
@@ -1791,6 +1796,9 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
        }
        peer->local_as = local_as;
        peer->as = remote_as;
+       /* internal and external values do not use as_pretty */
+       if (as_str && asn_str2asn(as_str, NULL))
+               peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str);
        peer->as_type = as_type;
        peer->local_id = bgp->router_id;
        peer->v_holdtime = bgp->default_holdtime;
@@ -1894,10 +1902,9 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
 }
 
 /* Change peer's AS number.  */
-void peer_as_change(struct peer *peer, as_t as, int as_specified)
+void peer_as_change(struct peer *peer, as_t as, int as_specified,
+                   const char *as_str)
 {
-       afi_t afi;
-       safi_t safi;
        enum bgp_peer_sort origtype, newtype;
 
        /* Stop peer. */
@@ -1911,6 +1918,12 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
        }
        origtype = peer_sort_lookup(peer);
        peer->as = as;
+       if (as_specified == AS_SPECIFIED && as_str) {
+               if (peer->as_pretty)
+                       XFREE(MTYPE_BGP, peer->as_pretty);
+               peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str);
+       } else if (peer->as_type == AS_UNSPECIFIED && peer->as_pretty)
+               XFREE(MTYPE_BGP, peer->as_pretty);
        peer->as_type = as_specified;
 
        if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION)
@@ -1936,11 +1949,6 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
 
        /* reflector-client reset */
        if (newtype != BGP_PEER_IBGP) {
-
-               FOREACH_AFI_SAFI (afi, safi)
-                       UNSET_FLAG(peer->af_flags[afi][safi],
-                                  PEER_FLAG_ORR_GROUP);
-
                UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_UNICAST],
                           PEER_FLAG_REFLECTOR_CLIENT);
                UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_MULTICAST],
@@ -1973,7 +1981,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
 /* 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, const char *conf_if,
-                  as_t *as, int as_type)
+                  as_t *as, int as_type, const char *as_str)
 {
        struct peer *peer;
        as_t local_as;
@@ -2027,22 +2035,22 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
                /* Existing peer's AS number change. */
                if (((peer->as_type == AS_SPECIFIED) && peer->as != *as)
                    || (peer->as_type != as_type))
-                       peer_as_change(peer, *as, as_type);
+                       peer_as_change(peer, *as, as_type, as_str);
        } 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 */
-               if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)
-                   && !bgp_confederation_peers_check(bgp, *as)
-                   && bgp->as != *as)
+               if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION) &&
+                   !bgp_confederation_peers_check(bgp, *as) && *as &&
+                   bgp->as != *as)
                        local_as = bgp->confed_id;
                else
                        local_as = bgp->as;
 
                peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL,
-                           true);
+                           true, as_str);
        }
 
        return 0;
@@ -2067,6 +2075,13 @@ const char *bgp_get_name_by_role(uint8_t role)
        return "unknown";
 }
 
+enum asnotation_mode bgp_get_asnotation(struct bgp *bgp)
+{
+       if (!bgp)
+               return ASNOTATION_PLAIN;
+       return bgp->asnotation;
+}
+
 static void peer_group2peer_config_copy_af(struct peer_group *group,
                                           struct peer *peer, afi_t afi,
                                           safi_t safi)
@@ -2452,16 +2467,16 @@ void peer_nsf_stop(struct peer *peer)
 
        FOREACH_AFI_SAFI_NSF (afi, safi) {
                peer->nsf[afi][safi] = 0;
-               THREAD_OFF(peer->t_llgr_stale[afi][safi]);
+               EVENT_OFF(peer->t_llgr_stale[afi][safi]);
        }
 
        if (peer->t_gr_restart) {
-               THREAD_OFF(peer->t_gr_restart);
+               EVENT_OFF(peer->t_gr_restart);
                if (bgp_debug_neighbor_events(peer))
                        zlog_debug("%pBP graceful restart timer stopped", peer);
        }
        if (peer->t_gr_stale) {
-               THREAD_OFF(peer->t_gr_stale);
+               EVENT_OFF(peer->t_gr_stale);
                if (bgp_debug_neighbor_events(peer))
                        zlog_debug(
                                "%pBP graceful restart stalepath timer stopped",
@@ -2501,9 +2516,9 @@ int peer_delete(struct peer *peer)
        bgp_keepalives_off(peer);
        bgp_reads_off(peer);
        bgp_writes_off(peer);
-       thread_cancel_event_ready(bm->master, peer);
+       event_cancel_event_ready(bm->master, peer);
        FOREACH_AFI_SAFI (afi, safi)
-               THREAD_OFF(peer->t_revalidate_all[afi][safi]);
+               EVENT_OFF(peer->t_revalidate_all[afi][safi]);
        assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON));
        assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON));
        assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON));
@@ -2638,6 +2653,7 @@ int peer_delete(struct peer *peer)
 
        XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
        XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
+       XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
 
        peer_unlock(peer); /* initial reference */
 
@@ -2710,7 +2726,7 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name)
 static void peer_group2peer_config_copy(struct peer_group *group,
                                        struct peer *peer)
 {
-       uint32_t flags_tmp;
+       uint64_t flags_tmp;
        struct peer *conf;
        bool config_node = !!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
 
@@ -2781,6 +2797,13 @@ static void peer_group2peer_config_copy(struct peer_group *group,
                if (CHECK_FLAG(conf->flags, PEER_FLAG_CAPABILITY_ENHE))
                        SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE);
 
+       /* capability software-version apply */
+       if (!CHECK_FLAG(peer->flags_override,
+                       PEER_FLAG_CAPABILITY_SOFT_VERSION))
+               if (CHECK_FLAG(conf->flags, PEER_FLAG_CAPABILITY_SOFT_VERSION))
+                       SET_FLAG(peer->flags,
+                                PEER_FLAG_CAPABILITY_SOFT_VERSION);
+
        /* password apply */
        if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_PASSWORD))
                PEER_STR_ATTR_INHERIT(peer, group, password,
@@ -2816,7 +2839,7 @@ static void peer_group2peer_config_copy(struct peer_group *group,
 
 /* Peer group's remote AS configuration.  */
 int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as,
-                        int as_type)
+                        int as_type, const char *as_str)
 {
        struct peer_group *group;
        struct peer *peer;
@@ -2832,12 +2855,12 @@ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as,
 
        /* When we setup peer-group AS number all peer group member's AS
           number must be updated to same number.  */
-       peer_as_change(group->conf, *as, as_type);
+       peer_as_change(group->conf, *as, as_type, as_str);
 
        for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
                if (((peer->as_type == AS_SPECIFIED) && peer->as != *as)
                    || (peer->as_type != as_type))
-                       peer_as_change(peer, *as, as_type);
+                       peer_as_change(peer, *as, as_type, as_str);
        }
 
        return 0;
@@ -3144,7 +3167,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
                }
 
                peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
-                                  group->conf->as_type, group, true);
+                                  group->conf->as_type, group, true, NULL);
 
                peer = peer_lock(peer); /* group->peer list reference */
                listnode_add(group->peer, peer);
@@ -3174,11 +3197,11 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
        return 0;
 }
 
-static void bgp_startup_timer_expire(struct thread *thread)
+static void bgp_startup_timer_expire(struct event *thread)
 {
        struct bgp *bgp;
 
-       bgp = THREAD_ARG(thread);
+       bgp = EVENT_ARG(thread);
        bgp->t_startup = NULL;
 }
 
@@ -3196,23 +3219,37 @@ static void bgp_vrf_string_name_delete(void *data)
 
 /* BGP instance creation by `router bgp' commands. */
 static struct bgp *bgp_create(as_t *as, const char *name,
-                             enum bgp_instance_type inst_type)
+                             enum bgp_instance_type inst_type,
+                             const char *as_pretty,
+                             enum asnotation_mode asnotation)
 {
        struct bgp *bgp;
        afi_t afi;
        safi_t safi;
 
        bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp));
+       bgp->as = *as;
+       if (as_pretty)
+               bgp->as_pretty = XSTRDUP(MTYPE_BGP, as_pretty);
+       else
+               bgp->as_pretty = XSTRDUP(MTYPE_BGP, asn_asn2asplain(*as));
+
+       if (asnotation != ASNOTATION_UNDEFINED) {
+               bgp->asnotation = asnotation;
+               SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION);
+       } else
+               asn_str2asn_notation(bgp->as_pretty, NULL, &bgp->asnotation);
 
        if (BGP_DEBUG(zebra, ZEBRA)) {
                if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
-                       zlog_debug("Creating Default VRF, AS %u", *as);
+                       zlog_debug("Creating Default VRF, AS %s",
+                                  bgp->as_pretty);
                else
-                       zlog_debug("Creating %s %s, AS %u",
+                       zlog_debug("Creating %s %s, AS %s",
                                   (inst_type == BGP_INSTANCE_TYPE_VRF)
                                           ? "VRF"
                                           : "VIEW",
-                                  name, *as);
+                                  name, bgp->as_pretty);
        }
 
        /* Default the EVPN VRF to the default one */
@@ -3289,7 +3326,6 @@ static struct bgp *bgp_create(as_t *as, const char *name,
        bgp->condition_check_period = DEFAULT_CONDITIONAL_ROUTES_POLL_TIME;
        bgp_addpath_init_bgp_data(&bgp->tx_addpath);
        bgp->fast_convergence = false;
-       bgp->as = *as;
        bgp->llgr_stale_time = BGP_DEFAULT_LLGR_STALE_TIME;
 
 #ifdef ENABLE_BGP_VNC
@@ -3319,8 +3355,8 @@ static struct bgp *bgp_create(as_t *as, const char *name,
        if (name)
                bgp->name = XSTRDUP(MTYPE_BGP, name);
 
-       thread_add_timer(bm->master, bgp_startup_timer_expire, bgp,
-                        bgp->restart_time, &bgp->t_startup);
+       event_add_timer(bm->master, bgp_startup_timer_expire, bgp,
+                       bgp->restart_time, &bgp->t_startup);
 
        /* printable name we can use in debug messages */
        if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
@@ -3526,7 +3562,8 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *name,
 
 /* Called from VTY commands. */
 int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
-           enum bgp_instance_type inst_type)
+           enum bgp_instance_type inst_type, const char *as_pretty,
+           enum asnotation_mode asnotation)
 {
        struct bgp *bgp;
        struct vrf *vrf = NULL;
@@ -3536,7 +3573,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
        if (ret || *bgp_val)
                return ret;
 
-       bgp = bgp_create(as, name, inst_type);
+       bgp = bgp_create(as, name, inst_type, as_pretty, asnotation);
 
        /*
         * view instances will never work inside of a vrf
@@ -3659,7 +3696,7 @@ void bgp_instance_down(struct bgp *bgp)
 
        /* Stop timers. */
        if (bgp->t_rmap_def_originate_eval) {
-               THREAD_OFF(bgp->t_rmap_def_originate_eval);
+               EVENT_OFF(bgp->t_rmap_def_originate_eval);
                bgp_unlock(bgp); /* TODO - This timer is started with a lock -
                                    why? */
        }
@@ -3711,39 +3748,39 @@ int bgp_delete(struct bgp *bgp)
        hook_call(bgp_inst_delete, bgp);
 
        FOREACH_AFI_SAFI (afi, safi)
-               THREAD_OFF(bgp->t_revalidate[afi][safi]);
+               EVENT_OFF(bgp->t_revalidate[afi][safi]);
 
-       THREAD_OFF(bgp->t_condition_check);
-       THREAD_OFF(bgp->t_startup);
-       THREAD_OFF(bgp->t_maxmed_onstartup);
-       THREAD_OFF(bgp->t_update_delay);
-       THREAD_OFF(bgp->t_establish_wait);
+       EVENT_OFF(bgp->t_condition_check);
+       EVENT_OFF(bgp->t_startup);
+       EVENT_OFF(bgp->t_maxmed_onstartup);
+       EVENT_OFF(bgp->t_update_delay);
+       EVENT_OFF(bgp->t_establish_wait);
 
        /* Set flag indicating bgp instance delete in progress */
        SET_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS);
 
        /* Delete the graceful restart info */
        FOREACH_AFI_SAFI (afi, safi) {
-               struct thread *t;
+               struct event *t;
 
                gr_info = &bgp->gr_info[afi][safi];
                if (!gr_info)
                        continue;
                t = gr_info->t_select_deferral;
                if (t) {
-                       void *info = THREAD_ARG(t);
+                       void *info = EVENT_ARG(t);
 
                        XFREE(MTYPE_TMP, info);
                }
-               THREAD_OFF(gr_info->t_select_deferral);
+               EVENT_OFF(gr_info->t_select_deferral);
 
                t = gr_info->t_route_select;
                if (t) {
-                       void *info = THREAD_ARG(t);
+                       void *info = EVENT_ARG(t);
 
                        XFREE(MTYPE_TMP, info);
                }
-               THREAD_OFF(gr_info->t_route_select);
+               EVENT_OFF(gr_info->t_route_select);
        }
 
        if (BGP_DEBUG(zebra, ZEBRA)) {
@@ -3766,7 +3803,7 @@ int bgp_delete(struct bgp *bgp)
 
        /* Stop timers. */
        if (bgp->t_rmap_def_originate_eval) {
-               THREAD_OFF(bgp->t_rmap_def_originate_eval);
+               EVENT_OFF(bgp->t_rmap_def_originate_eval);
                bgp_unlock(bgp); /* TODO - This timer is started with a lock -
                                    why? */
        }
@@ -3860,7 +3897,7 @@ int bgp_delete(struct bgp *bgp)
        if (bgp->process_queue)
                work_queue_free_and_null(&bgp->process_queue);
 
-       thread_master_free_unused(bm->master);
+       event_master_free_unused(bm->master);
        bgp_unlock(bgp); /* initial reference */
 
        return 0;
@@ -3930,10 +3967,13 @@ void bgp_free(struct bgp *bgp)
                dir = BGP_VPN_POLICY_DIR_TOVPN;
                if (bgp->vpn_policy[afi].rtlist[dir])
                        ecommunity_free(&bgp->vpn_policy[afi].rtlist[dir]);
+               if (bgp->vpn_policy[afi].tovpn_rd_pretty)
+                       XFREE(MTYPE_BGP, bgp->vpn_policy[afi].tovpn_rd_pretty);
        }
 
-       bgp_orr_cleanup(bgp);
+       bgp_confederation_id_unset(bgp);
 
+       XFREE(MTYPE_BGP, bgp->as_pretty);
        XFREE(MTYPE_BGP, bgp->name);
        XFREE(MTYPE_BGP, bgp->name_pretty);
        XFREE(MTYPE_BGP, bgp->snmp_stats);
@@ -4038,7 +4078,7 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp,
 
        /* Create peer first; we've already checked group config is valid. */
        peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
-                          group->conf->as_type, group, true);
+                          group->conf->as_type, group, true, NULL);
        if (!peer)
                return NULL;
 
@@ -4222,6 +4262,26 @@ bool bgp_path_attribute_discard(struct peer *peer, char *buf, size_t size)
        return false;
 }
 
+bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf,
+                                         size_t size)
+{
+       if (!buf)
+               return false;
+
+       buf[0] = '\0';
+
+       for (unsigned int i = 0; i < BGP_ATTR_MAX; i++) {
+               if (peer->withdraw_attrs[i])
+                       snprintf(buf + strlen(buf), size - strlen(buf), "%s%d",
+                                (strlen(buf) > 0) ? " " : "", i);
+       }
+
+       if (strlen(buf) > 0)
+               return true;
+
+       return false;
+}
+
 /* If peer is configured at least one address family return 1. */
 bool peer_active(struct peer *peer)
 {
@@ -4375,6 +4435,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
        {PEER_FLAG_PORT, 0, peer_change_reset},
        {PEER_FLAG_AIGP, 0, peer_change_none},
        {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none},
+       {PEER_FLAG_CAPABILITY_SOFT_VERSION, 0, peer_change_reset},
        {0, 0, 0}};
 
 static const struct peer_flag_action peer_af_flag_action_list[] = {
@@ -4457,7 +4518,7 @@ static int peer_flag_action_set(const struct peer_flag_action *action_list,
        return found;
 }
 
-static void peer_flag_modify_action(struct peer *peer, uint32_t flag)
+static void peer_flag_modify_action(struct peer *peer, uint64_t flag)
 {
        if (flag == PEER_FLAG_SHUTDOWN) {
                if (CHECK_FLAG(peer->flags, flag)) {
@@ -4467,7 +4528,7 @@ static void peer_flag_modify_action(struct peer *peer, uint32_t flag)
                        UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
 
                        if (peer->t_pmax_restart) {
-                               THREAD_OFF(peer->t_pmax_restart);
+                               EVENT_OFF(peer->t_pmax_restart);
                                if (bgp_debug_neighbor_events(peer))
                                        zlog_debug(
                                                "%pBP Maximum-prefix restart timer canceled",
@@ -4576,6 +4637,9 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg)
 /* Disable global administrative shutdown of all peers of BGP instance */
 void bgp_shutdown_disable(struct bgp *bgp)
 {
+       const struct listnode *node;
+       struct peer *peer;
+
        /* do nothing if not shut down. */
        if (!CHECK_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN))
                return;
@@ -4586,6 +4650,9 @@ void bgp_shutdown_disable(struct bgp *bgp)
 
        /* clear the BGP instances shutdown flag */
        UNSET_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN);
+
+       for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer))
+               bgp_timer_set(peer);
 }
 
 /* Change specified peer flag. */
@@ -4738,11 +4805,6 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
        if (flag & PEER_FLAG_REFLECTOR_CLIENT && ptype != BGP_PEER_IBGP)
                return BGP_ERR_NOT_INTERNAL_PEER;
 
-       /* Do not remove reflector client when ORR is configured on this peer */
-       if (flag & PEER_FLAG_REFLECTOR_CLIENT && !set &&
-           peer_orr_rrclient_check(peer, afi, safi))
-               return BGP_ERR_PEER_ORR_CONFIGURED;
-
        /* Special check for remove-private-AS.  */
        if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && ptype == BGP_PEER_IBGP)
                return BGP_ERR_REMOVE_PRIVATE_AS;
@@ -6226,7 +6288,7 @@ int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi)
 }
 
 int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
-                     bool replace_as)
+                     bool replace_as, const char *as_str)
 {
        bool old_no_prepend, old_replace_as;
        struct bgp *bgp = peer->bgp;
@@ -6251,6 +6313,12 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
            && old_replace_as == replace_as)
                return 0;
        peer->change_local_as = as;
+       if (as_str) {
+               if (peer->change_local_as_pretty)
+                       XFREE(MTYPE_BGP, peer->change_local_as_pretty);
+               peer->change_local_as_pretty = XSTRDUP(MTYPE_BGP, as_str);
+       }
+
        (void)peer_sort(peer);
 
        /* Check if handling a regular peer. */
@@ -6284,6 +6352,9 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
                COND_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS,
                          replace_as);
                member->change_local_as = as;
+               if (as_str)
+                       member->change_local_as_pretty =
+                               XSTRDUP(MTYPE_BGP, as_str);
        }
 
        return 0;
@@ -6309,6 +6380,7 @@ int peer_local_as_unset(struct peer *peer)
                peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
                peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
                peer->change_local_as = 0;
+               XFREE(MTYPE_BGP, peer->change_local_as_pretty);
        }
 
        /* Check if handling a regular peer. */
@@ -6339,6 +6411,7 @@ int peer_local_as_unset(struct peer *peer)
                UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
                UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
                member->change_local_as = 0;
+               XFREE(MTYPE_BGP, member->change_local_as_pretty);
 
                /* Send notification or stop peer depending on state. */
                if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
@@ -7325,7 +7398,7 @@ static bool peer_maximum_prefix_clear_overflow(struct peer *peer)
 
        UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
        if (peer->t_pmax_restart) {
-               THREAD_OFF(peer->t_pmax_restart);
+               EVENT_OFF(peer->t_pmax_restart);
                if (bgp_debug_neighbor_events(peer))
                        zlog_debug(
                                "%pBP Maximum-prefix restart timer cancelled",
@@ -7937,7 +8010,7 @@ char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
        return buf;
 }
 
-void bgp_master_init(struct thread_master *master, const int buffer_size,
+void bgp_master_init(struct event_loop *master, const int buffer_size,
                     struct list *addresses)
 {
        qobj_init();
@@ -7959,7 +8032,8 @@ void bgp_master_init(struct thread_master *master, const int buffer_size,
        bm->socket_buffer = buffer_size;
        bm->wait_for_fib = false;
        bm->tcp_dscp = IPTOS_PREC_INTERNETCONTROL;
-       bm->inq_limit = BM_DEFAULT_INQ_LIMIT;
+       bm->inq_limit = BM_DEFAULT_Q_LIMIT;
+       bm->outq_limit = BM_DEFAULT_Q_LIMIT;
 
        bgp_mac_init();
        /* init the rd id space.
@@ -8021,7 +8095,7 @@ static void bgp_instasn_autocomplete(vector comps, struct cmd_token *token)
 {
        struct listnode *next, *next2;
        struct bgp *bgp, *bgp2;
-       char buf[11];
+       char buf[ASN_STRING_MAX_SIZE];
 
        for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) {
                /* deduplicate */
@@ -8034,7 +8108,7 @@ static void bgp_instasn_autocomplete(vector comps, struct cmd_token *token)
                if (bgp2 != bgp)
                        continue;
 
-               snprintf(buf, sizeof(buf), "%u", bgp->as);
+               snprintf(buf, sizeof(buf), "%s", bgp->as_pretty);
                vector_set(comps, XSTRDUP(MTYPE_COMPLETION, buf));
        }
 }
@@ -8202,7 +8276,7 @@ void bgp_terminate(void)
        if (bm->listen_sockets)
                list_delete(&bm->listen_sockets);
 
-       THREAD_OFF(bm->t_rmap_update);
+       EVENT_OFF(bm->t_rmap_update);
 
        bgp_mac_finish();
 }