]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgpd.c
Merge branch 'master' into evpn-symmetric-routing
[mirror_frr.git] / bgpd / bgpd.c
index a39ff3b271a06e391228292de2e05f922122dc42..0947c85fcf31533bc184da4ae6afb1304940b611 100644 (file)
@@ -24,6 +24,7 @@
 #include "thread.h"
 #include "buffer.h"
 #include "stream.h"
+#include "ringbuf.h"
 #include "command.h"
 #include "sockunion.h"
 #include "sockopt.h"
@@ -42,6 +43,7 @@
 #include "jhash.h"
 #include "table.h"
 #include "lib/json.h"
+#include "frr_pthread.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_table.h"
@@ -75,7 +77,9 @@
 #include "bgpd/bgp_bfd.h"
 #include "bgpd/bgp_memory.h"
 #include "bgpd/bgp_evpn_vty.h"
-
+#include "bgpd/bgp_keepalives.h"
+#include "bgpd/bgp_io.h"
+#include "bgpd/bgp_ecommunity.h"
 
 DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
 DEFINE_QOBJ_TYPE(bgp_master)
@@ -214,7 +218,7 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id)
                return 0;
 
        /* EVPN uses router id in RD, withdraw them */
-       if (bgp->advertise_all_vni)
+       if (is_evpn_enabled())
                bgp_evpn_handle_router_id_update(bgp, TRUE);
 
        IPV4_ADDR_COPY(&bgp->router_id, id);
@@ -231,7 +235,7 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id)
        }
 
        /* EVPN uses router id in RD, update them */
-       if (bgp->advertise_all_vni)
+       if (is_evpn_enabled())
                bgp_evpn_handle_router_id_update(bgp, FALSE);
 
        return 0;
@@ -909,7 +913,7 @@ static void peer_global_config_reset(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)
+static inline bgp_peer_sort_t peer_calc_sort(struct peer *peer)
 {
        struct bgp *bgp;
 
@@ -989,10 +993,14 @@ static void peer_free(struct peer *peer)
         * but just to be sure..
         */
        bgp_timer_set(peer);
-       BGP_READ_OFF(peer->t_read);
-       BGP_WRITE_OFF(peer->t_write);
+       bgp_reads_off(peer);
+       bgp_writes_off(peer);
+       assert(!peer->t_write);
+       assert(!peer->t_read);
        BGP_EVENT_FLUSH(peer);
 
+       pthread_mutex_destroy(&peer->io_mtx);
+
        /* Free connected nexthop, if present */
        if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)
            && !peer_dynamic_neighbor(peer))
@@ -1121,25 +1129,25 @@ struct peer *peer_new(struct bgp *bgp)
        peer->password = NULL;
 
        /* Set default flags.  */
-       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-               for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
-                       if (!bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
-                               SET_FLAG(peer->af_flags[afi][safi],
-                                        PEER_FLAG_SEND_COMMUNITY);
-                               SET_FLAG(peer->af_flags[afi][safi],
-                                        PEER_FLAG_SEND_EXT_COMMUNITY);
-                               SET_FLAG(peer->af_flags[afi][safi],
-                                        PEER_FLAG_SEND_LARGE_COMMUNITY);
-                       }
-                       peer->orf_plist[afi][safi] = NULL;
+       FOREACH_AFI_SAFI (afi, safi) {
+               if (!bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
+                       SET_FLAG(peer->af_flags[afi][safi],
+                                PEER_FLAG_SEND_COMMUNITY);
+                       SET_FLAG(peer->af_flags[afi][safi],
+                                PEER_FLAG_SEND_EXT_COMMUNITY);
+                       SET_FLAG(peer->af_flags[afi][safi],
+                                PEER_FLAG_SEND_LARGE_COMMUNITY);
                }
+               peer->orf_plist[afi][safi] = NULL;
+       }
        SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
 
        /* Create buffers.  */
-       peer->ibuf = stream_new(BGP_MAX_PACKET_SIZE);
+       peer->ibuf = stream_fifo_new();
        peer->obuf = stream_fifo_new();
+       pthread_mutex_init(&peer->io_mtx, NULL);
 
-       /* We use a larger buffer for peer->work in the event that:
+       /* We use a larger buffer for peer->obuf_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
@@ -1153,10 +1161,12 @@ struct peer *peer_new(struct bgp *bgp)
         * bounds
         * checking for every single attribute as we construct an UPDATE.
         */
