]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: Advertise FIB installed routes to bgp peers (Part 3)
authorSoman K S <somanks@gmail.com>
Fri, 6 Nov 2020 03:25:56 +0000 (08:55 +0530)
committerSoman K S <somanks@gmail.com>
Fri, 6 Nov 2020 03:25:56 +0000 (08:55 +0530)
* Process FIB update in bgp_zebra_route_notify_owner() and call
  group_announce_route() if route is installed
* When bgp update is received for a route which is not installed earlier
  (flag BGP_NODE_FIB_INSTALLED is not set) and suppress fib is enabled
  set the flag BGP_NODE_FIB_INSTALL_PENDING to indicate fib install is
  pending for the route. The route will be advertised when zebra send
  ZAPI_ROUTE_INSTALLED status.
* The advertisement delay (BGP_DEFAULT_UPDATE_ADVERTISEMENT_TIME)
  is added to allow more routes to be sent in single update message.
  This is required since zebra sends route notify message for each route.
  The delay will be applied to update group timer which advertises
  routes to peers.

Signed-off-by: kssoman <somanks@gmail.com>
bgpd/bgp_fsm.c
bgpd/bgp_fsm.h
bgpd/bgp_io.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_table.h
bgpd/bgp_updgrp_adv.c
bgpd/bgp_zebra.c
bgpd/bgpd.h

index 4468408415b8f2597c8cc920c05a5f7cfeb87eb7..dd31a9b7cb36f600dbb468ce42456852c044647c 100644 (file)
@@ -792,9 +792,13 @@ void bgp_adjust_routeadv(struct peer *peer)
                        BGP_TIMER_OFF(peer->t_routeadv);
 
                peer->synctime = bgp_clock();
-               thread_add_timer_msec(bm->master, bgp_generate_updgrp_packets,
-                                     peer, 0,
-                                     &peer->t_generate_updgrp_packets);
+               /* If suppress fib pending is enabled, route is advertised to
+                * peers when the status is received from the FIB. The delay
+                * is added to update group packet generate which will allow
+                * more routes to be sent in the update message
+                */
+               BGP_UPDATE_GROUP_TIMER_ON(&peer->t_generate_updgrp_packets,
+                                         bgp_generate_updgrp_packets);
                return;
        }
 
index b9156df617abf14e21d43cb570f3955d685f8613..cd464d8c588e31e2c75e7828b53e5f9f80bb8d8a 100644 (file)
                thread_cancel_event(bm->master, (P));                          \
        } while (0)
 
+#define BGP_UPDATE_GROUP_TIMER_ON(T, F)                                               \
+       do {                                                                   \
+               if (BGP_SUPPRESS_FIB_ENABLED(peer->bgp) &&                     \
+                   PEER_ROUTE_ADV_DELAY(peer))                                \
+                       thread_add_timer_msec(bm->master, (F), peer,           \
+                               (BGP_DEFAULT_UPDATE_ADVERTISEMENT_TIME * 1000),\
+                               T);                                            \
+               else                                                           \
+                       thread_add_timer_msec(bm->master, (F), peer,           \
+                                             0, T);                           \
+       } while (0)                                                            \
+
 #define BGP_MSEC_JITTER 10
 
 /* Status codes for bgp_event_update() */
index 38455b5e02984977f77057c12b511a37e3e15c97..53fd3b5fe3086c85bbd892a8c3f27dd35b23db01 100644 (file)
@@ -149,12 +149,17 @@ static int bgp_process_writes(struct thread *thread)
                fatal = true;
        }
 
+       /* If suppress fib pending is enabled, route is advertised to peers when
+        * the status is received from the FIB. The delay is added
+        * to update group packet generate which will allow more routes to be
+        * sent in the update message
+        */
        if (reschedule) {
                thread_add_write(fpt->master, bgp_process_writes, peer,
                                 peer->fd, &peer->t_write);
        } else if (!fatal) {
-               BGP_TIMER_ON(peer->t_generate_updgrp_packets,
-                            bgp_generate_updgrp_packets, 0);
+               BGP_UPDATE_GROUP_TIMER_ON(&peer->t_generate_updgrp_packets,
+                                         bgp_generate_updgrp_packets);
        }
 
        return 0;