-       peer->work =
+       peer->obuf_work =
                stream_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW);
-       peer->scratch = stream_new(BGP_MAX_PACKET_SIZE);
+       peer->ibuf_work =
+               ringbuf_new(BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX);
 
+       peer->scratch = stream_new(BGP_MAX_PACKET_SIZE);
 
        bgp_sync_init(peer);
 
@@ -1197,7 +1207,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
        peer_dst->local_as = peer_src->local_as;
        peer_dst->ifindex = peer_src->ifindex;
        peer_dst->port = peer_src->port;
-       peer_sort(peer_dst);
+       (void)peer_sort(peer_dst);
        peer_dst->rmap_type = peer_src->rmap_type;
 
        /* Timers */
@@ -1214,16 +1224,13 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
                peer_dst->password =
                        XSTRDUP(MTYPE_PEER_PASSWORD, peer_src->password);
 
-       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];
-                       peer_dst->weight[afi][safi] =
-                               peer_src->weight[afi][safi];
-               }
+       FOREACH_AFI_SAFI (afi, 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];
+               peer_dst->weight[afi][safi] = peer_src->weight[afi][safi];
+       }
 
        for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
                paf = peer_src->peer_af_array[afidx];
@@ -1425,10 +1432,8 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp)
        afi_t afi;
        safi_t safi;
 
-       for (afi = AFI_IP; afi < AFI_MAX; afi++) {
-               for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
-                       bgp_recalculate_afi_safi_bestpaths(bgp, afi, safi);
-               }
+       FOREACH_AFI_SAFI (afi, safi) {
+               bgp_recalculate_afi_safi_bestpaths(bgp, afi, safi);
        }
 }
 
@@ -1472,6 +1477,14 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
        listnode_add_sort(bgp->peer, peer);
        hash_get(bgp->peerhash, peer, hash_alloc_intern);
 
+       /* Adjust update-group coalesce timer heuristics for # peers. */
+       if (bgp->heuristic_coalesce) {
+               long ct = BGP_DEFAULT_SUBGROUP_COALESCE_TIME
+                         + (bgp->peer->count
+                            * BGP_PEER_ADJUST_SUBGROUP_COALESCE_TIME);
+               bgp->coalesce_time = MIN(BGP_MAX_SUBGROUP_COALESCE_TIME, ct);
+       }
+
        active = peer_active(peer);
 
        /* Last read and reset time set */
@@ -1875,6 +1888,11 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi)
                                                BGP_NOTIFY_CEASE_CONFIG_CHANGE);
                        }
                }
+               if (peer->status == OpenSent || peer->status == OpenConfirm) {
+                       peer->last_reset = PEER_DOWN_AF_ACTIVATE;
+                       bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+                                       BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+               }
        }
 
        return 0;
@@ -2088,6 +2106,11 @@ int peer_delete(struct peer *peer)
        bgp = peer->bgp;
        accept_peer = CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
 
+       bgp_reads_off(peer);
+       bgp_writes_off(peer);
+       assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON));
+       assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON));
+
        if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT))
                peer_nsf_stop(peer);
 
@@ -2149,7 +2172,7 @@ int peer_delete(struct peer *peer)
 
        /* Buffers.  */
        if (peer->ibuf) {
-               stream_free(peer->ibuf);
+               stream_fifo_free(peer->ibuf);
                peer->ibuf = NULL;
        }
 
@@ -2158,9 +2181,14 @@ int peer_delete(struct peer *peer)
                peer->obuf = NULL;
        }
 
-       if (peer->work) {
-               stream_free(peer->work);
-               peer->work = NULL;
+       if (peer->ibuf_work) {
+               ringbuf_del(peer->ibuf_work);
+               peer->ibuf_work = NULL;
+       }
+
+       if (peer->obuf_work) {
+               stream_free(peer->obuf_work);
+               peer->obuf_work = NULL;
        }
 
        if (peer->scratch) {
@@ -2180,51 +2208,49 @@ int peer_delete(struct peer *peer)
        }
 
        /* Free filter related memory.  */
-       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-               for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
-                       filter = &peer->filter[afi][safi];
-
-                       for (i = FILTER_IN; i < FILTER_MAX; i++) {
-                               if (filter->dlist[i].name) {
-                                       XFREE(MTYPE_BGP_FILTER_NAME,
-                                             filter->dlist[i].name);
-                                       filter->dlist[i].name = NULL;
-                               }
-
-                               if (filter->plist[i].name) {
-                                       XFREE(MTYPE_BGP_FILTER_NAME,
-                                             filter->plist[i].name);
-                                       filter->plist[i].name = NULL;
-                               }
+       FOREACH_AFI_SAFI (afi, safi) {
+               filter = &peer->filter[afi][safi];
 
-                               if (filter->aslist[i].name) {
-                                       XFREE(MTYPE_BGP_FILTER_NAME,
-                                             filter->aslist[i].name);
-                                       filter->aslist[i].name = NULL;
-                               }
+               for (i = FILTER_IN; i < FILTER_MAX; i++) {
+                       if (filter->dlist[i].name) {
+                               XFREE(MTYPE_BGP_FILTER_NAME,
+                                     filter->dlist[i].name);
+                               filter->dlist[i].name = NULL;
                        }
 
-                       for (i = RMAP_IN; i < RMAP_MAX; i++) {
-                               if (filter->map[i].name) {
-                                       XFREE(MTYPE_BGP_FILTER_NAME,
-                                             filter->map[i].name);
-                                       filter->map[i].name = NULL;
-                               }
+                       if (filter->plist[i].name) {
+                               XFREE(MTYPE_BGP_FILTER_NAME,
+                                     filter->plist[i].name);
+                               filter->plist[i].name = NULL;
                        }
 
-                       if (filter->usmap.name) {
+                       if (filter->aslist[i].name) {
                                XFREE(MTYPE_BGP_FILTER_NAME,
-                                     filter->usmap.name);
-                               filter->usmap.name = NULL;
+                                     filter->aslist[i].name);
+                               filter->aslist[i].name = NULL;
                        }
+               }
 
-                       if (peer->default_rmap[afi][safi].name) {
-                               XFREE(MTYPE_ROUTE_MAP_NAME,
-                                     peer->default_rmap[afi][safi].name);
-                               peer->default_rmap[afi][safi].name = NULL;
+               for (i = RMAP_IN; i < RMAP_MAX; i++) {
+                       if (filter->map[i].name) {
+                               XFREE(MTYPE_BGP_FILTER_NAME,
+                                     filter->map[i].name);
+                               filter->map[i].name = NULL;
                        }
                }
 
+               if (filter->usmap.name) {
+                       XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+                       filter->usmap.name = NULL;
+               }
+
+               if (peer->default_rmap[afi][safi].name) {
+                       XFREE(MTYPE_ROUTE_MAP_NAME,
+                             peer->default_rmap[afi][safi].name);
+                       peer->default_rmap[afi][safi].name = NULL;
+               }
+       }
+
        FOREACH_AFI_SAFI (afi, safi)
                peer_af_delete(peer, afi, safi);
 
@@ -2301,6 +2327,7 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name)
        group->conf->gtsm_hops = 0;
        group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
        UNSET_FLAG(group->conf->config, PEER_CONFIG_TIMER);
+       UNSET_FLAG(group->conf->config, PEER_GROUP_CONFIG_TIMER);
        UNSET_FLAG(group->conf->config, PEER_CONFIG_CONNECT);
        group->conf->keepalive = 0;
        group->conf->holdtime = 0;
@@ -2621,19 +2648,17 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
                if (peer->conf_if && cap_enhe_preset)
                        peer_flag_set(peer, PEER_FLAG_CAPABILITY_ENHE);
 
-               for (afi = AFI_IP; afi < AFI_MAX; afi++)
-                       for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
-                               if (group->conf->afc[afi][safi]) {
-                                       peer->afc[afi][safi] = 1;
-
-                                       if (peer_af_find(peer, afi, safi)
-                                           || peer_af_create(peer, afi,
-                                                             safi)) {
-                                               peer_group2peer_config_copy_af(
-                                                       group, peer, afi, safi);
-                                       }
-                               } else if (peer->afc[afi][safi])
-                                       peer_deactivate(peer, afi, safi);
+               FOREACH_AFI_SAFI (afi, safi) {
+                       if (group->conf->afc[afi][safi]) {
+                               peer->afc[afi][safi] = 1;
+
+                               if (peer_af_find(peer, afi, safi)
+                                   || peer_af_create(peer, afi, safi)) {
+                                       peer_group2peer_config_copy_af(
+                                               group, peer, afi, safi);
+                               }
+                       } else if (peer->afc[afi][safi])
+                               peer_deactivate(peer, afi, safi);
                        }
 
                if (peer->group) {
@@ -2703,15 +2728,15 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
 
                /* If the peer-group is active for this afi/safi then activate
                 * for this peer */
-               for (afi = AFI_IP; afi < AFI_MAX; afi++)
-                       for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
-                               if (group->conf->afc[afi][safi]) {
-                                       peer->afc[afi][safi] = 1;
-                                       peer_af_create(peer, afi, safi);
-                                       peer_group2peer_config_copy_af(
-                                               group, peer, afi, safi);
-                               } else if (peer->afc[afi][safi])
-                                       peer_deactivate(peer, afi, safi);
+               FOREACH_AFI_SAFI (afi, safi) {
+                       if (group->conf->afc[afi][safi]) {
+                               peer->afc[afi][safi] = 1;
+                               peer_af_create(peer, afi, safi);
+                               peer_group2peer_config_copy_af(group, peer, afi,
+                                                              safi);
+                       } else if (peer->afc[afi][safi])
+                               peer_deactivate(peer, afi, safi);
+               }
 
                SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
 
@@ -2733,19 +2758,18 @@ int peer_group_unbind(struct bgp *bgp, struct peer *peer,
        if (group != peer->group)
                return BGP_ERR_PEER_GROUP_MISMATCH;
 
-       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-               for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
-                       if (peer->afc[afi][safi]) {
-                               peer->afc[afi][safi] = 0;
-                               peer_af_flag_reset(peer, afi, safi);
-
-                               if (peer_af_delete(peer, afi, safi) != 0) {
-                                       zlog_err(
-                                               "couldn't delete af structure for peer %s",
-                                               peer->host);
-                               }
+       FOREACH_AFI_SAFI (afi, safi) {
+               if (peer->afc[afi][safi]) {
+                       peer->afc[afi][safi] = 0;
+                       peer_af_flag_reset(peer, afi, safi);
+
+                       if (peer_af_delete(peer, afi, safi) != 0) {
+                               zlog_err(
+                                       "couldn't delete af structure for peer %s",
+                                       peer->host);
                        }
                }
+       }
 
        assert(listnode_lookup(group->peer, peer));
        peer_unlock(peer); /* peer group list reference */
@@ -2845,18 +2869,17 @@ static struct bgp *bgp_create(as_t *as, const char *name,
        bgp->group = list_new();
        bgp->group->cmp = (int (*)(void *, void *))peer_group_cmp;
 
-       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-               for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
-                       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);
+       FOREACH_AFI_SAFI (afi, safi) {
+               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);
 
-                       /* Enable maximum-paths */
-                       bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_EBGP,
-                                             multipath_num, 0);
-                       bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_IBGP,
-                                             multipath_num, 0);
-               }
+               /* Enable maximum-paths */
+               bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_EBGP,
+                                     multipath_num, 0);
+               bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_IBGP,
+                                     multipath_num, 0);
+       }
 
        bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
        bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