index 8a237e329e2acfcd6c970000764a5567e8a9e87c..1a766ac23cfa36088e6fdbec9c1e09f16260cb73 100644 (file)
@@ -2497,10 +2497,13 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp,
        struct attr attr;
        afi_t afi;
        safi_t safi;
+       struct bgp *bgp;
+       bool advertise;
 
        p = bgp_dest_get_prefix(dest);
        afi = SUBGRP_AFI(subgrp);
        safi = SUBGRP_SAFI(subgrp);
+       bgp = SUBGRP_INST(subgrp);
        onlypeer = ((SUBGRP_PCOUNT(subgrp) == 1) ? (SUBGRP_PFIRST(subgrp))->peer
                                                 : NULL);
 
@@ -2515,13 +2518,23 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp,
        memset(&attr, 0, sizeof(struct attr));
        /* It's initialized in bgp_announce_check() */
 
-       /* Announcement to the subgroup.  If the route is filtered withdraw it.
+       /* Announcement to the subgroup. If the route is filtered withdraw it.
+        * If BGP_NODE_FIB_INSTALL_PENDING is set and data plane install status
+        * is pending (BGP_NODE_FIB_INSTALL_PENDING), do not advertise the
+        * route
         */
+       advertise = bgp_check_advertise(bgp, dest);
+
        if (selected) {
                if (subgroup_announce_check(dest, selected, subgrp, p, &attr,
-                                           false))
-                       bgp_adj_out_set_subgroup(dest, subgrp, &attr, selected);
-               else
+                                           false)) {
+                       /* Route is selected, if the route is already installed
+                        * in FIB, then it is advertised
+                        */
+                       if (advertise)
+                               bgp_adj_out_set_subgroup(dest, subgrp, &attr,
+                                                        selected);
+               } else
                        bgp_adj_out_unset_subgroup(dest, subgrp, 1,
                                                   addpath_tx_id);
        }
@@ -3524,6 +3537,19 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
        else
                has_valid_label = bgp_is_valid_label(label);
 