@@ -2901,7 +2924,10 @@ static struct bgp *bgp_create(as_t *as, const char *name,
                                 bgp->restart_time, &bgp->t_startup);
        }
 
-       bgp->wpkt_quanta = BGP_WRITE_PACKET_MAX;
+       atomic_store_explicit(&bgp->wpkt_quanta, BGP_WRITE_PACKET_MAX,
+                             memory_order_relaxed);
+       atomic_store_explicit(&bgp->rpkt_quanta, BGP_READ_PACKET_MAX,
+                             memory_order_relaxed);
        bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME;
 
        QOBJ_REG(bgp, bgp);
@@ -3119,6 +3145,9 @@ int bgp_delete(struct bgp *bgp)
                                   bgp->name);
        }
 
+       /* unmap from RT list */
+       bgp_evpn_vrf_delete(bgp);
+
        /* Stop timers. */
        if (bgp->t_rmap_def_originate_eval) {
                BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval);
@@ -3205,27 +3234,26 @@ void bgp_free(struct bgp *bgp)
                bgp->peerhash = NULL;
        }
 
-       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-               for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
-                       /* Special handling for 2-level routing tables. */
-                       if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
-                           || safi == SAFI_EVPN) {
-                               for (rn = bgp_table_top(bgp->rib[afi][safi]);
-                                    rn; rn = bgp_route_next(rn)) {
-                                       table = (struct bgp_table *)rn->info;
-                                       bgp_table_finish(&table);
-                               }
+       FOREACH_AFI_SAFI (afi, safi) {
+               /* Special handling for 2-level routing tables. */
+               if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
+                   || safi == SAFI_EVPN) {
+                       for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
+                            rn = bgp_route_next(rn)) {
+                               table = (struct bgp_table *)rn->info;
+                               bgp_table_finish(&table);
                        }
-                       if (bgp->route[afi][safi])
-                               bgp_table_finish(&bgp->route[afi][safi]);
-                       if (bgp->aggregate[afi][safi])
-                               bgp_table_finish(&bgp->aggregate[afi][safi]);
-                       if (bgp->rib[afi][safi])
-                               bgp_table_finish(&bgp->rib[afi][safi]);
-                       rmap = &bgp->table_map[afi][safi];
-                       if (rmap->name)
-                               XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
                }
+               if (bgp->route[afi][safi])
+                       bgp_table_finish(&bgp->route[afi][safi]);
+               if (bgp->aggregate[afi][safi])
+                       bgp_table_finish(&bgp->aggregate[afi][safi]);
+               if (bgp->rib[afi][safi])
+                       bgp_table_finish(&bgp->rib[afi][safi]);
+               rmap = &bgp->table_map[afi][safi];
+               if (rmap->name)
+                       XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+       }
 
        bgp_scan_finish(bgp);
        bgp_address_destroy(bgp);
@@ -3359,17 +3387,16 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp,
         * peer_group_bind as that is sub-optimal and does some stuff we don't
         * want.
         */
-       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-               for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
-                       if (!group->conf->afc[afi][safi])
-                               continue;
-                       peer->afc[afi][safi] = 1;
+       FOREACH_AFI_SAFI (afi, safi) {
+               if (!group->conf->afc[afi][safi])
+                       continue;
+               peer->afc[afi][safi] = 1;
 
-                       if (!peer_af_find(peer, afi, safi))
-                               peer_af_create(peer, afi, safi);
+               if (!peer_af_find(peer, afi, safi))
+                       peer_af_create(peer, afi, safi);
 
-                       peer_group2peer_config_copy_af(group, peer, afi, safi);
-               }
+               peer_group2peer_config_copy_af(group, peer, afi, safi);
+       }
 
        /* Mark as dynamic, but also as a "config node" for other things to
         * work. */
@@ -4582,20 +4609,30 @@ int peer_timers_set(struct peer *peer, u_int32_t keepalive, u_int32_t holdtime)
                return BGP_ERR_INVALID_VALUE;
 
        /* Set value to the configuration. */
-       SET_FLAG(peer->config, PEER_CONFIG_TIMER);
        peer->holdtime = holdtime;
        peer->keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3);
 
-       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)) {
+       /* First work on real peers with timers */
+       if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
                SET_FLAG(peer->config, PEER_CONFIG_TIMER);
-               peer->holdtime = group->conf->holdtime;
-               peer->keepalive = group->conf->keepalive;
+               UNSET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
+       } else {
+               /* Now work on the peer-group timers */
+               SET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
+
+               /* peer-group member updates. */
+               group = peer->group;
+               for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+                       /* Skip peers that have their own timers */
+                       if (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER))
+                               continue;
+
+                       SET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
+                       peer->holdtime = group->conf->holdtime;
+                       peer->keepalive = group->conf->keepalive;
+               }
        }
+
        return 0;
 }
 
@@ -4604,20 +4641,32 @@ int peer_timers_unset(struct peer *peer)
        struct peer_group *group;
        struct listnode *node, *nnode;
 