+       /* The flag BGP_NODE_FIB_INSTALL_PENDING is for the following
+        * condition :
+        * Suppress fib is enabled
+        * BGP_OPT_NO_FIB is not enabled
+        * Route type is BGP_ROUTE_NORMAL (peer learnt routes)
+        * Route is being installed first time (BGP_NODE_FIB_INSTALLED not set)
+        */
+       if (BGP_SUPPRESS_FIB_ENABLED(bgp) &&
+           (sub_type == BGP_ROUTE_NORMAL) &&
+           (!bgp_option_check(BGP_OPT_NO_FIB)) &&
+           (!CHECK_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED)))
+               SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING);
+
        /* When peer's soft reconfiguration enabled.  Record input packet in
           Adj-RIBs-In.  */
        if (!soft_reconfig
@@ -6788,6 +6814,12 @@ void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi,
                if (dest_p->prefixlen <= p->prefixlen)
                        continue;
 
+               /* If suppress fib is enabled and route not installed
+                * in FIB, skip the route
+                */
+               if (!bgp_check_advertise(bgp, dest))
+                       continue;
+
                match = 0;
 
                for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
@@ -7283,6 +7315,12 @@ void bgp_aggregate_increment(struct bgp *bgp, const struct prefix *p,
        if (BGP_PATH_HOLDDOWN(pi))
                return;
 
+       /* If suppress fib is enabled and route not installed
+        * in FIB, do not update the aggregate route
+        */
+       if (!bgp_check_advertise(bgp, pi->net))
+               return;
+
        child = bgp_node_get(table, p);
 
        /* Aggregate address configuration check. */
index e4c6f9a0e2f356c022755c625037ea1c465e18bf..0b76d7504b5f10eaef3fd477f8eb34f018ebb74e 100644 (file)
@@ -524,6 +524,13 @@ static inline void prep_for_rmap_apply(struct bgp_path_info *dst_pi,
        }
 }
 
+static inline bool bgp_check_advertise(struct bgp *bgp, struct bgp_dest *dest)
+{
+       return (!(BGP_SUPPRESS_FIB_ENABLED(bgp) &&
+                 CHECK_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING) &&
+                (!bgp_option_check(BGP_OPT_NO_FIB))));
+}
+
 /* called before bgp_process() */
 DECLARE_HOOK(bgp_process,
             (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn,
index 4e9abf863ddb9d6b6ae3533752d66f0eef064769..738d41ee6d7bb4d5f9f0e573f21c4d60fb9c730d 100644 (file)
@@ -102,6 +102,8 @@ struct bgp_node {
 #define BGP_NODE_LABEL_CHANGED          (1 << 2)
 #define BGP_NODE_REGISTERED_FOR_LABEL   (1 << 3)
 #define BGP_NODE_SELECT_DEFER           (1 << 4)
+#define BGP_NODE_FIB_INSTALL_PENDING    (1 << 5)
+#define BGP_NODE_FIB_INSTALLED          (1 << 6)
 
        struct bgp_addpath_node_data tx_addpath;
 
index 3cfb73d8a81b15bbc5e5f0fe0d8f8af139e6401d..a03232466cac2f1154419b1f11d27af1577e4de5 100644 (file)
@@ -315,6 +315,7 @@ static void updgrp_show_adj(struct bgp *bgp, afi_t afi, safi_t safi,
 static int subgroup_coalesce_timer(struct thread *thread)
 {
        struct update_subgroup *subgrp;
+       struct bgp *bgp;
 
        subgrp = THREAD_ARG(thread);
        if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
@@ -323,6 +324,7 @@ static int subgroup_coalesce_timer(struct thread *thread)
                           subgrp->v_coalesce);
        subgrp->t_coalesce = NULL;
        subgrp->v_coalesce = 0;
+       bgp = SUBGRP_INST(subgrp);
        subgroup_announce_route(subgrp);
 
 
@@ -334,7 +336,8 @@ static int subgroup_coalesce_timer(struct thread *thread)
         * to
         * announce, this is the method currently employed to trigger the EOR.
         */
-       if (!bgp_update_delay_active(SUBGRP_INST(subgrp))) {
+       if (!bgp_update_delay_active(SUBGRP_INST(subgrp)) &&
+           !(BGP_SUPPRESS_FIB_ENABLED(bgp))) {
                struct peer_af *paf;
                struct peer *peer;
 
@@ -458,10 +461,14 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest,
        struct peer *peer;
        afi_t afi;
        safi_t safi;
+       struct peer *adv_peer;
+       struct peer_af *paf;
+       struct bgp *bgp;
 
        peer = SUBGRP_PEER(subgrp);
        afi = SUBGRP_AFI(subgrp);
        safi = SUBGRP_SAFI(subgrp);
+       bgp = SUBGRP_INST(subgrp);
 
        if (DISABLE_BGP_ANNOUNCE)
                return;
@@ -504,9 +511,21 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest,
         * mrai timers so the socket writes can happen.
         */
        if (!bgp_adv_fifo_count(&subgrp->sync->update)) {
-               struct peer_af *paf;
-
                SUBGRP_FOREACH_PEER (subgrp, paf) {
+                       /* If there are no routes in the withdraw list, set
+                        * the flag PEER_STATUS_ADV_DELAY which will allow
+                        * more routes to be sent in the update message
+                        */
+                       if (BGP_SUPPRESS_FIB_ENABLED(bgp)) {
+                               adv_peer = PAF_PEER(paf);
+                               if (!bgp_adv_fifo_count(
+                                               &subgrp->sync->withdraw))
+                                       SET_FLAG(adv_peer->thread_flags,
+                                                PEER_THREAD_SUBGRP_ADV_DELAY);
+                               else
+                                       UNSET_FLAG(adv_peer->thread_flags,
+                                               PEER_THREAD_SUBGRP_ADV_DELAY);
+                       }
                        bgp_adjust_routeadv(PAF_PEER(paf));
                }
        }
@@ -617,10 +636,13 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
        afi_t afi;
        safi_t safi;
        int addpath_capable;
+       struct bgp *bgp;
+       bool advertise;
 
        peer = SUBGRP_PEER(subgrp);
        afi = SUBGRP_AFI(subgrp);
        safi = SUBGRP_SAFI(subgrp);
+       bgp = SUBGRP_INST(subgrp);
        addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
 
        if (safi == SAFI_LABELED_UNICAST)
@@ -637,6 +659,9 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
        for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
                const struct prefix *dest_p = bgp_dest_get_prefix(dest);
 
+               /* Check if the route can be advertised */
+               advertise = bgp_check_advertise(bgp, dest);
+
                for (ri = bgp_dest_get_bgp_path_info(dest); ri; ri = ri->next)
 
                        if (CHECK_FLAG(ri->flags, BGP_PATH_SELECTED)
@@ -646,10 +671,14 @@ void subgroup_announce_table(struct update_subgroup *subgrp,
                                           ri))) {
                                if (subgroup_announce_check(dest, ri, subgrp,
                                                            dest_p, &attr,
-                                                           false))
-                                       bgp_adj_out_set_subgroup(dest, subgrp,
-                                                                &attr, ri);
-                               else {
+                                                           false)) {
+                                       /* Check if route can be advertised */
+                                       if (advertise)
+                                               bgp_adj_out_set_subgroup(dest,
+                                                                        subgrp,
+                                                                        &attr,
+                                                                        ri);
+                               } else {
                                        /* If default originate is enabled for
                                         * the peer, do not send explicit
                                         * withdraw. This will prevent deletion
@@ -944,6 +973,13 @@ void group_announce_route(struct bgp *bgp, afi_t afi, safi_t safi,
        struct updwalk_context ctx;
        ctx.pi = pi;
        ctx.dest = dest;
+
+       /* If suppress fib is enabled, the route will be advertised when
+        * FIB status is received
+        */
+       if (!bgp_check_advertise(bgp, dest))
+               return;
+
        update_group_af_walk(bgp, afi, safi, group_announce_route_walkcb, &ctx);
 }
 
index 957db4cbc123e79829937bd647f43140a38dfcf6..17bb41cb9f9b773ff0b5e4344bfe9a944dff74d3 100644 (file)
@@ -2380,6 +2380,99 @@ static int iptable_notify_owner(ZAPI_CALLBACK_ARGS)
        return 0;
 }
 
+/* Process route notification messages from RIB */
+static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient,
+                                       zebra_size_t length, vrf_id_t vrf_id)
+{
+       struct prefix p;
+       enum zapi_route_notify_owner note;
+       uint32_t table_id;
+       char buf[PREFIX_STRLEN];
+       afi_t afi;
+       safi_t safi;
+       struct bgp_dest *dest;
+       struct bgp *bgp;
+       struct bgp_path_info *pi, *new_select;
+
+       if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note,
+                                     &afi, &safi)) {
+               zlog_err("%s : error in msg decode", __PRETTY_FUNCTION__);
+               return -1;
+       }
+
+       /* Get the bgp instance */
+       bgp = bgp_lookup_by_vrf_id(vrf_id);
+       if (!bgp) {
+               flog_err(EC_BGP_INVALID_BGP_INSTANCE,
+                        "%s : bgp instance not found vrf %d",
+                        __PRETTY_FUNCTION__, vrf_id);
+               return -1;
+       }
+
+       if (BGP_DEBUG(zebra, ZEBRA))
+               prefix2str(&p, buf, sizeof(buf));
+
+       /* Find the bgp route node */
+       dest = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi, &p,
+                                  &bgp->vrf_prd);
+       if (!dest)
+               return -1;
+
+       bgp_dest_unlock_node(dest);
+
+       switch (note) {
+       case ZAPI_ROUTE_INSTALLED:
+               new_select = NULL;
+               /* Clear the flags so that route can be processed */
+               if (CHECK_FLAG(dest->flags,
+                              BGP_NODE_FIB_INSTALL_PENDING)) {
+                       UNSET_FLAG(dest->flags,
+                                  BGP_NODE_FIB_INSTALL_PENDING);
+                       SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED);
+                       if (BGP_DEBUG(zebra, ZEBRA))
+                               zlog_debug("route %s : INSTALLED", buf);
+                       /* Find the best route */
+                       for (pi = dest->info; pi; pi = pi->next) {
+                               /* Process aggregate route */
+                               bgp_aggregate_increment(bgp, &p, pi,
+                                                       afi, safi);
+                               if (CHECK_FLAG(pi->flags,
+                                              BGP_PATH_SELECTED))
+                                       new_select = pi;
+                       }
+                       /* Advertise the route */
+                       if (new_select)
+                               group_announce_route(bgp, afi, safi,
+                                                    dest, new_select);
+                       else {
+                               flog_err(EC_BGP_INVALID_ROUTE,
+                                        "selected route %s not found",
+                                        buf);
+                               return -1;
+                       }
+               }
+               break;
+       case ZAPI_ROUTE_REMOVED:
+               /* Route deleted from dataplane, reset the installed flag
+                * so that route can be reinstalled when client sends
+                * route add later
+                */
+               UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED);
+               break;
+       case ZAPI_ROUTE_FAIL_INSTALL:
+               /* Error will be logged by zebra module */
+               break;
+       case ZAPI_ROUTE_BETTER_ADMIN_WON:
+               /* No action required */
+               break;
+       case ZAPI_ROUTE_REMOVE_FAIL:
+               zlog_warn("%s: Route %s failure to remove",
+                         __func__, buf);
+               break;
+       }
+       return 0;
+}
+
 /* this function is used to forge ip rule,
  * - either for iptable/ipset using fwmark id
  * - or for sample ip rule cmd
@@ -2910,6 +3003,7 @@ void bgp_zebra_init(struct thread_master *master, unsigned short instance)
        zclient->ipset_notify_owner = ipset_notify_owner;
        zclient->ipset_entry_notify_owner = ipset_entry_notify_owner;
        zclient->iptable_notify_owner = iptable_notify_owner;
+       zclient->route_notify_owner = bgp_zebra_route_notify_owner;
        zclient->instance = instance;
 }
 
index e7d46f3e13bacae45d7b7524bb1f70f84efaec56..a2a3f374e2ce469e0b281a4768f2ee485fa14a91 100644 (file)
@@ -1287,6 +1287,8 @@ struct peer {
 #define PEER_THREAD_WRITES_ON         (1U << 0)
 #define PEER_THREAD_READS_ON          (1U << 1)
 #define PEER_THREAD_KEEPALIVES_ON     (1U << 2)
+#define PEER_THREAD_SUBGRP_ADV_DELAY  (1U << 3)
+
        /* workqueues */
        struct work_queue *clear_node_queue;
 
@@ -1511,8 +1513,8 @@ DECLARE_QOBJ_TYPE(peer)
         || CHECK_FLAG((P)->sflags, PEER_STATUS_PREFIX_OVERFLOW)               \
         || CHECK_FLAG((P)->bgp->flags, BGP_FLAG_SHUTDOWN))
 
-#define PEER_ROUTE_ADV_DELAY(peer)  \
-       CHECK_FLAG(peer->thread_flags, PEER_THREAD_SUBGRP_ADV_DELAY)
+#define PEER_ROUTE_ADV_DELAY(peer)                                            \
+       (CHECK_FLAG(peer->thread_flags, PEER_THREAD_SUBGRP_ADV_DELAY))
 
 #define PEER_PASSWORD_MINLEN   (1)
 #define PEER_PASSWORD_MAXLEN   (80)