-       /* Clear configuration. */
-       UNSET_FLAG(peer->config, PEER_CONFIG_TIMER);
-       peer->keepalive = 0;
-       peer->holdtime = 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)) {
+       /* First work on real peers vs the peer-group */
+       if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
                UNSET_FLAG(peer->config, PEER_CONFIG_TIMER);
-               peer->holdtime = 0;
                peer->keepalive = 0;
+               peer->holdtime = 0;
+
+               if (peer->group && peer->group->conf->holdtime) {
+                       SET_FLAG(peer->config, PEER_GROUP_CONFIG_TIMER);
+                       peer->keepalive = peer->group->conf->keepalive;
+                       peer->holdtime = peer->group->conf->holdtime;
+               }
+       } else {
+               /* peer-group member updates. */
+               group = peer->group;
+               for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+                       if (!CHECK_FLAG(peer->config, PEER_CONFIG_TIMER)) {
+                               UNSET_FLAG(peer->config,
+                                          PEER_GROUP_CONFIG_TIMER);
+                               peer->holdtime = 0;
+                               peer->keepalive = 0;
+                       }
+               }
+
+               UNSET_FLAG(group->conf->config, PEER_GROUP_CONFIG_TIMER);
+               group->conf->holdtime = 0;
+               group->conf->keepalive = 0;
        }
 
        return 0;
@@ -5214,45 +5263,40 @@ static void peer_distribute_update(struct access_list *access)
                        update_group_policy_update(bgp, BGP_POLICY_FILTER_LIST,
                                                   access->name, 0, 0);
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
-                       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-                               for (safi = SAFI_UNICAST; safi < SAFI_MAX;
-                                    safi++) {
-                                       filter = &peer->filter[afi][safi];
-
-                                       for (direct = FILTER_IN;
-                                            direct < FILTER_MAX; direct++) {
-                                               if (filter->dlist[direct].name)
-                                                       filter->dlist[direct]
-                                                               .alist = access_list_lookup(
-                                                               afi,
-                                                               filter->dlist[direct]
-                                                                       .name);
-                                               else
+                       FOREACH_AFI_SAFI (afi, safi) {
+                               filter = &peer->filter[afi][safi];
+
+                               for (direct = FILTER_IN; direct < FILTER_MAX;
+                                    direct++) {
+                                       if (filter->dlist[direct].name)
+                                               filter->dlist[direct]
+                                                       .alist = access_list_lookup(
+                                                       afi,
                                                        filter->dlist[direct]
-                                                               .alist = NULL;
-                                       }
+                                                               .name);
+                                       else
+                                               filter->dlist[direct].alist =
+                                                       NULL;
                                }
+                       }
                }
                for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
-                       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-                               for (safi = SAFI_UNICAST; safi < SAFI_MAX;
-                                    safi++) {
-                                       filter =
-                                               &group->conf->filter[afi][safi];
-
-                                       for (direct = FILTER_IN;
-                                            direct < FILTER_MAX; direct++) {
-                                               if (filter->dlist[direct].name)
-                                                       filter->dlist[direct]
-                                                               .alist = access_list_lookup(
-                                                               afi,
-                                                               filter->dlist[direct]
-                                                                       .name);
-                                               else
+                       FOREACH_AFI_SAFI (afi, safi) {
+                               filter = &group->conf->filter[afi][safi];
+
+                               for (direct = FILTER_IN; direct < FILTER_MAX;
+                                    direct++) {
+                                       if (filter->dlist[direct].name)
+                                               filter->dlist[direct]
+                                                       .alist = access_list_lookup(
+                                                       afi,
                                                        filter->dlist[direct]
-                                                               .alist = NULL;
-                                       }
+                                                               .name);
+                                       else
+                                               filter->dlist[direct].alist =
+                                                       NULL;
                                }
+                       }
                }
 #if ENABLE_BGP_VNC
                vnc_prefix_list_update(bgp);
@@ -5385,45 +5429,40 @@ static void peer_prefix_list_update(struct prefix_list *plist)
                        plist ? prefix_list_name(plist) : NULL, 0, 0);
 
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
-                       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-                               for (safi = SAFI_UNICAST; safi < SAFI_MAX;
-                                    safi++) {
-                                       filter = &peer->filter[afi][safi];
-
-                                       for (direct = FILTER_IN;
-                                            direct < FILTER_MAX; direct++) {
-                                               if (filter->plist[direct].name)
-                                                       filter->plist[direct]
-                                                               .plist = prefix_list_lookup(
-                                                               afi,
-                                                               filter->plist[direct]
-                                                                       .name);
-                                               else
+                       FOREACH_AFI_SAFI (afi, safi) {
+                               filter = &peer->filter[afi][safi];
+
+                               for (direct = FILTER_IN; direct < FILTER_MAX;
+                                    direct++) {
+                                       if (filter->plist[direct].name)
+                                               filter->plist[direct]
+                                                       .plist = prefix_list_lookup(
+                                                       afi,
                                                        filter->plist[direct]
-                                                               .plist = NULL;
-                                       }
+                                                               .name);
+                                       else
+                                               filter->plist[direct].plist =
+                                                       NULL;
                                }
+                       }
                }
                for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
-                       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-                               for (safi = SAFI_UNICAST; safi < SAFI_MAX;
-                                    safi++) {
-                                       filter =
-                                               &group->conf->filter[afi][safi];
-
-                                       for (direct = FILTER_IN;
-                                            direct < FILTER_MAX; direct++) {
-                                               if (filter->plist[direct].name)
+                       FOREACH_AFI_SAFI (afi, safi) {
+                               filter = &group->conf->filter[afi][safi];
+
+                               for (direct = FILTER_IN; direct < FILTER_MAX;
+                                    direct++) {
+                                       if (filter->plist[direct].name)
+                                               filter->plist[direct]
+                                                       .plist = prefix_list_lookup(
+                                                       afi,
                                                        filter->plist[direct]
-                                                               .plist = prefix_list_lookup(
-                                                               afi,
-                                                               filter->plist[direct]
-                                                                       .name);
-                                               else
-                                                       filter->plist[direct]
-                                                               .plist = NULL;
-                                       }
+                                                               .name);
+                                       else
+                                               filter->plist[direct].plist =
+                                                       NULL;
                                }
+                       }
                }
        }
 }
@@ -5542,43 +5581,38 @@ static void peer_aslist_update(const char *aslist_name)
                                           aslist_name, 0, 0);
 
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
-                       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-                               for (safi = SAFI_UNICAST; safi < SAFI_MAX;
-                                    safi++) {
-                                       filter = &peer->filter[afi][safi];
-
-                                       for (direct = FILTER_IN;
-                                            direct < FILTER_MAX; direct++) {
-                                               if (filter->aslist[direct].name)
+                       FOREACH_AFI_SAFI (afi, safi) {
+                               filter = &peer->filter[afi][safi];
+
+                               for (direct = FILTER_IN; direct < FILTER_MAX;
+                                    direct++) {
+                                       if (filter->aslist[direct].name)
+                                               filter->aslist[direct]
+                                                       .aslist = as_list_lookup(
                                                        filter->aslist[direct]
-                                                               .aslist = as_list_lookup(
-                                                               filter->aslist[direct]
-                                                                       .name);
-                                               else
-                                                       filter->aslist[direct]
-                                                               .aslist = NULL;
-                                       }
+                                                               .name);
+                                       else
+                                               filter->aslist[direct].aslist =
+                                                       NULL;
                                }
+                       }
                }
                for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
-                       for (afi = AFI_IP; afi < AFI_MAX; afi++)
-                               for (safi = SAFI_UNICAST; safi < SAFI_MAX;
-                                    safi++) {
-                                       filter =
-                                               &group->conf->filter[afi][safi];
-
-                                       for (direct = FILTER_IN;
-                                            direct < FILTER_MAX; direct++) {
-                                               if (filter->aslist[direct].name)
-                                                       filter->aslist[direct]
-                                                               .aslist = as_list_lookup(
-                                                               filter->aslist[direct]
-                                                                       .name);
-                                               else
+                       FOREACH_AFI_SAFI (afi, safi) {
+                               filter = &group->conf->filter[afi][safi];
+
+                               for (direct = FILTER_IN; direct < FILTER_MAX;
+                                    direct++) {
+                                       if (filter->aslist[direct].name)
+                                               filter->aslist[direct]
+                                                       .aslist = as_list_lookup(
                                                        filter->aslist[direct]
-                                                               .aslist = NULL;
-                                       }
+                                                               .name);
+                                       else
+                                               filter->aslist[direct].aslist =
+                                                       NULL;
                                }
+                       }
                }
        }
 }
@@ -6535,7 +6569,7 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
        }
 
        /* timers */
-       if (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER)
+       if ((PEER_OR_GROUP_TIMER_SET(peer))
            && ((!peer_group_active(peer)
                 && (peer->keepalive != BGP_DEFAULT_KEEPALIVE
                     || peer->holdtime != BGP_DEFAULT_HOLDTIME))
@@ -7052,6 +7086,11 @@ int bgp_config_write(struct vty *vty)
 
        /* BGP configuration. */
        for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
+
+               /* skip all auto created vrf as they dont have user config */
+               if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+                       continue;
+
                /* Router bgp ASN */
                vty_out(vty, "router bgp %u", bgp->as);
 
@@ -7180,6 +7219,8 @@ int bgp_config_write(struct vty *vty)
 
                /* write quanta */
                bgp_config_write_wpkt_quanta(vty, bgp);
+               /* read quanta */
+               bgp_config_write_rpkt_quanta(vty, bgp);
 
                /* coalesce time */
                bgp_config_write_coalesce_time(vty, bgp);
@@ -7274,6 +7315,38 @@ int bgp_config_write(struct vty *vty)
                if (bgp_option_check(BGP_OPT_CONFIG_CISCO))
                        vty_out(vty, " no auto-summary\n");
 
+               /* import route-target */
+               if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
+                       char *ecom_str;
+                       struct listnode *node, *nnode;
+                       struct ecommunity *ecom;
+
+                       for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode,
+                                              ecom)) {
+                               ecom_str = ecommunity_ecom2str(
+                                       ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+                               vty_out(vty, "   route-target import %s\n",
+                                       ecom_str);
+                               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+                       }
+               }
+
+               /* export route-target */
+               if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
+                       char *ecom_str;
+                       struct listnode *node, *nnode;
+                       struct ecommunity *ecom;
+
+                       for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode,
+                                              ecom)) {
+                               ecom_str = ecommunity_ecom2str(
+                                       ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+                               vty_out(vty, "   route-target export %s\n",
+                                       ecom_str);
+                               XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+                       }
+               }
+
                /* IPv4 unicast configuration.  */
                bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
 
@@ -7334,6 +7407,13 @@ void bgp_master_init(struct thread_master *master)
 
        bgp_process_queue_init();
 
+       /* init the rd id space.
+          assign 0th index in the bitfield,
+          so that we start with id 1
+        */
+       bf_init(bm->rd_idspace, UINT16_MAX);
+       bf_assign_zero_index(bm->rd_idspace);
+
        /* Enable multiple instances by default. */
        bgp_option_set(BGP_OPT_MULTIPLE_INSTANCE);
 
@@ -7387,12 +7467,53 @@ static const struct cmd_variable_handler bgp_viewvrf_var_handlers[] = {
        {.completions = NULL},
 };
 
+static void bgp_pthreads_init()
+{
+       frr_pthread_init();
+
+       frr_pthread_new("BGP i/o thread", PTHREAD_IO, bgp_io_start,
+                       bgp_io_stop);
+       frr_pthread_new("BGP keepalives thread", PTHREAD_KEEPALIVES,
+                       bgp_keepalives_start, bgp_keepalives_stop);
+
+       /* pre-run initialization */
+       bgp_keepalives_init();
+       bgp_io_init();
+}
+
+void bgp_pthreads_run()
+{
+       pthread_attr_t attr;
+       pthread_attr_init(&attr);
+       pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+
+       /*
+        * Please ensure that the io thread is running
+        * by calling bgp_io_running.  The BGP threads
+        * depend on it being running when we start
+        * looking for it.
+        */
+       frr_pthread_run(PTHREAD_IO, &attr, NULL);
+       bgp_io_running();
+
+       frr_pthread_run(PTHREAD_KEEPALIVES, &attr, NULL);
+}
+
+void bgp_pthreads_finish()
+{
+       frr_pthread_stop_all();
+       frr_pthread_finish();
+}
+
 void bgp_init(void)
 {
 
        /* allocates some vital data structures used by peer commands in
         * vty_init */
 
+       /* pre-init pthreads */
+       bgp_pthreads_init();
+
        /* Init zebra. */
        bgp_zebra_init(bm->master);
 
@@ -7457,6 +7578,7 @@ void bgp_terminate(void)
         */
        /* reverse bgp_master_init */
        bgp_close();
+
        if (bm->listen_sockets)
                list_delete_and_null(&bm->listen_sockets);